diff --git a/[refs] b/[refs] index c093a3dc1190..dd52fd1b8b79 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: d6bb69cfa88b8ac9f952de4fada5b216d5ba8830 +refs/heads/master: 18b34b9546dc192d978dda940673f40928d2e36e diff --git a/trunk/CREDITS b/trunk/CREDITS index e8b7d36611e5..9a93e3e26d70 100644 --- a/trunk/CREDITS +++ b/trunk/CREDITS @@ -495,6 +495,11 @@ S: Kopmansg 2 S: 411 13 Goteborg S: Sweden +N: Paul Bristow +E: paul@paulbristow.net +W: http://paulbristow.net/linux/idefloppy.html +D: Maintainer of IDE/ATAPI floppy driver + N: Dominik Brodowski E: linux@brodo.de W: http://www.brodo.de/ @@ -2642,6 +2647,10 @@ S: C/ Mieses 20, 9-B S: Valladolid 47009 S: Spain +N: Gadi Oxman +E: gadio@netvision.net.il +D: Original author and maintainer of IDE/ATAPI floppy/tape drivers + N: Greg Page E: gpage@sovereign.org D: IPX development and support diff --git a/trunk/Documentation/ABI/testing/sysfs-bus-pci b/trunk/Documentation/ABI/testing/sysfs-bus-pci index e638e15a8895..97ad190e13af 100644 --- a/trunk/Documentation/ABI/testing/sysfs-bus-pci +++ b/trunk/Documentation/ABI/testing/sysfs-bus-pci @@ -41,6 +41,49 @@ Description: for the device and attempt to bind to it. For example: # echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id +What: /sys/bus/pci/drivers/.../remove_id +Date: February 2009 +Contact: Chris Wright +Description: + Writing a device ID to this file will remove an ID + that was dynamically added via the new_id sysfs entry. + The format for the device ID is: + VVVV DDDD SVVV SDDD CCCC MMMM. That is Vendor ID, Device + ID, Subsystem Vendor ID, Subsystem Device ID, Class, + and Class Mask. The Vendor ID and Device ID fields are + required, the rest are optional. After successfully + removing an ID, the driver will no longer support the + device. This is useful to ensure auto probing won't + match the driver to the device. For example: + # echo "8086 10f5" > /sys/bus/pci/drivers/foo/remove_id + +What: /sys/bus/pci/rescan +Date: January 2009 +Contact: Linux PCI developers +Description: + Writing a non-zero value to this attribute will + force a rescan of all PCI buses in the system, and + re-discover previously removed devices. + Depends on CONFIG_HOTPLUG. + +What: /sys/bus/pci/devices/.../remove +Date: January 2009 +Contact: Linux PCI developers +Description: + Writing a non-zero value to this attribute will + hot-remove the PCI device and any of its children. + Depends on CONFIG_HOTPLUG. + +What: /sys/bus/pci/devices/.../rescan +Date: January 2009 +Contact: Linux PCI developers +Description: + Writing a non-zero value to this attribute will + force a rescan of the device's parent bus and all + child buses, and re-discover devices removed earlier + from this part of the device tree. + Depends on CONFIG_HOTPLUG. + What: /sys/bus/pci/devices/.../vpd Date: February 2008 Contact: Ben Hutchings @@ -52,3 +95,30 @@ Description: that some devices may have malformatted data. If the underlying VPD has a writable section then the corresponding section of this file will be writable. + +What: /sys/bus/pci/devices/.../virtfnN +Date: March 2009 +Contact: Yu Zhao +Description: + This symbolic link appears when hardware supports the SR-IOV + capability and the Physical Function driver has enabled it. + The symbolic link points to the PCI device sysfs entry of the + Virtual Function whose index is N (0...MaxVFs-1). + +What: /sys/bus/pci/devices/.../dep_link +Date: March 2009 +Contact: Yu Zhao +Description: + This symbolic link appears when hardware supports the SR-IOV + capability and the Physical Function driver has enabled it, + and this device has vendor specific dependencies with others. + The symbolic link points to the PCI device sysfs entry of + Physical Function this device depends on. + +What: /sys/bus/pci/devices/.../physfn +Date: March 2009 +Contact: Yu Zhao +Description: + This symbolic link appears when a device is a Virtual Function. + The symbolic link points to the PCI device sysfs entry of the + Physical Function this device associates with. diff --git a/trunk/Documentation/ABI/testing/sysfs-fs-ext4 b/trunk/Documentation/ABI/testing/sysfs-fs-ext4 new file mode 100644 index 000000000000..4e79074de282 --- /dev/null +++ b/trunk/Documentation/ABI/testing/sysfs-fs-ext4 @@ -0,0 +1,81 @@ +What: /sys/fs/ext4//mb_stats +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + Controls whether the multiblock allocator should + collect statistics, which are shown during the unmount. + 1 means to collect statistics, 0 means not to collect + statistics + +What: /sys/fs/ext4//mb_group_prealloc +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + The multiblock allocator will round up allocation + requests to a multiple of this tuning parameter if the + stripe size is not set in the ext4 superblock + +What: /sys/fs/ext4//mb_max_to_scan +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + The maximum number of extents the multiblock allocator + will search to find the best extent + +What: /sys/fs/ext4//mb_min_to_scan +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + The minimum number of extents the multiblock allocator + will search to find the best extent + +What: /sys/fs/ext4//mb_order2_req +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + Tuning parameter which controls the minimum size for + requests (as a power of 2) where the buddy cache is + used + +What: /sys/fs/ext4//mb_stream_req +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + Files which have fewer blocks than this tunable + parameter will have their blocks allocated out of a + block group specific preallocation pool, so that small + files are packed closely together. Each large file + will have its blocks allocated out of its own unique + preallocation pool. + +What: /sys/fs/ext4//inode_readahead +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + Tuning parameter which controls the maximum number of + inode table blocks that ext4's inode table readahead + algorithm will pre-read into the buffer cache + +What: /sys/fs/ext4//delayed_allocation_blocks +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + This file is read-only and shows the number of blocks + that are dirty in the page cache, but which do not + have their location in the filesystem allocated yet. + +What: /sys/fs/ext4//lifetime_write_kbytes +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + This file is read-only and shows the number of kilobytes + of data that have been written to this filesystem since it was + created. + +What: /sys/fs/ext4//session_write_kbytes +Date: March 2008 +Contact: "Theodore Ts'o" +Description: + This file is read-only and shows the number of + kilobytes of data that have been written to this + filesystem since it was mounted. diff --git a/trunk/Documentation/DocBook/.gitignore b/trunk/Documentation/DocBook/.gitignore index c102c02ecf89..c6def352fe39 100644 --- a/trunk/Documentation/DocBook/.gitignore +++ b/trunk/Documentation/DocBook/.gitignore @@ -4,3 +4,7 @@ *.html *.9.gz *.9 +*.aux +*.dvi +*.log +*.out diff --git a/trunk/Documentation/DocBook/kernel-api.tmpl b/trunk/Documentation/DocBook/kernel-api.tmpl index bc962cda6504..58c194572c76 100644 --- a/trunk/Documentation/DocBook/kernel-api.tmpl +++ b/trunk/Documentation/DocBook/kernel-api.tmpl @@ -199,6 +199,7 @@ X!Edrivers/pci/hotplug.c --> !Edrivers/pci/probe.c !Edrivers/pci/rom.c +!Edrivers/pci/iov.c PCI Hotplug Support Library !Edrivers/pci/hotplug/pci_hotplug_core.c diff --git a/trunk/Documentation/PCI/MSI-HOWTO.txt b/trunk/Documentation/PCI/MSI-HOWTO.txt index 256defd7e174..dcf7acc720e1 100644 --- a/trunk/Documentation/PCI/MSI-HOWTO.txt +++ b/trunk/Documentation/PCI/MSI-HOWTO.txt @@ -4,506 +4,356 @@ Revised Feb 12, 2004 by Martine Silbermann email: Martine.Silbermann@hp.com Revised Jun 25, 2004 by Tom L Nguyen + Revised Jul 9, 2008 by Matthew Wilcox + Copyright 2003, 2008 Intel Corporation 1. About this guide -This guide describes the basics of Message Signaled Interrupts (MSI), -the advantages of using MSI over traditional interrupt mechanisms, -and how to enable your driver to use MSI or MSI-X. Also included is -a Frequently Asked Questions (FAQ) section. - -1.1 Terminology - -PCI devices can be single-function or multi-function. In either case, -when this text talks about enabling or disabling MSI on a "device -function," it is referring to one specific PCI device and function and -not to all functions on a PCI device (unless the PCI device has only -one function). - -2. Copyright 2003 Intel Corporation - -3. What is MSI/MSI-X? - -Message Signaled Interrupt (MSI), as described in the PCI Local Bus -Specification Revision 2.3 or later, is an optional feature, and a -required feature for PCI Express devices. MSI enables a device function -to request service by sending an Inbound Memory Write on its PCI bus to -the FSB as a Message Signal Interrupt transaction. Because MSI is -generated in the form of a Memory Write, all transaction conditions, -such as a Retry, Master-Abort, Target-Abort or normal completion, are -supported. - -A PCI device that supports MSI must also support pin IRQ assertion -interrupt mechanism to provide backward compatibility for systems that -do not support MSI. In systems which support MSI, the bus driver is -responsible for initializing the message address and message data of -the device function's MSI/MSI-X capability structure during device -initial configuration. - -An MSI capable device function indicates MSI support by implementing -the MSI/MSI-X capability structure in its PCI capability list. The -device function may implement both the MSI capability structure and -the MSI-X capability structure; however, the bus driver should not -enable both. - -The MSI capability structure contains Message Control register, -Message Address register and Message Data register. These registers -provide the bus driver control over MSI. The Message Control register -indicates the MSI capability supported by the device. The Message -Address register specifies the target address and the Message Data -register specifies the characteristics of the message. To request -service, the device function writes the content of the Message Data -register to the target address. The device and its software driver -are prohibited from writing to these registers. - -The MSI-X capability structure is an optional extension to MSI. It -uses an independent and separate capability structure. There are -some key advantages to implementing the MSI-X capability structure -over the MSI capability structure as described below. - - - Support a larger maximum number of vectors per function. - - - Provide the ability for system software to configure - each vector with an independent message address and message - data, specified by a table that resides in Memory Space. - - - MSI and MSI-X both support per-vector masking. Per-vector - masking is an optional extension of MSI but a required - feature for MSI-X. Per-vector masking provides the kernel the - ability to mask/unmask a single MSI while running its - interrupt service routine. If per-vector masking is - not supported, then the device driver should provide the - hardware/software synchronization to ensure that the device - generates MSI when the driver wants it to do so. - -4. Why use MSI? - -As a benefit to the simplification of board design, MSI allows board -designers to remove out-of-band interrupt routing. MSI is another -step towards a legacy-free environment. - -Due to increasing pressure on chipset and processor packages to -reduce pin count, the need for interrupt pins is expected to -diminish over time. Devices, due to pin constraints, may implement -messages to increase performance. - -PCI Express endpoints uses INTx emulation (in-band messages) instead -of IRQ pin assertion. Using INTx emulation requires interrupt -sharing among devices connected to the same node (PCI bridge) while -MSI is unique (non-shared) and does not require BIOS configuration -support. As a result, the PCI Express technology requires MSI -support for better interrupt performance. - -Using MSI enables the device functions to support two or more -vectors, which can be configured to target different CPUs to -increase scalability. - -5. Configuring a driver to use MSI/MSI-X - -By default, the kernel will not enable MSI/MSI-X on all devices that -support this capability. The CONFIG_PCI_MSI kernel option -must be selected to enable MSI/MSI-X support. - -5.1 Including MSI/MSI-X support into the kernel - -To allow MSI/MSI-X capable device drivers to selectively enable -MSI/MSI-X (using pci_enable_msi()/pci_enable_msix() as described -below), the VECTOR based scheme needs to be enabled by setting -CONFIG_PCI_MSI during kernel config. - -Since the target of the inbound message is the local APIC, providing -CONFIG_X86_LOCAL_APIC must be enabled as well as CONFIG_PCI_MSI. - -5.2 Configuring for MSI support - -Due to the non-contiguous fashion in vector assignment of the -existing Linux kernel, this version does not support multiple -messages regardless of a device function is capable of supporting -more than one vector. To enable MSI on a device function's MSI -capability structure requires a device driver to call the function -pci_enable_msi() explicitly. - -5.2.1 API pci_enable_msi +This guide describes the basics of Message Signaled Interrupts (MSIs), +the advantages of using MSI over traditional interrupt mechanisms, how +to change your driver to use MSI or MSI-X and some basic diagnostics to +try if a device doesn't support MSIs. -int pci_enable_msi(struct pci_dev *dev) -With this new API, a device driver that wants to have MSI -enabled on its device function must call this API to enable MSI. -A successful call will initialize the MSI capability structure -with ONE vector, regardless of whether a device function is -capable of supporting multiple messages. This vector replaces the -pre-assigned dev->irq with a new MSI vector. To avoid a conflict -of the new assigned vector with existing pre-assigned vector requires -a device driver to call this API before calling request_irq(). +2. What are MSIs? -5.2.2 API pci_disable_msi +A Message Signaled Interrupt is a write from the device to a special +address which causes an interrupt to be received by the CPU. -void pci_disable_msi(struct pci_dev *dev) +The MSI capability was first specified in PCI 2.2 and was later enhanced +in PCI 3.0 to allow each interrupt to be masked individually. The MSI-X +capability was also introduced with PCI 3.0. It supports more interrupts +per device than MSI and allows interrupts to be independently configured. -This API should always be used to undo the effect of pci_enable_msi() -when a device driver is unloading. This API restores dev->irq with -the pre-assigned IOAPIC vector and switches a device's interrupt -mode to PCI pin-irq assertion/INTx emulation mode. - -Note that a device driver should always call free_irq() on the MSI vector -that it has done request_irq() on before calling this API. Failure to do -so results in a BUG_ON() and a device will be left with MSI enabled and -leaks its vector. - -5.2.3 MSI mode vs. legacy mode diagram - -The below diagram shows the events which switch the interrupt -mode on the MSI-capable device function between MSI mode and -PIN-IRQ assertion mode. - - ------------ pci_enable_msi ------------------------ - | | <=============== | | - | MSI MODE | | PIN-IRQ ASSERTION MODE | - | | ===============> | | - ------------ pci_disable_msi ------------------------ - - -Figure 1. MSI Mode vs. Legacy Mode - -In Figure 1, a device operates by default in legacy mode. Legacy -in this context means PCI pin-irq assertion or PCI-Express INTx -emulation. A successful MSI request (using pci_enable_msi()) switches -a device's interrupt mode to MSI mode. A pre-assigned IOAPIC vector -stored in dev->irq will be saved by the PCI subsystem and a new -assigned MSI vector will replace dev->irq. - -To return back to its default mode, a device driver should always call -pci_disable_msi() to undo the effect of pci_enable_msi(). Note that a -device driver should always call free_irq() on the MSI vector it has -done request_irq() on before calling pci_disable_msi(). Failure to do -so results in a BUG_ON() and a device will be left with MSI enabled and -leaks its vector. Otherwise, the PCI subsystem restores a device's -dev->irq with a pre-assigned IOAPIC vector and marks the released -MSI vector as unused. - -Once being marked as unused, there is no guarantee that the PCI -subsystem will reserve this MSI vector for a device. Depending on -the availability of current PCI vector resources and the number of -MSI/MSI-X requests from other drivers, this MSI may be re-assigned. - -For the case where the PCI subsystem re-assigns this MSI vector to -another driver, a request to switch back to MSI mode may result -in being assigned a different MSI vector or a failure if no more -vectors are available. - -5.3 Configuring for MSI-X support - -Due to the ability of the system software to configure each vector of -the MSI-X capability structure with an independent message address -and message data, the non-contiguous fashion in vector assignment of -the existing Linux kernel has no impact on supporting multiple -messages on an MSI-X capable device functions. To enable MSI-X on -a device function's MSI-X capability structure requires its device -driver to call the function pci_enable_msix() explicitly. - -The function pci_enable_msix(), once invoked, enables either -all or nothing, depending on the current availability of PCI vector -resources. If the PCI vector resources are available for the number -of vectors requested by a device driver, this function will configure -the MSI-X table of the MSI-X capability structure of a device with -requested messages. To emphasize this reason, for example, a device -may be capable for supporting the maximum of 32 vectors while its -software driver usually may request 4 vectors. It is recommended -that the device driver should call this function once during the -initialization phase of the device driver. - -Unlike the function pci_enable_msi(), the function pci_enable_msix() -does not replace the pre-assigned IOAPIC dev->irq with a new MSI -vector because the PCI subsystem writes the 1:1 vector-to-entry mapping -into the field vector of each element contained in a second argument. -Note that the pre-assigned IOAPIC dev->irq is valid only if the device -operates in PIN-IRQ assertion mode. In MSI-X mode, any attempt at -using dev->irq by the device driver to request for interrupt service -may result in unpredictable behavior. - -For each MSI-X vector granted, a device driver is responsible for calling -other functions like request_irq(), enable_irq(), etc. to enable -this vector with its corresponding interrupt service handler. It is -a device driver's choice to assign all vectors with the same -interrupt service handler or each vector with a unique interrupt -service handler. - -5.3.1 Handling MMIO address space of MSI-X Table - -The PCI 3.0 specification has implementation notes that MMIO address -space for a device's MSI-X structure should be isolated so that the -software system can set different pages for controlling accesses to the -MSI-X structure. The implementation of MSI support requires the PCI -subsystem, not a device driver, to maintain full control of the MSI-X -table/MSI-X PBA (Pending Bit Array) and MMIO address space of the MSI-X -table/MSI-X PBA. A device driver should not access the MMIO address -space of the MSI-X table/MSI-X PBA. - -5.3.2 API pci_enable_msix +Devices may support both MSI and MSI-X, but only one can be enabled at +a time. -int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) -This API enables a device driver to request the PCI subsystem -to enable MSI-X messages on its hardware device. Depending on -the availability of PCI vectors resources, the PCI subsystem enables -either all or none of the requested vectors. +3. Why use MSIs? + +There are three reasons why using MSIs can give an advantage over +traditional pin-based interrupts. + +Pin-based PCI interrupts are often shared amongst several devices. +To support this, the kernel must call each interrupt handler associated +with an interrupt, which leads to reduced performance for the system as +a whole. MSIs are never shared, so this problem cannot arise. + +When a device writes data to memory, then raises a pin-based interrupt, +it is possible that the interrupt may arrive before all the data has +arrived in memory (this becomes more likely with devices behind PCI-PCI +bridges). In order to ensure that all the data has arrived in memory, +the interrupt handler must read a register on the device which raised +the interrupt. PCI transaction ordering rules require that all the data +arrives in memory before the value can be returned from the register. +Using MSIs avoids this problem as the interrupt-generating write cannot +pass the data writes, so by the time the interrupt is raised, the driver +knows that all the data has arrived in memory. + +PCI devices can only support a single pin-based interrupt per function. +Often drivers have to query the device to find out what event has +occurred, slowing down interrupt handling for the common case. With +MSIs, a device can support more interrupts, allowing each interrupt +to be specialised to a different purpose. One possible design gives +infrequent conditions (such as errors) their own interrupt which allows +the driver to handle the normal interrupt handling path more efficiently. +Other possible designs include giving one interrupt to each packet queue +in a network card or each port in a storage controller. + + +4. How to use MSIs + +PCI devices are initialised to use pin-based interrupts. The device +driver has to set up the device to use MSI or MSI-X. Not all machines +support MSIs correctly, and for those machines, the APIs described below +will simply fail and the device will continue to use pin-based interrupts. + +4.1 Include kernel support for MSIs + +To support MSI or MSI-X, the kernel must be built with the CONFIG_PCI_MSI +option enabled. This option is only available on some architectures, +and it may depend on some other options also being set. For example, +on x86, you must also enable X86_UP_APIC or SMP in order to see the +CONFIG_PCI_MSI option. + +4.2 Using MSI + +Most of the hard work is done for the driver in the PCI layer. It simply +has to request that the PCI layer set up the MSI capability for this +device. + +4.2.1 pci_enable_msi + +int pci_enable_msi(struct pci_dev *dev) + +A successful call will allocate ONE interrupt to the device, regardless +of how many MSIs the device supports. The device will be switched from +pin-based interrupt mode to MSI mode. The dev->irq number is changed +to a new number which represents the message signaled interrupt. +This function should be called before the driver calls request_irq() +since enabling MSIs disables the pin-based IRQ and the driver will not +receive interrupts on the old interrupt. + +4.2.2 pci_enable_msi_block + +int pci_enable_msi_block(struct pci_dev *dev, int count) + +This variation on the above call allows a device driver to request multiple +MSIs. The MSI specification only allows interrupts to be allocated in +powers of two, up to a maximum of 2^5 (32). + +If this function returns 0, it has succeeded in allocating at least as many +interrupts as the driver requested (it may have allocated more in order +to satisfy the power-of-two requirement). In this case, the function +enables MSI on this device and updates dev->irq to be the lowest of +the new interrupts assigned to it. The other interrupts assigned to +the device are in the range dev->irq to dev->irq + count - 1. + +If this function returns a negative number, it indicates an error and +the driver should not attempt to request any more MSI interrupts for +this device. If this function returns a positive number, it will be +less than 'count' and indicate the number of interrupts that could have +been allocated. In neither case will the irq value have been +updated, nor will the device have been switched into MSI mode. + +The device driver must decide what action to take if +pci_enable_msi_block() returns a value less than the number asked for. +Some devices can make use of fewer interrupts than the maximum they +request; in this case the driver should call pci_enable_msi_block() +again. Note that it is not guaranteed to succeed, even when the +'count' has been reduced to the value returned from a previous call to +pci_enable_msi_block(). This is because there are multiple constraints +on the number of vectors that can be allocated; pci_enable_msi_block() +will return as soon as it finds any constraint that doesn't allow the +call to succeed. + +4.2.3 pci_disable_msi + +void pci_disable_msi(struct pci_dev *dev) -Argument 'dev' points to the device (pci_dev) structure. +This function should be used to undo the effect of pci_enable_msi() or +pci_enable_msi_block(). Calling it restores dev->irq to the pin-based +interrupt number and frees the previously allocated message signaled +interrupt(s). The interrupt may subsequently be assigned to another +device, so drivers should not cache the value of dev->irq. -Argument 'entries' is a pointer to an array of msix_entry structs. -The number of entries is indicated in argument 'nvec'. -struct msix_entry is defined in /driver/pci/msi.h: +A device driver must always call free_irq() on the interrupt(s) +for which it has called request_irq() before calling this function. +Failure to do so will result in a BUG_ON(), the device will be left with +MSI enabled and will leak its vector. + +4.3 Using MSI-X + +The MSI-X capability is much more flexible than the MSI capability. +It supports up to 2048 interrupts, each of which can be controlled +independently. To support this flexibility, drivers must use an array of +`struct msix_entry': struct msix_entry { u16 vector; /* kernel uses to write alloc vector */ u16 entry; /* driver uses to specify entry */ }; -A device driver is responsible for initializing the field 'entry' of -each element with a unique entry supported by MSI-X table. Otherwise, --EINVAL will be returned as a result. A successful return of zero -indicates the PCI subsystem completed initializing each of the requested -entries of the MSI-X table with message address and message data. -Last but not least, the PCI subsystem will write the 1:1 -vector-to-entry mapping into the field 'vector' of each element. A -device driver is responsible for keeping track of allocated MSI-X -vectors in its internal data structure. - -A return of zero indicates that the number of MSI-X vectors was -successfully allocated. A return of greater than zero indicates -MSI-X vector shortage. Or a return of less than zero indicates -a failure. This failure may be a result of duplicate entries -specified in second argument, or a result of no available vector, -or a result of failing to initialize MSI-X table entries. - -5.3.3 API pci_disable_msix +This allows for the device to use these interrupts in a sparse fashion; +for example it could use interrupts 3 and 1027 and allocate only a +two-element array. The driver is expected to fill in the 'entry' value +in each element of the array to indicate which entries it wants the kernel +to assign interrupts for. It is invalid to fill in two entries with the +same number. + +4.3.1 pci_enable_msix + +int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) + +Calling this function asks the PCI subsystem to allocate 'nvec' MSIs. +The 'entries' argument is a pointer to an array of msix_entry structs +which should be at least 'nvec' entries in size. On success, the +function will return 0 and the device will have been switched into +MSI-X interrupt mode. The 'vector' elements in each entry will have +been filled in with the interrupt number. The driver should then call +request_irq() for each 'vector' that it decides to use. + +If this function returns a negative number, it indicates an error and +the driver should not attempt to allocate any more MSI-X interrupts for +this device. If it returns a positive number, it indicates the maximum +number of interrupt vectors that could have been allocated. See example +below. + +This function, in contrast with pci_enable_msi(), does not adjust +dev->irq. The device will not generate interrupts for this interrupt +number once MSI-X is enabled. The device driver is responsible for +keeping track of the interrupts assigned to the MSI-X vectors so it can +free them again later. + +Device drivers should normally call this function once per device +during the initialization phase. + +It is ideal if drivers can cope with a variable number of MSI-X interrupts, +there are many reasons why the platform may not be able to provide the +exact number a driver asks for. + +A request loop to achieve that might look like: + +static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec) +{ + while (nvec >= FOO_DRIVER_MINIMUM_NVEC) { + rc = pci_enable_msix(adapter->pdev, + adapter->msix_entries, nvec); + if (rc > 0) + nvec = rc; + else + return rc; + } + + return -ENOSPC; +} + +4.3.2 pci_disable_msix void pci_disable_msix(struct pci_dev *dev) -This API should always be used to undo the effect of pci_enable_msix() -when a device driver is unloading. Note that a device driver should -always call free_irq() on all MSI-X vectors it has done request_irq() -on before calling this API. Failure to do so results in a BUG_ON() and -a device will be left with MSI-X enabled and leaks its vectors. - -5.3.4 MSI-X mode vs. legacy mode diagram - -The below diagram shows the events which switch the interrupt -mode on the MSI-X capable device function between MSI-X mode and -PIN-IRQ assertion mode (legacy). - - ------------ pci_enable_msix(,,n) ------------------------ - | | <=============== | | - | MSI-X MODE | | PIN-IRQ ASSERTION MODE | - | | ===============> | | - ------------ pci_disable_msix ------------------------ - -Figure 2. MSI-X Mode vs. Legacy Mode - -In Figure 2, a device operates by default in legacy mode. A -successful MSI-X request (using pci_enable_msix()) switches a -device's interrupt mode to MSI-X mode. A pre-assigned IOAPIC vector -stored in dev->irq will be saved by the PCI subsystem; however, -unlike MSI mode, the PCI subsystem will not replace dev->irq with -assigned MSI-X vector because the PCI subsystem already writes the 1:1 -vector-to-entry mapping into the field 'vector' of each element -specified in second argument. - -To return back to its default mode, a device driver should always call -pci_disable_msix() to undo the effect of pci_enable_msix(). Note that -a device driver should always call free_irq() on all MSI-X vectors it -has done request_irq() on before calling pci_disable_msix(). Failure -to do so results in a BUG_ON() and a device will be left with MSI-X -enabled and leaks its vectors. Otherwise, the PCI subsystem switches a -device function's interrupt mode from MSI-X mode to legacy mode and -marks all allocated MSI-X vectors as unused. - -Once being marked as unused, there is no guarantee that the PCI -subsystem will reserve these MSI-X vectors for a device. Depending on -the availability of current PCI vector resources and the number of -MSI/MSI-X requests from other drivers, these MSI-X vectors may be -re-assigned. - -For the case where the PCI subsystem re-assigned these MSI-X vectors -to other drivers, a request to switch back to MSI-X mode may result -being assigned with another set of MSI-X vectors or a failure if no -more vectors are available. - -5.4 Handling function implementing both MSI and MSI-X capabilities - -For the case where a function implements both MSI and MSI-X -capabilities, the PCI subsystem enables a device to run either in MSI -mode or MSI-X mode but not both. A device driver determines whether it -wants MSI or MSI-X enabled on its hardware device. Once a device -driver requests for MSI, for example, it is prohibited from requesting -MSI-X; in other words, a device driver is not permitted to ping-pong -between MSI mod MSI-X mode during a run-time. - -5.5 Hardware requirements for MSI/MSI-X support - -MSI/MSI-X support requires support from both system hardware and -individual hardware device functions. - -5.5.1 Required x86 hardware support - -Since the target of MSI address is the local APIC CPU, enabling -MSI/MSI-X support in the Linux kernel is dependent on whether existing -system hardware supports local APIC. Users should verify that their -system supports local APIC operation by testing that it runs when -CONFIG_X86_LOCAL_APIC=y. - -In SMP environment, CONFIG_X86_LOCAL_APIC is automatically set; -however, in UP environment, users must manually set -CONFIG_X86_LOCAL_APIC. Once CONFIG_X86_LOCAL_APIC=y, setting -CONFIG_PCI_MSI enables the VECTOR based scheme and the option for -MSI-capable device drivers to selectively enable MSI/MSI-X. - -Note that CONFIG_X86_IO_APIC setting is irrelevant because MSI/MSI-X -vector is allocated new during runtime and MSI/MSI-X support does not -depend on BIOS support. This key independency enables MSI/MSI-X -support on future IOxAPIC free platforms. - -5.5.2 Device hardware support - -The hardware device function supports MSI by indicating the -MSI/MSI-X capability structure on its PCI capability list. By -default, this capability structure will not be initialized by -the kernel to enable MSI during the system boot. In other words, -the device function is running on its default pin assertion mode. -Note that in many cases the hardware supporting MSI have bugs, -which may result in system hangs. The software driver of specific -MSI-capable hardware is responsible for deciding whether to call -pci_enable_msi or not. A return of zero indicates the kernel -successfully initialized the MSI/MSI-X capability structure of the -device function. The device function is now running on MSI/MSI-X mode. - -5.6 How to tell whether MSI/MSI-X is enabled on device function - -At the driver level, a return of zero from the function call of -pci_enable_msi()/pci_enable_msix() indicates to a device driver that -its device function is initialized successfully and ready to run in -MSI/MSI-X mode. - -At the user level, users can use the command 'cat /proc/interrupts' -to display the vectors allocated for devices and their interrupt -MSI/MSI-X modes ("PCI-MSI"/"PCI-MSI-X"). Below shows MSI mode is -enabled on a SCSI Adaptec 39320D Ultra320 controller. - - CPU0 CPU1 - 0: 324639 0 IO-APIC-edge timer - 1: 1186 0 IO-APIC-edge i8042 - 2: 0 0 XT-PIC cascade - 12: 2797 0 IO-APIC-edge i8042 - 14: 6543 0 IO-APIC-edge ide0 - 15: 1 0 IO-APIC-edge ide1 -169: 0 0 IO-APIC-level uhci-hcd -185: 0 0 IO-APIC-level uhci-hcd -193: 138 10 PCI-MSI aic79xx -201: 30 0 PCI-MSI aic79xx -225: 30 0 IO-APIC-level aic7xxx -233: 30 0 IO-APIC-level aic7xxx -NMI: 0 0 -LOC: 324553 325068 -ERR: 0 -MIS: 0 - -6. MSI quirks - -Several PCI chipsets or devices are known to not support MSI. -The PCI stack provides 3 possible levels of MSI disabling: -* on a single device -* on all devices behind a specific bridge -* globally - -6.1. Disabling MSI on a single device - -Under some circumstances it might be required to disable MSI on a -single device. This may be achieved by either not calling pci_enable_msi() -or all, or setting the pci_dev->no_msi flag before (most of the time -in a quirk). - -6.2. Disabling MSI below a bridge - -The vast majority of MSI quirks are required by PCI bridges not -being able to route MSI between busses. In this case, MSI have to be -disabled on all devices behind this bridge. It is achieves by setting -the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge -subordinate bus. There is no need to set the same flag on bridges that -are below the broken bridge. When pci_enable_msi() is called to enable -MSI on a device, pci_msi_supported() takes care of checking the NO_MSI -flag in all parent busses of the device. - -Some bridges actually support dynamic MSI support enabling/disabling -by changing some bits in their PCI configuration space (especially -the Hypertransport chipsets such as the nVidia nForce and Serverworks -HT2000). It may then be required to update the NO_MSI flag on the -corresponding devices in the sysfs hierarchy. To enable MSI support -on device "0000:00:0e", do: - - echo 1 > /sys/bus/pci/devices/0000:00:0e/msi_bus - -To disable MSI support, echo 0 instead of 1. Note that it should be -used with caution since changing this value might break interrupts. - -6.3. Disabling MSI globally - -Some extreme cases may require to disable MSI globally on the system. -For now, the only known case is a Serverworks PCI-X chipsets (MSI are -not supported on several busses that are not all connected to the -chipset in the Linux PCI hierarchy). In the vast majority of other -cases, disabling only behind a specific bridge is enough. - -For debugging purpose, the user may also pass pci=nomsi on the kernel -command-line to explicitly disable MSI globally. But, once the appro- -priate quirks are added to the kernel, this option should not be -required anymore. - -6.4. Finding why MSI cannot be enabled on a device - -Assuming that MSI are not enabled on a device, you should look at -dmesg to find messages that quirks may output when disabling MSI -on some devices, some bridges or even globally. -Then, lspci -t gives the list of bridges above a device. Reading -/sys/bus/pci/devices/0000:00:0e/msi_bus will tell you whether MSI -are enabled (1) or disabled (0). In 0 is found in a single bridge -msi_bus file above the device, MSI cannot be enabled. - -7. FAQ - -Q1. Are there any limitations on using the MSI? - -A1. If the PCI device supports MSI and conforms to the -specification and the platform supports the APIC local bus, -then using MSI should work. - -Q2. Will it work on all the Pentium processors (P3, P4, Xeon, -AMD processors)? In P3 IPI's are transmitted on the APIC local -bus and in P4 and Xeon they are transmitted on the system -bus. Are there any implications with this? - -A2. MSI support enables a PCI device sending an inbound -memory write (0xfeexxxxx as target address) on its PCI bus -directly to the FSB. Since the message address has a -redirection hint bit cleared, it should work. - -Q3. The target address 0xfeexxxxx will be translated by the -Host Bridge into an interrupt message. Are there any -limitations on the chipsets such as Intel 8xx, Intel e7xxx, -or VIA? - -A3. If these chipsets support an inbound memory write with -target address set as 0xfeexxxxx, as conformed to PCI -specification 2.3 or latest, then it should work. - -Q4. From the driver point of view, if the MSI is lost because -of errors occurring during inbound memory write, then it may -wait forever. Is there a mechanism for it to recover? - -A4. Since the target of the transaction is an inbound memory -write, all transaction termination conditions (Retry, -Master-Abort, Target-Abort, or normal completion) are -supported. A device sending an MSI must abide by all the PCI -rules and conditions regarding that inbound memory write. So, -if a retry is signaled it must retry, etc... We believe that -the recommendation for Abort is also a retry (refer to PCI -specification 2.3 or latest). +This API should be used to undo the effect of pci_enable_msix(). It frees +the previously allocated message signaled interrupts. The interrupts may +subsequently be assigned to another device, so drivers should not cache +the value of the 'vector' elements over a call to pci_disable_msix(). + +A device driver must always call free_irq() on the interrupt(s) +for which it has called request_irq() before calling this function. +Failure to do so will result in a BUG_ON(), the device will be left with +MSI enabled and will leak its vector. + +4.3.3 The MSI-X Table + +The MSI-X capability specifies a BAR and offset within that BAR for the +MSI-X Table. This address is mapped by the PCI subsystem, and should not +be accessed directly by the device driver. If the driver wishes to +mask or unmask an interrupt, it should call disable_irq() / enable_irq(). + +4.4 Handling devices implementing both MSI and MSI-X capabilities + +If a device implements both MSI and MSI-X capabilities, it can +run in either MSI mode or MSI-X mode but not both simultaneously. +This is a requirement of the PCI spec, and it is enforced by the +PCI layer. Calling pci_enable_msi() when MSI-X is already enabled or +pci_enable_msix() when MSI is already enabled will result in an error. +If a device driver wishes to switch between MSI and MSI-X at runtime, +it must first quiesce the device, then switch it back to pin-interrupt +mode, before calling pci_enable_msi() or pci_enable_msix() and resuming +operation. This is not expected to be a common operation but may be +useful for debugging or testing during development. + +4.5 Considerations when using MSIs + +4.5.1 Choosing between MSI-X and MSI + +If your device supports both MSI-X and MSI capabilities, you should use +the MSI-X facilities in preference to the MSI facilities. As mentioned +above, MSI-X supports any number of interrupts between 1 and 2048. +In constrast, MSI is restricted to a maximum of 32 interrupts (and +must be a power of two). In addition, the MSI interrupt vectors must +be allocated consecutively, so the system may not be able to allocate +as many vectors for MSI as it could for MSI-X. On some platforms, MSI +interrupts must all be targetted at the same set of CPUs whereas MSI-X +interrupts can all be targetted at different CPUs. + +4.5.2 Spinlocks + +Most device drivers have a per-device spinlock which is taken in the +interrupt handler. With pin-based interrupts or a single MSI, it is not +necessary to disable interrupts (Linux guarantees the same interrupt will +not be re-entered). If a device uses multiple interrupts, the driver +must disable interrupts while the lock is held. If the device sends +a different interrupt, the driver will deadlock trying to recursively +acquire the spinlock. + +There are two solutions. The first is to take the lock with +spin_lock_irqsave() or spin_lock_irq() (see +Documentation/DocBook/kernel-locking). The second is to specify +IRQF_DISABLED to request_irq() so that the kernel runs the entire +interrupt routine with interrupts disabled. + +If your MSI interrupt routine does not hold the lock for the whole time +it is running, the first solution may be best. The second solution is +normally preferred as it avoids making two transitions from interrupt +disabled to enabled and back again. + +4.6 How to tell whether MSI/MSI-X is enabled on a device + +Using 'lspci -v' (as root) may show some devices with "MSI", "Message +Signalled Interrupts" or "MSI-X" capabilities. Each of these capabilities +has an 'Enable' flag which will be followed with either "+" (enabled) +or "-" (disabled). + + +5. MSI quirks + +Several PCI chipsets or devices are known not to support MSIs. +The PCI stack provides three ways to disable MSIs: + +1. globally +2. on all devices behind a specific bridge +3. on a single device + +5.1. Disabling MSIs globally + +Some host chipsets simply don't support MSIs properly. If we're +lucky, the manufacturer knows this and has indicated it in the ACPI +FADT table. In this case, Linux will automatically disable MSIs. +Some boards don't include this information in the table and so we have +to detect them ourselves. The complete list of these is found near the +quirk_disable_all_msi() function in drivers/pci/quirks.c. + +If you have a board which has problems with MSIs, you can pass pci=nomsi +on the kernel command line to disable MSIs on all devices. It would be +in your best interests to report the problem to linux-pci@vger.kernel.org +including a full 'lspci -v' so we can add the quirks to the kernel. + +5.2. Disabling MSIs below a bridge + +Some PCI bridges are not able to route MSIs between busses properly. +In this case, MSIs must be disabled on all devices behind the bridge. + +Some bridges allow you to enable MSIs by changing some bits in their +PCI configuration space (especially the Hypertransport chipsets such +as the nVidia nForce and Serverworks HT2000). As with host chipsets, +Linux mostly knows about them and automatically enables MSIs if it can. +If you have a bridge which Linux doesn't yet know about, you can enable +MSIs in configuration space using whatever method you know works, then +enable MSIs on that bridge by doing: + + echo 1 > /sys/bus/pci/devices/$bridge/msi_bus + +where $bridge is the PCI address of the bridge you've enabled (eg +0000:00:0e.0). + +To disable MSIs, echo 0 instead of 1. Changing this value should be +done with caution as it can break interrupt handling for all devices +below this bridge. + +Again, please notify linux-pci@vger.kernel.org of any bridges that need +special handling. + +5.3. Disabling MSIs on a single device + +Some devices are known to have faulty MSI implementations. Usually this +is handled in the individual device driver but occasionally it's necessary +to handle this with a quirk. Some drivers have an option to disable use +of MSI. While this is a convenient workaround for the driver author, +it is not good practise, and should not be emulated. + +5.4. Finding why MSIs are disabled on a device + +From the above three sections, you can see that there are many reasons +why MSIs may not be enabled for a given device. Your first step should +be to examine your dmesg carefully to determine whether MSIs are enabled +for your machine. You should also check your .config to be sure you +have enabled CONFIG_PCI_MSI. + +Then, 'lspci -t' gives the list of bridges above a device. Reading +/sys/bus/pci/devices/*/msi_bus will tell you whether MSI are enabled (1) +or disabled (0). If 0 is found in any of the msi_bus files belonging +to bridges between the PCI root and the device, MSIs are disabled. + +It is also worth checking the device driver to see whether it supports MSIs. +For example, it may contain calls to pci_enable_msi(), pci_enable_msix() or +pci_enable_msi_block(). diff --git a/trunk/Documentation/PCI/pci-iov-howto.txt b/trunk/Documentation/PCI/pci-iov-howto.txt new file mode 100644 index 000000000000..fc73ef5d65b8 --- /dev/null +++ b/trunk/Documentation/PCI/pci-iov-howto.txt @@ -0,0 +1,99 @@ + PCI Express I/O Virtualization Howto + Copyright (C) 2009 Intel Corporation + Yu Zhao + + +1. Overview + +1.1 What is SR-IOV + +Single Root I/O Virtualization (SR-IOV) is a PCI Express Extended +capability which makes one physical device appear as multiple virtual +devices. The physical device is referred to as Physical Function (PF) +while the virtual devices are referred to as Virtual Functions (VF). +Allocation of the VF can be dynamically controlled by the PF via +registers encapsulated in the capability. By default, this feature is +not enabled and the PF behaves as traditional PCIe device. Once it's +turned on, each VF's PCI configuration space can be accessed by its own +Bus, Device and Function Number (Routing ID). And each VF also has PCI +Memory Space, which is used to map its register set. VF device driver +operates on the register set so it can be functional and appear as a +real existing PCI device. + +2. User Guide + +2.1 How can I enable SR-IOV capability + +The device driver (PF driver) will control the enabling and disabling +of the capability via API provided by SR-IOV core. If the hardware +has SR-IOV capability, loading its PF driver would enable it and all +VFs associated with the PF. + +2.2 How can I use the Virtual Functions + +The VF is treated as hot-plugged PCI devices in the kernel, so they +should be able to work in the same way as real PCI devices. The VF +requires device driver that is same as a normal PCI device's. + +3. Developer Guide + +3.1 SR-IOV API + +To enable SR-IOV capability: + int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn); + 'nr_virtfn' is number of VFs to be enabled. + +To disable SR-IOV capability: + void pci_disable_sriov(struct pci_dev *dev); + +To notify SR-IOV core of Virtual Function Migration: + irqreturn_t pci_sriov_migration(struct pci_dev *dev); + +3.2 Usage example + +Following piece of code illustrates the usage of the SR-IOV API. + +static int __devinit dev_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + pci_enable_sriov(dev, NR_VIRTFN); + + ... + + return 0; +} + +static void __devexit dev_remove(struct pci_dev *dev) +{ + pci_disable_sriov(dev); + + ... +} + +static int dev_suspend(struct pci_dev *dev, pm_message_t state) +{ + ... + + return 0; +} + +static int dev_resume(struct pci_dev *dev) +{ + ... + + return 0; +} + +static void dev_shutdown(struct pci_dev *dev) +{ + ... +} + +static struct pci_driver dev_driver = { + .name = "SR-IOV Physical Function driver", + .id_table = dev_id_table, + .probe = dev_probe, + .remove = __devexit_p(dev_remove), + .suspend = dev_suspend, + .resume = dev_resume, + .shutdown = dev_shutdown, +}; diff --git a/trunk/Documentation/RCU/listRCU.txt b/trunk/Documentation/RCU/listRCU.txt index 1fd175368a87..4349c1487e91 100644 --- a/trunk/Documentation/RCU/listRCU.txt +++ b/trunk/Documentation/RCU/listRCU.txt @@ -118,7 +118,7 @@ Following are the RCU equivalents for these two functions: list_for_each_entry(e, list, list) { if (!audit_compare_rule(rule, &e->rule)) { list_del_rcu(&e->list); - call_rcu(&e->rcu, audit_free_rule, e); + call_rcu(&e->rcu, audit_free_rule); return 0; } } @@ -206,7 +206,7 @@ RCU ("read-copy update") its name. The RCU code is as follows: ne->rule.action = newaction; ne->rule.file_count = newfield_count; list_replace_rcu(e, ne); - call_rcu(&e->rcu, audit_free_rule, e); + call_rcu(&e->rcu, audit_free_rule); return 0; } } @@ -283,7 +283,7 @@ flag under the spinlock as follows: list_del_rcu(&e->list); e->deleted = 1; spin_unlock(&e->lock); - call_rcu(&e->rcu, audit_free_rule, e); + call_rcu(&e->rcu, audit_free_rule); return 0; } } diff --git a/trunk/Documentation/RCU/rcu.txt b/trunk/Documentation/RCU/rcu.txt index 95821a29ae41..7aa2002ade77 100644 --- a/trunk/Documentation/RCU/rcu.txt +++ b/trunk/Documentation/RCU/rcu.txt @@ -81,7 +81,7 @@ o I hear that RCU needs work in order to support realtime kernels? This work is largely completed. Realtime-friendly RCU can be enabled via the CONFIG_PREEMPT_RCU kernel configuration parameter. However, work is in progress for enabling priority boosting of - preempted RCU read-side critical sections.This is needed if you + preempted RCU read-side critical sections. This is needed if you have CPU-bound realtime threads. o Where can I find more information on RCU? diff --git a/trunk/Documentation/RCU/rculist_nulls.txt b/trunk/Documentation/RCU/rculist_nulls.txt index 239f542d48ba..6389dec33459 100644 --- a/trunk/Documentation/RCU/rculist_nulls.txt +++ b/trunk/Documentation/RCU/rculist_nulls.txt @@ -21,7 +21,7 @@ if (obj) { /* * Because a writer could delete object, and a writer could * reuse these object before the RCU grace period, we - * must check key after geting the reference on object + * must check key after getting the reference on object */ if (obj->key != key) { // not the object we expected put_ref(obj); @@ -117,7 +117,7 @@ a race (some writer did a delete and/or a move of an object to another chain) checking the final 'nulls' value if the lookup met the end of chain. If final 'nulls' value is not the slot number, then we must restart the lookup at -the begining. If the object was moved to same chain, +the beginning. If the object was moved to the same chain, then the reader doesnt care : It might eventually scan the list again without harm. diff --git a/trunk/Documentation/cgroups/cgroups.txt b/trunk/Documentation/cgroups/cgroups.txt index 93feb8444489..4ea852345a47 100644 --- a/trunk/Documentation/cgroups/cgroups.txt +++ b/trunk/Documentation/cgroups/cgroups.txt @@ -333,12 +333,23 @@ The "xxx" is not interpreted by the cgroup code, but will appear in To mount a cgroup hierarchy with just the cpuset and numtasks subsystems, type: -# mount -t cgroup -o cpuset,numtasks hier1 /dev/cgroup +# mount -t cgroup -o cpuset,memory hier1 /dev/cgroup To change the set of subsystems bound to a mounted hierarchy, just remount with different options: +# mount -o remount,cpuset,ns hier1 /dev/cgroup -# mount -o remount,cpuset,ns /dev/cgroup +Now memory is removed from the hierarchy and ns is added. + +Note this will add ns to the hierarchy but won't remove memory or +cpuset, because the new options are appended to the old ones: +# mount -o remount,ns /dev/cgroup + +To Specify a hierarchy's release_agent: +# mount -t cgroup -o cpuset,release_agent="/sbin/cpuset_release_agent" \ + xxx /dev/cgroup + +Note that specifying 'release_agent' more than once will return failure. Note that changing the set of subsystems is currently only supported when the hierarchy consists of a single (root) cgroup. Supporting @@ -349,6 +360,11 @@ Then under /dev/cgroup you can find a tree that corresponds to the tree of the cgroups in the system. For instance, /dev/cgroup is the cgroup that holds the whole system. +If you want to change the value of release_agent: +# echo "/sbin/new_release_agent" > /dev/cgroup/release_agent + +It can also be changed via remount. + If you want to create a new cgroup under /dev/cgroup: # cd /dev/cgroup # mkdir my_cgroup @@ -476,11 +492,13 @@ cgroup->parent is still valid. (Note - can also be called for a newly-created cgroup if an error occurs after this subsystem's create() method has been called for the new cgroup). -void pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); +int pre_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp); Called before checking the reference count on each subsystem. This may be useful for subsystems which have some extra references even if -there are not tasks in the cgroup. +there are not tasks in the cgroup. If pre_destroy() returns error code, +rmdir() will fail with it. From this behavior, pre_destroy() can be +called multiple times against a cgroup. int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, struct task_struct *task) diff --git a/trunk/Documentation/cgroups/memcg_test.txt b/trunk/Documentation/cgroups/memcg_test.txt index 523a9c16c400..8a11caf417a0 100644 --- a/trunk/Documentation/cgroups/memcg_test.txt +++ b/trunk/Documentation/cgroups/memcg_test.txt @@ -1,5 +1,5 @@ Memory Resource Controller(Memcg) Implementation Memo. -Last Updated: 2009/1/19 +Last Updated: 2009/1/20 Base Kernel Version: based on 2.6.29-rc2. Because VM is getting complex (one of reasons is memcg...), memcg's behavior @@ -360,3 +360,21 @@ Under below explanation, we assume CONFIG_MEM_RES_CTRL_SWAP=y. # kill malloc task. Of course, tmpfs v.s. swapoff test should be tested, too. + + 9.8 OOM-Killer + Out-of-memory caused by memcg's limit will kill tasks under + the memcg. When hierarchy is used, a task under hierarchy + will be killed by the kernel. + In this case, panic_on_oom shouldn't be invoked and tasks + in other groups shouldn't be killed. + + It's not difficult to cause OOM under memcg as following. + Case A) when you can swapoff + #swapoff -a + #echo 50M > /memory.limit_in_bytes + run 51M of malloc + + Case B) when you use mem+swap limitation. + #echo 50M > memory.limit_in_bytes + #echo 50M > memory.memsw.limit_in_bytes + run 51M of malloc diff --git a/trunk/Documentation/fb/00-INDEX b/trunk/Documentation/fb/00-INDEX index caabbd395e61..a618fd99c9f0 100644 --- a/trunk/Documentation/fb/00-INDEX +++ b/trunk/Documentation/fb/00-INDEX @@ -11,8 +11,6 @@ aty128fb.txt - info on the ATI Rage128 frame buffer driver. cirrusfb.txt - info on the driver for Cirrus Logic chipsets. -cyblafb/ - - directory with documentation files related to the cyblafb driver. deferred_io.txt - an introduction to deferred IO. fbcon.txt diff --git a/trunk/Documentation/fb/cyblafb/bugs b/trunk/Documentation/fb/cyblafb/bugs deleted file mode 100644 index 9443a6d72cdd..000000000000 --- a/trunk/Documentation/fb/cyblafb/bugs +++ /dev/null @@ -1,13 +0,0 @@ -Bugs -==== - -I currently don't know of any bug. Please do send reports to: - - linux-fbdev-devel@lists.sourceforge.net - - Knut_Petersen@t-online.de. - - -Untested features -================= - -All LCD stuff is untested. If it worked in tridentfb, it should work in -cyblafb. Please test and report the results to Knut_Petersen@t-online.de. diff --git a/trunk/Documentation/fb/cyblafb/credits b/trunk/Documentation/fb/cyblafb/credits deleted file mode 100644 index 0eb3b443dc2b..000000000000 --- a/trunk/Documentation/fb/cyblafb/credits +++ /dev/null @@ -1,7 +0,0 @@ -Thanks to -========= - * Alan Hourihane, for writing the X trident driver - * Jani Monoses, for writing the tridentfb driver - * Antonino A. Daplas, for review of the first published - version of cyblafb and some code - * Jochen Hein, for testing and a helpfull bug report diff --git a/trunk/Documentation/fb/cyblafb/documentation b/trunk/Documentation/fb/cyblafb/documentation deleted file mode 100644 index bb1aac048425..000000000000 --- a/trunk/Documentation/fb/cyblafb/documentation +++ /dev/null @@ -1,17 +0,0 @@ -Available Documentation -======================= - -Apollo PLE 133 Chipset VT8601A North Bridge Datasheet, Rev. 1.82, October 22, -2001, available from VIA: - - http://www.viavpsd.com/product/6/15/DS8601A182.pdf - -The datasheet is incomplete, some registers that need to be programmed are not -explained at all and important bits are listed as "reserved". But you really -need the datasheet to understand the code. "p. xxx" comments refer to page -numbers of this document. - -XFree/XOrg drivers are available and of good quality, looking at the code -there is a good idea if the datasheet does not provide enough information -or if the datasheet seems to be wrong. - diff --git a/trunk/Documentation/fb/cyblafb/fb.modes b/trunk/Documentation/fb/cyblafb/fb.modes deleted file mode 100644 index fe0e5223ba86..000000000000 --- a/trunk/Documentation/fb/cyblafb/fb.modes +++ /dev/null @@ -1,154 +0,0 @@ -# -# Sample fb.modes file -# -# Provides an incomplete list of working modes for -# the cyberblade/i1 graphics core. -# -# The value 4294967256 is used instead of -40. Of course, -40 is not -# a really reasonable value, but chip design does not always follow -# logic. Believe me, it's ok, and it's the way the BIOS does it. -# -# fbset requires 4294967256 in fb.modes and -40 as an argument to -# the -t parameter. That's also not too reasonable, and it might change -# in the future or might even be differt for your current version. -# - -mode "640x480-50" - geometry 640 480 2048 4096 8 - timings 47619 4294967256 24 17 0 216 3 -endmode - -mode "640x480-60" - geometry 640 480 2048 4096 8 - timings 39682 4294967256 24 17 0 216 3 -endmode - -mode "640x480-70" - geometry 640 480 2048 4096 8 - timings 34013 4294967256 24 17 0 216 3 -endmode - -mode "640x480-72" - geometry 640 480 2048 4096 8 - timings 33068 4294967256 24 17 0 216 3 -endmode - -mode "640x480-75" - geometry 640 480 2048 4096 8 - timings 31746 4294967256 24 17 0 216 3 -endmode - -mode "640x480-80" - geometry 640 480 2048 4096 8 - timings 29761 4294967256 24 17 0 216 3 -endmode - -mode "640x480-85" - geometry 640 480 2048 4096 8 - timings 28011 4294967256 24 17 0 216 3 -endmode - -mode "800x600-50" - geometry 800 600 2048 4096 8 - timings 30303 96 24 14 0 136 11 -endmode - -mode "800x600-60" - geometry 800 600 2048 4096 8 - timings 25252 96 24 14 0 136 11 -endmode - -mode "800x600-70" - geometry 800 600 2048 4096 8 - timings 21645 96 24 14 0 136 11 -endmode - -mode "800x600-72" - geometry 800 600 2048 4096 8 - timings 21043 96 24 14 0 136 11 -endmode - -mode "800x600-75" - geometry 800 600 2048 4096 8 - timings 20202 96 24 14 0 136 11 -endmode - -mode "800x600-80" - geometry 800 600 2048 4096 8 - timings 18939 96 24 14 0 136 11 -endmode - -mode "800x600-85" - geometry 800 600 2048 4096 8 - timings 17825 96 24 14 0 136 11 -endmode - -mode "1024x768-50" - geometry 1024 768 2048 4096 8 - timings 19054 144 24 29 0 120 3 -endmode - -mode "1024x768-60" - geometry 1024 768 2048 4096 8 - timings 15880 144 24 29 0 120 3 -endmode - -mode "1024x768-70" - geometry 1024 768 2048 4096 8 - timings 13610 144 24 29 0 120 3 -endmode - -mode "1024x768-72" - geometry 1024 768 2048 4096 8 - timings 13232 144 24 29 0 120 3 -endmode - -mode "1024x768-75" - geometry 1024 768 2048 4096 8 - timings 12703 144 24 29 0 120 3 -endmode - -mode "1024x768-80" - geometry 1024 768 2048 4096 8 - timings 11910 144 24 29 0 120 3 -endmode - -mode "1024x768-85" - geometry 1024 768 2048 4096 8 - timings 11209 144 24 29 0 120 3 -endmode - -mode "1280x1024-50" - geometry 1280 1024 2048 4096 8 - timings 11114 232 16 39 0 160 3 -endmode - -mode "1280x1024-60" - geometry 1280 1024 2048 4096 8 - timings 9262 232 16 39 0 160 3 -endmode - -mode "1280x1024-70" - geometry 1280 1024 2048 4096 8 - timings 7939 232 16 39 0 160 3 -endmode - -mode "1280x1024-72" - geometry 1280 1024 2048 4096 8 - timings 7719 232 16 39 0 160 3 -endmode - -mode "1280x1024-75" - geometry 1280 1024 2048 4096 8 - timings 7410 232 16 39 0 160 3 -endmode - -mode "1280x1024-80" - geometry 1280 1024 2048 4096 8 - timings 6946 232 16 39 0 160 3 -endmode - -mode "1280x1024-85" - geometry 1280 1024 2048 4096 8 - timings 6538 232 16 39 0 160 3 -endmode diff --git a/trunk/Documentation/fb/cyblafb/performance b/trunk/Documentation/fb/cyblafb/performance deleted file mode 100644 index 8d15d5dfc6b3..000000000000 --- a/trunk/Documentation/fb/cyblafb/performance +++ /dev/null @@ -1,79 +0,0 @@ -Speed -===== - -CyBlaFB is much faster than tridentfb and vesafb. Compare the performance data -for mode 1280x1024-[8,16,32]@61 Hz. - -Test 1: Cat a file with 2000 lines of 0 characters. -Test 2: Cat a file with 2000 lines of 80 characters. -Test 3: Cat a file with 2000 lines of 160 characters. - -All values show system time use in seconds, kernel 2.6.12 was used for -the measurements. 2.6.13 is a bit slower, 2.6.14 hopefully will include a -patch that speeds up kernel bitblitting a lot ( > 20%). - -+-----------+-----------------------------------------------------+ -| | not accelerated | -| TRIDENTFB +-----------------+-----------------+-----------------+ -| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp | -| | noypan | ypan | noypan | ypan | noypan | ypan | -+-----------+--------+--------+--------+--------+--------+--------+ -| Test 1 | 4.31 | 4.33 | 6.05 | 12.81 | ---- | ---- | -| Test 2 | 67.94 | 5.44 | 123.16 | 14.79 | ---- | ---- | -| Test 3 | 131.36 | 6.55 | 240.12 | 16.76 | ---- | ---- | -+-----------+--------+--------+--------+--------+--------+--------+ -| Comments | | | completely bro- | -| | | | ken, monitor | -| | | | switches off | -+-----------+-----------------+-----------------+-----------------+ - - -+-----------+-----------------------------------------------------+ -| | accelerated | -| TRIDENTFB +-----------------+-----------------+-----------------+ -| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp | -| | noypan | ypan | noypan | ypan | noypan | ypan | -+-----------+--------+--------+--------+--------+--------+--------+ -| Test 1 | ---- | ---- | 20.62 | 1.22 | ---- | ---- | -| Test 2 | ---- | ---- | 22.61 | 3.19 | ---- | ---- | -| Test 3 | ---- | ---- | 24.59 | 5.16 | ---- | ---- | -+-----------+--------+--------+--------+--------+--------+--------+ -| Comments | broken, writing | broken, ok only | completely bro- | -| | to wrong places | if bgcolor is | ken, monitor | -| | on screen + bug | black, bug in | switches off | -| | in fillrect() | fillrect() | | -+-----------+-----------------+-----------------+-----------------+ - - -+-----------+-----------------------------------------------------+ -| | not accelerated | -| VESAFB +-----------------+-----------------+-----------------+ -| of 2.6.12 | 8 bpp | 16 bpp | 32 bpp | -| | noypan | ypan | noypan | ypan | noypan | ypan | -+-----------+--------+--------+--------+--------+--------+--------+ -| Test 1 | 4.26 | 3.76 | 5.99 | 7.23 | ---- | ---- | -| Test 2 | 65.65 | 4.89 | 120.88 | 9.08 | ---- | ---- | -| Test 3 | 126.91 | 5.94 | 235.77 | 11.03 | ---- | ---- | -+-----------+--------+--------+--------+--------+--------+--------+ -| Comments | vga=0x307 | vga=0x31a | vga=0x31b not | -| | fh=80kHz | fh=80kHz | supported by | -| | fv=75kHz | fv=75kHz | video BIOS and | -| | | | hardware | -+-----------+-----------------+-----------------+-----------------+ - - -+-----------+-----------------------------------------------------+ -| | accelerated | -| CYBLAFB +-----------------+-----------------+-----------------+ -| | 8 bpp | 16 bpp | 32 bpp | -| | noypan | ypan | noypan | ypan | noypan | ypan | -+-----------+--------+--------+--------+--------+--------+--------+ -| Test 1 | 8.02 | 0.23 | 19.04 | 0.61 | 57.12 | 2.74 | -| Test 2 | 8.38 | 0.55 | 19.39 | 0.92 | 57.54 | 3.13 | -| Test 3 | 8.73 | 0.86 | 19.74 | 1.24 | 57.95 | 3.51 | -+-----------+--------+--------+--------+--------+--------+--------+ -| Comments | | | | -| | | | | -| | | | | -| | | | | -+-----------+-----------------+-----------------+-----------------+ diff --git a/trunk/Documentation/fb/cyblafb/todo b/trunk/Documentation/fb/cyblafb/todo deleted file mode 100644 index c5f6d0eae545..000000000000 --- a/trunk/Documentation/fb/cyblafb/todo +++ /dev/null @@ -1,31 +0,0 @@ -TODO / Missing features -======================= - -Verify LCD stuff "stretch" and "center" options are - completely untested ... this code needs to be - verified. As I don't have access to such - hardware, please contact me if you are - willing run some tests. - -Interlaced video modes The reason that interleaved - modes are disabled is that I do not know - the meaning of the vertical interlace - parameter. Also the datasheet mentions a - bit d8 of a horizontal interlace parameter, - but nowhere the lower 8 bits. Please help - if you can. - -low-res double scan modes Who needs it? - -accelerated color blitting Who needs it? The console driver does use color - blitting for nothing but drawing the penguine, - everything else is done using color expanding - blitting of 1bpp character bitmaps. - -ioctls Who needs it? - -TV-out Will be done later. Use "vga= " at boot time - to set a suitable video mode. - -??? Feel free to contact me if you have any - feature requests diff --git a/trunk/Documentation/fb/cyblafb/usage b/trunk/Documentation/fb/cyblafb/usage deleted file mode 100644 index a39bb3d402a2..000000000000 --- a/trunk/Documentation/fb/cyblafb/usage +++ /dev/null @@ -1,217 +0,0 @@ -CyBlaFB is a framebuffer driver for the Cyberblade/i1 graphics core integrated -into the VIA Apollo PLE133 (aka vt8601) south bridge. It is developed and -tested using a VIA EPIA 5000 board. - -Cyblafb - compiled into the kernel or as a module? -================================================== - -You might compile cyblafb either as a module or compile it permanently into the -kernel. - -Unless you have a real reason to do so you should not compile both vesafb and -cyblafb permanently into the kernel. It's possible and it helps during the -developement cycle, but it's useless and will at least block some otherwise -usefull memory for ordinary users. - -Selecting Modes -=============== - - Startup Mode - ============ - - First of all, you might use the "vga=???" boot parameter as it is - documented in vesafb.txt and svga.txt. Cyblafb will detect the video - mode selected and will use the geometry and timings found by - inspecting the hardware registers. - - video=cyblafb vga=0x317 - - Alternatively you might use a combination of the mode, ref and bpp - parameters. If you compiled the driver into the kernel, add something - like this to the kernel command line: - - video=cyblafb:1280x1024,bpp=16,ref=50 ... - - If you compiled the driver as a module, the same mode would be - selected by the following command: - - modprobe cyblafb mode=1280x1024 bpp=16 ref=50 ... - - None of the modes possible to select as startup modes are affected by - the problems described at the end of the next subsection. - - For all startup modes cyblafb chooses a virtual x resolution of 2048, - the only exception is mode 1280x1024 in combination with 32 bpp. This - allows ywrap scrolling for all those modes if rotation is 0 or 2, and - also fast scrolling if rotation is 1 or 3. The default virtual y reso- - lution is 4096 for bpp == 8, 2048 for bpp==16 and 1024 for bpp == 32, - again with the only exception of 1280x1024 at 32 bpp. - - Please do set your video memory size to 8 Mb in the Bios setup. Other - values will work, but performace is decreased for a lot of modes. - - Mode changes using fbset - ======================== - - You might use fbset to change the video mode, see "man fbset". Cyblafb - generally does assume that you know what you are doing. But it does - some checks, especially those that are needed to prevent you from - damaging your hardware. - - - only 8, 16, 24 and 32 bpp video modes are accepted - - interlaced video modes are not accepted - - double scan video modes are not accepted - - if a flat panel is found, cyblafb does not allow you - to program a resolution higher than the physical - resolution of the flat panel monitor - - cyblafb does not allow vclk to exceed 230 MHz. As 32 bpp - and (currently) 24 bit modes use a doubled vclk internally, - the dotclock limit as seen by fbset is 115 MHz for those - modes and 230 MHz for 8 and 16 bpp modes. - - cyblafb will allow you to select very high resolutions as - long as the hardware can be programmed to these modes. The - documented limit 1600x1200 is not enforced, but don't expect - perfect signal quality. - - Any request that violates the rules given above will be either changed - to something the hardware supports or an error value will be returned. - - If you program a virtual y resolution higher than the hardware limit, - cyblafb will silently decrease that value to the highest possible - value. The same is true for a virtual x resolution that is not - supported by the hardware. Cyblafb tries to adapt vyres first because - vxres decides if ywrap scrolling is possible or not. - - Attempts to disable acceleration are ignored, I believe that this is - safe. - - Some video modes that should work do not work as expected. If you use - the standard fb.modes, fbset 640x480-60 will program that mode, but - you will see a vertical area, about two characters wide, with only - much darker characters than the other characters on the screen. - Cyblafb does allow that mode to be set, as it does not violate the - official specifications. It would need a lot of code to reliably sort - out all invalid modes, playing around with the margin values will - give a valid mode quickly. And if cyblafb would detect such an invalid - mode, should it silently alter the requested values or should it - report an error? Both options have some pros and cons. As stated - above, none of the startup modes are affected, and if you set - verbosity to 1 or higher, cyblafb will print the fbset command that - would be needed to program that mode using fbset. - - -Other Parameters -================ - - -crt don't autodetect, assume monitor connected to - standard VGA connector - -fp don't autodetect, assume flat panel display - connected to flat panel monitor interface - -nativex inform driver about native x resolution of - flat panel monitor connected to special - interface (should be autodetected) - -stretch stretch image to adapt low resolution modes to - higer resolutions of flat panel monitors - connected to special interface - -center center image to adapt low resolution modes to - higer resolutions of flat panel monitors - connected to special interface - -memsize use if autodetected memsize is wrong ... - should never be necessary - -nopcirr disable PCI read retry -nopciwr disable PCI write retry -nopcirb disable PCI read bursts -nopciwb disable PCI write bursts - -bpp bpp for specified modes - valid values: 8 || 16 || 24 || 32 - -ref refresh rate for specified mode - valid values: 50 <= ref <= 85 - -mode 640x480 or 800x600 or 1024x768 or 1280x1024 - if not specified, the startup mode will be detected - and used, so you might also use the vga=??? parameter - described in vesafb.txt. If you do not specify a mode, - bpp and ref parameters are ignored. - -verbosity 0 is the default, increase to at least 2 for every - bug report! - -Development hints -================= - -It's much faster do compile a module and to load the new version after -unloading the old module than to compile a new kernel and to reboot. So if you -try to work on cyblafb, it might be a good idea to use cyblafb as a module. -In real life, fast often means dangerous, and that's also the case here. If -you introduce a serious bug when cyblafb is compiled into the kernel, the -kernel will lock or oops with a high probability before the file system is -mounted, and the danger for your data is low. If you load a broken own version -of cyblafb on a running system, the danger for the integrity of the file -system is much higher as you might need a hard reset afterwards. Decide -yourself. - -Module unloading, the vfb method -================================ - -If you want to unload/reload cyblafb using the virtual framebuffer, you need -to enable vfb support in the kernel first. After that, load the modules as -shown below: - - modprobe vfb vfb_enable=1 - modprobe fbcon - modprobe cyblafb - fbset -fb /dev/fb1 1280x1024-60 -vyres 2662 - con2fb /dev/fb1 /dev/tty1 - ... - -If you now made some changes to cyblafb and want to reload it, you might do it -as show below: - - con2fb /dev/fb0 /dev/tty1 - ... - rmmod cyblafb - modprobe cyblafb - con2fb /dev/fb1 /dev/tty1 - ... - -Of course, you might choose another mode, and most certainly you also want to -map some other /dev/tty* to the real framebuffer device. You might also choose -to compile fbcon as a kernel module or place it permanently in the kernel. - -I do not know of any way to unload fbcon, and fbcon will prevent the -framebuffer device loaded first from unloading. [If there is a way, then -please add a description here!] - -Module unloading, the vesafb method -=================================== - -Configure the kernel: - - <*> Support for frame buffer devices - [*] VESA VGA graphics support - Cyberblade/i1 support - -Add e.g. "video=vesafb:ypan vga=0x307" to the kernel parameters. The ypan -parameter is important, choose any vga parameter you like as long as it is -a graphics mode. - -After booting, load cyblafb without any mode and bpp parameter and assign -cyblafb to individual ttys using con2fb, e.g.: - - modprobe cyblafb - con2fb /dev/fb1 /dev/tty1 - -Unloading cyblafb works without problems after you assign vesafb to all -ttys again, e.g.: - - con2fb /dev/fb0 /dev/tty1 - rmmod cyblafb diff --git a/trunk/Documentation/fb/cyblafb/whatsnew b/trunk/Documentation/fb/cyblafb/whatsnew deleted file mode 100644 index 76c07a26e044..000000000000 --- a/trunk/Documentation/fb/cyblafb/whatsnew +++ /dev/null @@ -1,29 +0,0 @@ -0.62 -==== - - - the vesafb parameter has been removed as I decided to allow the - feature without any special parameter. - - - Cyblafb does not use the vga style of panning any longer, now the - "right view" register in the graphics engine IO space is used. Without - that change it was impossible to use all available memory, and without - access to all available memory it is impossible to ywrap. - - - The imageblit function now uses hardware acceleration for all font - widths. Hardware blitting across pixel column 2048 is broken in the - cyberblade/i1 graphics core, but we work around that hardware bug. - - - modes with vxres != xres are supported now. - - - ywrap scrolling is supported now and the default. This is a big - performance gain. - - - default video modes use vyres > yres and vxres > xres to allow - almost optimal scrolling speed for normal and rotated screens - - - some features mainly usefull for debugging the upper layers of the - framebuffer system have been added, have a look at the code - - - fixed: Oops after unloading cyblafb when reading /proc/io* - - - we work around some bugs of the higher framebuffer layers. diff --git a/trunk/Documentation/fb/cyblafb/whycyblafb b/trunk/Documentation/fb/cyblafb/whycyblafb deleted file mode 100644 index a123bc11e698..000000000000 --- a/trunk/Documentation/fb/cyblafb/whycyblafb +++ /dev/null @@ -1,85 +0,0 @@ -I tried the following framebuffer drivers: - - - TRIDENTFB is full of bugs. Acceleration is broken for Blade3D - graphics cores like the cyberblade/i1. It claims to support a great - number of devices, but documentation for most of these devices is - unfortunately not available. There is _no_ reason to use tridentfb - for cyberblade/i1 + CRT users. VESAFB is faster, and the one - advantage, mode switching, is broken in tridentfb. - - - VESAFB is used by many distributions as a standard. Vesafb does - not support mode switching. VESAFB is a bit faster than the working - configurations of TRIDENTFB, but it is still too slow, even if you - use ypan. - - - EPIAFB (you'll find it on sourceforge) supports the Cyberblade/i1 - graphics core, but it still has serious bugs and developement seems - to have stopped. This is the one driver with TV-out support. If you - do need this feature, try epiafb. - -None of these drivers was a real option for me. - -I believe that is unreasonable to change code that announces to support 20 -devices if I only have more or less sufficient documentation for exactly one -of these. The risk of breaking device foo while fixing device bar is too high. - -So I decided to start CyBlaFB as a stripped down tridentfb. - -All code specific to other Trident chips has been removed. After that there -were a lot of cosmetic changes to increase the readability of the code. All -register names were changed to those mnemonics used in the datasheet. Function -and macro names were changed if they hindered easy understanding of the code. - -After that I debugged the code and implemented some new features. I'll try to -give a little summary of the main changes: - - - calculation of vertical and horizontal timings was fixed - - - video signal quality has been improved dramatically - - - acceleration: - - - fillrect and copyarea were fixed and reenabled - - - color expanding imageblit was newly implemented, color - imageblit (only used to draw the penguine) still uses the - generic code. - - - init of the acceleration engine was improved and moved to a - place where it really works ... - - - sync function has a timeout now and tries to reset and - reinit the accel engine if necessary - - - fewer slow copyarea calls when doing ypan scrolling by using - undocumented bit d21 of screen start address stored in - CR2B[5]. BIOS does use it also, so this should be safe. - - - cyblafb rejects any attempt to set modes that would cause vclk - values above reasonable 230 MHz. 32bit modes use a clock - multiplicator of 2, so fbset does show the correct values for - pixclock but not for vclk in this case. The fbset limit is 115 MHz - for 32 bpp modes. - - - cyblafb rejects modes known to be broken or unimplemented (all - interlaced modes, all doublescan modes for now) - - - cyblafb now works independant of the video mode in effect at startup - time (tridentfb does not init all needed registers to reasonable - values) - - - switching between video modes does work reliably now - - - the first video mode now is the one selected on startup using the - vga=???? mechanism or any of - - 640x480, 800x600, 1024x768, 1280x1024 - - 8, 16, 24 or 32 bpp - - refresh between 50 Hz and 85 Hz, 1 Hz steps (1280x1024-32 - is limited to 63Hz) - - - pci retry and pci burst mode are settable (try to disable if you - experience latency problems) - - - built as a module cyblafb might be unloaded and reloaded using - the vfb module and con2vt or might be used together with vesafb - diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index 5e02b83ac12b..a23361e80c64 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -255,6 +255,16 @@ Who: Jan Engelhardt --------------------------- +What: GPIO autorequest on gpio_direction_{input,output}() in gpiolib +When: February 2010 +Why: All callers should use explicit gpio_request()/gpio_free(). + The autorequest mechanism in gpiolib was provided mostly as a + migration aid for legacy GPIO interfaces (for SOC based GPIOs). + Those users have now largely migrated. Platforms implementing + the GPIO interfaces without using gpiolib will see no changes. +Who: David Brownell +--------------------------- + What: b43 support for firmware revision < 410 When: The schedule was July 2008, but it was decided that we are going to keep the code as long as there are no major maintanance headaches. @@ -311,6 +321,18 @@ Who: Vlad Yasevich --------------------------- +What: Ability for non root users to shm_get hugetlb pages based on mlock + resource limits +When: 2.6.31 +Why: Non root users need to be part of /proc/sys/vm/hugetlb_shm_group or + have CAP_IPC_LOCK to be able to allocate shm segments backed by + huge pages. The mlock based rlimit check to allow shm hugetlb is + inconsistent with mmap based allocations. Hence it is being + deprecated. +Who: Ravikiran Thirumalai + +--------------------------- + What: CONFIG_THERMAL_HWMON When: January 2009 Why: This option was introduced just to allow older lm-sensors userspace @@ -380,3 +402,35 @@ Why: The defines and typedefs (hw_interrupt_type, no_irq_type, irq_desc_t) have been kept around for migration reasons. After more than two years it's time to remove them finally Who: Thomas Gleixner + +--------------------------- + +What: fakephp and associated sysfs files in /sys/bus/pci/slots/ +When: 2011 +Why: In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to + represent a machine's physical PCI slots. The change in semantics + had userspace implications, as the hotplug core no longer allowed + drivers to create multiple sysfs files per physical slot (required + for multi-function devices, e.g.). fakephp was seen as a developer's + tool only, and its interface changed. Too late, we learned that + there were some users of the fakephp interface. + + In 2.6.30, the original fakephp interface was restored. At the same + time, the PCI core gained the ability that fakephp provided, namely + function-level hot-remove and hot-add. + + Since the PCI core now provides the same functionality, exposed in: + + /sys/bus/pci/rescan + /sys/bus/pci/devices/.../remove + /sys/bus/pci/devices/.../rescan + + there is no functional reason to maintain fakephp as well. + + We will keep the existing module so that 'modprobe fakephp' will + present the old /sys/bus/pci/slots/... interface for compatibility, + but users are urged to migrate their applications to the API above. + + After a reasonable transition period, we will remove the legacy + fakephp interface. +Who: Alex Chiang diff --git a/trunk/Documentation/filesystems/Locking b/trunk/Documentation/filesystems/Locking index 4e78ce677843..76efe5b71d7d 100644 --- a/trunk/Documentation/filesystems/Locking +++ b/trunk/Documentation/filesystems/Locking @@ -505,7 +505,7 @@ prototypes: void (*open)(struct vm_area_struct*); void (*close)(struct vm_area_struct*); int (*fault)(struct vm_area_struct*, struct vm_fault *); - int (*page_mkwrite)(struct vm_area_struct *, struct page *); + int (*page_mkwrite)(struct vm_area_struct *, struct vm_fault *); int (*access)(struct vm_area_struct *, unsigned long, void*, int, int); locking rules: diff --git a/trunk/Documentation/filesystems/caching/backend-api.txt b/trunk/Documentation/filesystems/caching/backend-api.txt new file mode 100644 index 000000000000..382d52cdaf2d --- /dev/null +++ b/trunk/Documentation/filesystems/caching/backend-api.txt @@ -0,0 +1,658 @@ + ========================== + FS-CACHE CACHE BACKEND API + ========================== + +The FS-Cache system provides an API by which actual caches can be supplied to +FS-Cache for it to then serve out to network filesystems and other interested +parties. + +This API is declared in . + + +==================================== +INITIALISING AND REGISTERING A CACHE +==================================== + +To start off, a cache definition must be initialised and registered for each +cache the backend wants to make available. For instance, CacheFS does this in +the fill_super() operation on mounting. + +The cache definition (struct fscache_cache) should be initialised by calling: + + void fscache_init_cache(struct fscache_cache *cache, + struct fscache_cache_ops *ops, + const char *idfmt, + ...); + +Where: + + (*) "cache" is a pointer to the cache definition; + + (*) "ops" is a pointer to the table of operations that the backend supports on + this cache; and + + (*) "idfmt" is a format and printf-style arguments for constructing a label + for the cache. + + +The cache should then be registered with FS-Cache by passing a pointer to the +previously initialised cache definition to: + + int fscache_add_cache(struct fscache_cache *cache, + struct fscache_object *fsdef, + const char *tagname); + +Two extra arguments should also be supplied: + + (*) "fsdef" which should point to the object representation for the FS-Cache + master index in this cache. Netfs primary index entries will be created + here. FS-Cache keeps the caller's reference to the index object if + successful and will release it upon withdrawal of the cache. + + (*) "tagname" which, if given, should be a text string naming this cache. If + this is NULL, the identifier will be used instead. For CacheFS, the + identifier is set to name the underlying block device and the tag can be + supplied by mount. + +This function may return -ENOMEM if it ran out of memory or -EEXIST if the tag +is already in use. 0 will be returned on success. + + +===================== +UNREGISTERING A CACHE +===================== + +A cache can be withdrawn from the system by calling this function with a +pointer to the cache definition: + + void fscache_withdraw_cache(struct fscache_cache *cache); + +In CacheFS's case, this is called by put_super(). + + +======== +SECURITY +======== + +The cache methods are executed one of two contexts: + + (1) that of the userspace process that issued the netfs operation that caused + the cache method to be invoked, or + + (2) that of one of the processes in the FS-Cache thread pool. + +In either case, this may not be an appropriate context in which to access the +cache. + +The calling process's fsuid, fsgid and SELinux security identities may need to +be masqueraded for the duration of the cache driver's access to the cache. +This is left to the cache to handle; FS-Cache makes no effort in this regard. + + +=================================== +CONTROL AND STATISTICS PRESENTATION +=================================== + +The cache may present data to the outside world through FS-Cache's interfaces +in sysfs and procfs - the former for control and the latter for statistics. + +A sysfs directory called /sys/fs/fscache// is created if CONFIG_SYSFS +is enabled. This is accessible through the kobject struct fscache_cache::kobj +and is for use by the cache as it sees fit. + + +======================== +RELEVANT DATA STRUCTURES +======================== + + (*) Index/Data file FS-Cache representation cookie: + + struct fscache_cookie { + struct fscache_object_def *def; + struct fscache_netfs *netfs; + void *netfs_data; + ... + }; + + The fields that might be of use to the backend describe the object + definition, the netfs definition and the netfs's data for this cookie. + The object definition contain functions supplied by the netfs for loading + and matching index entries; these are required to provide some of the + cache operations. + + + (*) In-cache object representation: + + struct fscache_object { + int debug_id; + enum { + FSCACHE_OBJECT_RECYCLING, + ... + } state; + spinlock_t lock + struct fscache_cache *cache; + struct fscache_cookie *cookie; + ... + }; + + Structures of this type should be allocated by the cache backend and + passed to FS-Cache when requested by the appropriate cache operation. In + the case of CacheFS, they're embedded in CacheFS's internal object + structures. + + The debug_id is a simple integer that can be used in debugging messages + that refer to a particular object. In such a case it should be printed + using "OBJ%x" to be consistent with FS-Cache. + + Each object contains a pointer to the cookie that represents the object it + is backing. An object should retired when put_object() is called if it is + in state FSCACHE_OBJECT_RECYCLING. The fscache_object struct should be + initialised by calling fscache_object_init(object). + + + (*) FS-Cache operation record: + + struct fscache_operation { + atomic_t usage; + struct fscache_object *object; + unsigned long flags; + #define FSCACHE_OP_EXCLUSIVE + void (*processor)(struct fscache_operation *op); + void (*release)(struct fscache_operation *op); + ... + }; + + FS-Cache has a pool of threads that it uses to give CPU time to the + various asynchronous operations that need to be done as part of driving + the cache. These are represented by the above structure. The processor + method is called to give the op CPU time, and the release method to get + rid of it when its usage count reaches 0. + + An operation can be made exclusive upon an object by setting the + appropriate flag before enqueuing it with fscache_enqueue_operation(). If + an operation needs more processing time, it should be enqueued again. + + + (*) FS-Cache retrieval operation record: + + struct fscache_retrieval { + struct fscache_operation op; + struct address_space *mapping; + struct list_head *to_do; + ... + }; + + A structure of this type is allocated by FS-Cache to record retrieval and + allocation requests made by the netfs. This struct is then passed to the + backend to do the operation. The backend may get extra refs to it by + calling fscache_get_retrieval() and refs may be discarded by calling + fscache_put_retrieval(). + + A retrieval operation can be used by the backend to do retrieval work. To + do this, the retrieval->op.processor method pointer should be set + appropriately by the backend and fscache_enqueue_retrieval() called to + submit it to the thread pool. CacheFiles, for example, uses this to queue + page examination when it detects PG_lock being cleared. + + The to_do field is an empty list available for the cache backend to use as + it sees fit. + + + (*) FS-Cache storage operation record: + + struct fscache_storage { + struct fscache_operation op; + pgoff_t store_limit; + ... + }; + + A structure of this type is allocated by FS-Cache to record outstanding + writes to be made. FS-Cache itself enqueues this operation and invokes + the write_page() method on the object at appropriate times to effect + storage. + + +================ +CACHE OPERATIONS +================ + +The cache backend provides FS-Cache with a table of operations that can be +performed on the denizens of the cache. These are held in a structure of type: + + struct fscache_cache_ops + + (*) Name of cache provider [mandatory]: + + const char *name + + This isn't strictly an operation, but should be pointed at a string naming + the backend. + + + (*) Allocate a new object [mandatory]: + + struct fscache_object *(*alloc_object)(struct fscache_cache *cache, + struct fscache_cookie *cookie) + + This method is used to allocate a cache object representation to back a + cookie in a particular cache. fscache_object_init() should be called on + the object to initialise it prior to returning. + + This function may also be used to parse the index key to be used for + multiple lookup calls to turn it into a more convenient form. FS-Cache + will call the lookup_complete() method to allow the cache to release the + form once lookup is complete or aborted. + + + (*) Look up and create object [mandatory]: + + void (*lookup_object)(struct fscache_object *object) + + This method is used to look up an object, given that the object is already + allocated and attached to the cookie. This should instantiate that object + in the cache if it can. + + The method should call fscache_object_lookup_negative() as soon as + possible if it determines the object doesn't exist in the cache. If the + object is found to exist and the netfs indicates that it is valid then + fscache_obtained_object() should be called once the object is in a + position to have data stored in it. Similarly, fscache_obtained_object() + should also be called once a non-present object has been created. + + If a lookup error occurs, fscache_object_lookup_error() should be called + to abort the lookup of that object. + + + (*) Release lookup data [mandatory]: + + void (*lookup_complete)(struct fscache_object *object) + + This method is called to ask the cache to release any resources it was + using to perform a lookup. + + + (*) Increment object refcount [mandatory]: + + struct fscache_object *(*grab_object)(struct fscache_object *object) + + This method is called to increment the reference count on an object. It + may fail (for instance if the cache is being withdrawn) by returning NULL. + It should return the object pointer if successful. + + + (*) Lock/Unlock object [mandatory]: + + void (*lock_object)(struct fscache_object *object) + void (*unlock_object)(struct fscache_object *object) + + These methods are used to exclusively lock an object. It must be possible + to schedule with the lock held, so a spinlock isn't sufficient. + + + (*) Pin/Unpin object [optional]: + + int (*pin_object)(struct fscache_object *object) + void (*unpin_object)(struct fscache_object *object) + + These methods are used to pin an object into the cache. Once pinned an + object cannot be reclaimed to make space. Return -ENOSPC if there's not + enough space in the cache to permit this. + + + (*) Update object [mandatory]: + + int (*update_object)(struct fscache_object *object) + + This is called to update the index entry for the specified object. The + new information should be in object->cookie->netfs_data. This can be + obtained by calling object->cookie->def->get_aux()/get_attr(). + + + (*) Discard object [mandatory]: + + void (*drop_object)(struct fscache_object *object) + + This method is called to indicate that an object has been unbound from its + cookie, and that the cache should release the object's resources and + retire it if it's in state FSCACHE_OBJECT_RECYCLING. + + This method should not attempt to release any references held by the + caller. The caller will invoke the put_object() method as appropriate. + + + (*) Release object reference [mandatory]: + + void (*put_object)(struct fscache_object *object) + + This method is used to discard a reference to an object. The object may + be freed when all the references to it are released. + + + (*) Synchronise a cache [mandatory]: + + void (*sync)(struct fscache_cache *cache) + + This is called to ask the backend to synchronise a cache with its backing + device. + + + (*) Dissociate a cache [mandatory]: + + void (*dissociate_pages)(struct fscache_cache *cache) + + This is called to ask a cache to perform any page dissociations as part of + cache withdrawal. + + + (*) Notification that the attributes on a netfs file changed [mandatory]: + + int (*attr_changed)(struct fscache_object *object); + + This is called to indicate to the cache that certain attributes on a netfs + file have changed (for example the maximum size a file may reach). The + cache can read these from the netfs by calling the cookie's get_attr() + method. + + The cache may use the file size information to reserve space on the cache. + It should also call fscache_set_store_limit() to indicate to FS-Cache the + highest byte it's willing to store for an object. + + This method may return -ve if an error occurred or the cache object cannot + be expanded. In such a case, the object will be withdrawn from service. + + This operation is run asynchronously from FS-Cache's thread pool, and + storage and retrieval operations from the netfs are excluded during the + execution of this operation. + + + (*) Reserve cache space for an object's data [optional]: + + int (*reserve_space)(struct fscache_object *object, loff_t size); + + This is called to request that cache space be reserved to hold the data + for an object and the metadata used to track it. Zero size should be + taken as request to cancel a reservation. + + This should return 0 if successful, -ENOSPC if there isn't enough space + available, or -ENOMEM or -EIO on other errors. + + The reservation may exceed the current size of the object, thus permitting + future expansion. If the amount of space consumed by an object would + exceed the reservation, it's permitted to refuse requests to allocate + pages, but not required. An object may be pruned down to its reservation + size if larger than that already. + + + (*) Request page be read from cache [mandatory]: + + int (*read_or_alloc_page)(struct fscache_retrieval *op, + struct page *page, + gfp_t gfp) + + This is called to attempt to read a netfs page from the cache, or to + reserve a backing block if not. FS-Cache will have done as much checking + as it can before calling, but most of the work belongs to the backend. + + If there's no page in the cache, then -ENODATA should be returned if the + backend managed to reserve a backing block; -ENOBUFS or -ENOMEM if it + didn't. + + If there is suitable data in the cache, then a read operation should be + queued and 0 returned. When the read finishes, fscache_end_io() should be + called. + + The fscache_mark_pages_cached() should be called for the page if any cache + metadata is retained. This will indicate to the netfs that the page needs + explicit uncaching. This operation takes a pagevec, thus allowing several + pages to be marked at once. + + The retrieval record pointed to by op should be retained for each page + queued and released when I/O on the page has been formally ended. + fscache_get/put_retrieval() are available for this purpose. + + The retrieval record may be used to get CPU time via the FS-Cache thread + pool. If this is desired, the op->op.processor should be set to point to + the appropriate processing routine, and fscache_enqueue_retrieval() should + be called at an appropriate point to request CPU time. For instance, the + retrieval routine could be enqueued upon the completion of a disk read. + The to_do field in the retrieval record is provided to aid in this. + + If an I/O error occurs, fscache_io_error() should be called and -ENOBUFS + returned if possible or fscache_end_io() called with a suitable error + code.. + + + (*) Request pages be read from cache [mandatory]: + + int (*read_or_alloc_pages)(struct fscache_retrieval *op, + struct list_head *pages, + unsigned *nr_pages, + gfp_t gfp) + + This is like the read_or_alloc_page() method, except it is handed a list + of pages instead of one page. Any pages on which a read operation is + started must be added to the page cache for the specified mapping and also + to the LRU. Such pages must also be removed from the pages list and + *nr_pages decremented per page. + + If there was an error such as -ENOMEM, then that should be returned; else + if one or more pages couldn't be read or allocated, then -ENOBUFS should + be returned; else if one or more pages couldn't be read, then -ENODATA + should be returned. If all the pages are dispatched then 0 should be + returned. + + + (*) Request page be allocated in the cache [mandatory]: + + int (*allocate_page)(struct fscache_retrieval *op, + struct page *page, + gfp_t gfp) + + This is like the read_or_alloc_page() method, except that it shouldn't + read from the cache, even if there's data there that could be retrieved. + It should, however, set up any internal metadata required such that + the write_page() method can write to the cache. + + If there's no backing block available, then -ENOBUFS should be returned + (or -ENOMEM if there were other problems). If a block is successfully + allocated, then the netfs page should be marked and 0 returned. + + + (*) Request pages be allocated in the cache [mandatory]: + + int (*allocate_pages)(struct fscache_retrieval *op, + struct list_head *pages, + unsigned *nr_pages, + gfp_t gfp) + + This is an multiple page version of the allocate_page() method. pages and + nr_pages should be treated as for the read_or_alloc_pages() method. + + + (*) Request page be written to cache [mandatory]: + + int (*write_page)(struct fscache_storage *op, + struct page *page); + + This is called to write from a page on which there was a previously + successful read_or_alloc_page() call or similar. FS-Cache filters out + pages that don't have mappings. + + This method is called asynchronously from the FS-Cache thread pool. It is + not required to actually store anything, provided -ENODATA is then + returned to the next read of this page. + + If an error occurred, then a negative error code should be returned, + otherwise zero should be returned. FS-Cache will take appropriate action + in response to an error, such as withdrawing this object. + + If this method returns success then FS-Cache will inform the netfs + appropriately. + + + (*) Discard retained per-page metadata [mandatory]: + + void (*uncache_page)(struct fscache_object *object, struct page *page) + + This is called when a netfs page is being evicted from the pagecache. The + cache backend should tear down any internal representation or tracking it + maintains for this page. + + +================== +FS-CACHE UTILITIES +================== + +FS-Cache provides some utilities that a cache backend may make use of: + + (*) Note occurrence of an I/O error in a cache: + + void fscache_io_error(struct fscache_cache *cache) + + This tells FS-Cache that an I/O error occurred in the cache. After this + has been called, only resource dissociation operations (object and page + release) will be passed from the netfs to the cache backend for the + specified cache. + + This does not actually withdraw the cache. That must be done separately. + + + (*) Invoke the retrieval I/O completion function: + + void fscache_end_io(struct fscache_retrieval *op, struct page *page, + int error); + + This is called to note the end of an attempt to retrieve a page. The + error value should be 0 if successful and an error otherwise. + + + (*) Set highest store limit: + + void fscache_set_store_limit(struct fscache_object *object, + loff_t i_size); + + This sets the limit FS-Cache imposes on the highest byte it's willing to + try and store for a netfs. Any page over this limit is automatically + rejected by fscache_read_alloc_page() and co with -ENOBUFS. + + + (*) Mark pages as being cached: + + void fscache_mark_pages_cached(struct fscache_retrieval *op, + struct pagevec *pagevec); + + This marks a set of pages as being cached. After this has been called, + the netfs must call fscache_uncache_page() to unmark the pages. + + + (*) Perform coherency check on an object: + + enum fscache_checkaux fscache_check_aux(struct fscache_object *object, + const void *data, + uint16_t datalen); + + This asks the netfs to perform a coherency check on an object that has + just been looked up. The cookie attached to the object will determine the + netfs to use. data and datalen should specify where the auxiliary data + retrieved from the cache can be found. + + One of three values will be returned: + + (*) FSCACHE_CHECKAUX_OKAY + + The coherency data indicates the object is valid as is. + + (*) FSCACHE_CHECKAUX_NEEDS_UPDATE + + The coherency data needs updating, but otherwise the object is + valid. + + (*) FSCACHE_CHECKAUX_OBSOLETE + + The coherency data indicates that the object is obsolete and should + be discarded. + + + (*) Initialise a freshly allocated object: + + void fscache_object_init(struct fscache_object *object); + + This initialises all the fields in an object representation. + + + (*) Indicate the destruction of an object: + + void fscache_object_destroyed(struct fscache_cache *cache); + + This must be called to inform FS-Cache that an object that belonged to a + cache has been destroyed and deallocated. This will allow continuation + of the cache withdrawal process when it is stopped pending destruction of + all the objects. + + + (*) Indicate negative lookup on an object: + + void fscache_object_lookup_negative(struct fscache_object *object); + + This is called to indicate to FS-Cache that a lookup process for an object + found a negative result. + + This changes the state of an object to permit reads pending on lookup + completion to go off and start fetching data from the netfs server as it's + known at this point that there can't be any data in the cache. + + This may be called multiple times on an object. Only the first call is + significant - all subsequent calls are ignored. + + + (*) Indicate an object has been obtained: + + void fscache_obtained_object(struct fscache_object *object); + + This is called to indicate to FS-Cache that a lookup process for an object + produced a positive result, or that an object was created. This should + only be called once for any particular object. + + This changes the state of an object to indicate: + + (1) if no call to fscache_object_lookup_negative() has been made on + this object, that there may be data available, and that reads can + now go and look for it; and + + (2) that writes may now proceed against this object. + + + (*) Indicate that object lookup failed: + + void fscache_object_lookup_error(struct fscache_object *object); + + This marks an object as having encountered a fatal error (usually EIO) + and causes it to move into a state whereby it will be withdrawn as soon + as possible. + + + (*) Get and release references on a retrieval record: + + void fscache_get_retrieval(struct fscache_retrieval *op); + void fscache_put_retrieval(struct fscache_retrieval *op); + + These two functions are used to retain a retrieval record whilst doing + asynchronous data retrieval and block allocation. + + + (*) Enqueue a retrieval record for processing. + + void fscache_enqueue_retrieval(struct fscache_retrieval *op); + + This enqueues a retrieval record for processing by the FS-Cache thread + pool. One of the threads in the pool will invoke the retrieval record's + op->op.processor callback function. This function may be called from + within the callback function. + + + (*) List of object state names: + + const char *fscache_object_states[]; + + For debugging purposes, this may be used to turn the state that an object + is in into a text string for display purposes. diff --git a/trunk/Documentation/filesystems/caching/cachefiles.txt b/trunk/Documentation/filesystems/caching/cachefiles.txt new file mode 100644 index 000000000000..c78a49b7bba6 --- /dev/null +++ b/trunk/Documentation/filesystems/caching/cachefiles.txt @@ -0,0 +1,501 @@ + =============================================== + CacheFiles: CACHE ON ALREADY MOUNTED FILESYSTEM + =============================================== + +Contents: + + (*) Overview. + + (*) Requirements. + + (*) Configuration. + + (*) Starting the cache. + + (*) Things to avoid. + + (*) Cache culling. + + (*) Cache structure. + + (*) Security model and SELinux. + + (*) A note on security. + + (*) Statistical information. + + (*) Debugging. + + +======== +OVERVIEW +======== + +CacheFiles is a caching backend that's meant to use as a cache a directory on +an already mounted filesystem of a local type (such as Ext3). + +CacheFiles uses a userspace daemon to do some of the cache management - such as +reaping stale nodes and culling. This is called cachefilesd and lives in +/sbin. + +The filesystem and data integrity of the cache are only as good as those of the +filesystem providing the backing services. Note that CacheFiles does not +attempt to journal anything since the journalling interfaces of the various +filesystems are very specific in nature. + +CacheFiles creates a misc character device - "/dev/cachefiles" - that is used +to communication with the daemon. Only one thing may have this open at once, +and whilst it is open, a cache is at least partially in existence. The daemon +opens this and sends commands down it to control the cache. + +CacheFiles is currently limited to a single cache. + +CacheFiles attempts to maintain at least a certain percentage of free space on +the filesystem, shrinking the cache by culling the objects it contains to make +space if necessary - see the "Cache Culling" section. This means it can be +placed on the same medium as a live set of data, and will expand to make use of +spare space and automatically contract when the set of data requires more +space. + + +============ +REQUIREMENTS +============ + +The use of CacheFiles and its daemon requires the following features to be +available in the system and in the cache filesystem: + + - dnotify. + + - extended attributes (xattrs). + + - openat() and friends. + + - bmap() support on files in the filesystem (FIBMAP ioctl). + + - The use of bmap() to detect a partial page at the end of the file. + +It is strongly recommended that the "dir_index" option is enabled on Ext3 +filesystems being used as a cache. + + +============= +CONFIGURATION +============= + +The cache is configured by a script in /etc/cachefilesd.conf. These commands +set up cache ready for use. The following script commands are available: + + (*) brun % + (*) bcull % + (*) bstop % + (*) frun % + (*) fcull % + (*) fstop % + + Configure the culling limits. Optional. See the section on culling + The defaults are 7% (run), 5% (cull) and 1% (stop) respectively. + + The commands beginning with a 'b' are file space (block) limits, those + beginning with an 'f' are file count limits. + + (*) dir + + Specify the directory containing the root of the cache. Mandatory. + + (*) tag + + Specify a tag to FS-Cache to use in distinguishing multiple caches. + Optional. The default is "CacheFiles". + + (*) debug + + Specify a numeric bitmask to control debugging in the kernel module. + Optional. The default is zero (all off). The following values can be + OR'd into the mask to collect various information: + + 1 Turn on trace of function entry (_enter() macros) + 2 Turn on trace of function exit (_leave() macros) + 4 Turn on trace of internal debug points (_debug()) + + This mask can also be set through sysfs, eg: + + echo 5 >/sys/modules/cachefiles/parameters/debug + + +================== +STARTING THE CACHE +================== + +The cache is started by running the daemon. The daemon opens the cache device, +configures the cache and tells it to begin caching. At that point the cache +binds to fscache and the cache becomes live. + +The daemon is run as follows: + + /sbin/cachefilesd [-d]* [-s] [-n] [-f ] + +The flags are: + + (*) -d + + Increase the debugging level. This can be specified multiple times and + is cumulative with itself. + + (*) -s + + Send messages to stderr instead of syslog. + + (*) -n + + Don't daemonise and go into background. + + (*) -f + + Use an alternative configuration file rather than the default one. + + +=============== +THINGS TO AVOID +=============== + +Do not mount other things within the cache as this will cause problems. The +kernel module contains its own very cut-down path walking facility that ignores +mountpoints, but the daemon can't avoid them. + +Do not create, rename or unlink files and directories in the cache whilst the +cache is active, as this may cause the state to become uncertain. + +Renaming files in the cache might make objects appear to be other objects (the +filename is part of the lookup key). + +Do not change or remove the extended attributes attached to cache files by the +cache as this will cause the cache state management to get confused. + +Do not create files or directories in the cache, lest the cache get confused or +serve incorrect data. + +Do not chmod files in the cache. The module creates things with minimal +permissions to prevent random users being able to access them directly. + + +============= +CACHE CULLING +============= + +The cache may need culling occasionally to make space. This involves +discarding objects from the cache that have been used less recently than +anything else. Culling is based on the access time of data objects. Empty +directories are culled if not in use. + +Cache culling is done on the basis of the percentage of blocks and the +percentage of files available in the underlying filesystem. There are six +"limits": + + (*) brun + (*) frun + + If the amount of free space and the number of available files in the cache + rises above both these limits, then culling is turned off. + + (*) bcull + (*) fcull + + If the amount of available space or the number of available files in the + cache falls below either of these limits, then culling is started. + + (*) bstop + (*) fstop + + If the amount of available space or the number of available files in the + cache falls below either of these limits, then no further allocation of + disk space or files is permitted until culling has raised things above + these limits again. + +These must be configured thusly: + + 0 <= bstop < bcull < brun < 100 + 0 <= fstop < fcull < frun < 100 + +Note that these are percentages of available space and available files, and do +_not_ appear as 100 minus the percentage displayed by the "df" program. + +The userspace daemon scans the cache to build up a table of cullable objects. +These are then culled in least recently used order. A new scan of the cache is +started as soon as space is made in the table. Objects will be skipped if +their atimes have changed or if the kernel module says it is still using them. + + +=============== +CACHE STRUCTURE +=============== + +The CacheFiles module will create two directories in the directory it was +given: + + (*) cache/ + + (*) graveyard/ + +The active cache objects all reside in the first directory. The CacheFiles +kernel module moves any retired or culled objects that it can't simply unlink +to the graveyard from which the daemon will actually delete them. + +The daemon uses dnotify to monitor the graveyard directory, and will delete +anything that appears therein. + + +The module represents index objects as directories with the filename "I..." or +"J...". Note that the "cache/" directory is itself a special index. + +Data objects are represented as files if they have no children, or directories +if they do. Their filenames all begin "D..." or "E...". If represented as a +directory, data objects will have a file in the directory called "data" that +actually holds the data. + +Special objects are similar to data objects, except their filenames begin +"S..." or "T...". + + +If an object has children, then it will be represented as a directory. +Immediately in the representative directory are a collection of directories +named for hash values of the child object keys with an '@' prepended. Into +this directory, if possible, will be placed the representations of the child +objects: + + INDEX INDEX INDEX DATA FILES + ========= ========== ================================= ================ + cache/@4a/I03nfs/@30/Ji000000000000000--fHg8hi8400 + cache/@4a/I03nfs/@30/Ji000000000000000--fHg8hi8400/@75/Es0g000w...DB1ry + cache/@4a/I03nfs/@30/Ji000000000000000--fHg8hi8400/@75/Es0g000w...N22ry + cache/@4a/I03nfs/@30/Ji000000000000000--fHg8hi8400/@75/Es0g000w...FP1ry + + +If the key is so long that it exceeds NAME_MAX with the decorations added on to +it, then it will be cut into pieces, the first few of which will be used to +make a nest of directories, and the last one of which will be the objects +inside the last directory. The names of the intermediate directories will have +'+' prepended: + + J1223/@23/+xy...z/+kl...m/Epqr + + +Note that keys are raw data, and not only may they exceed NAME_MAX in size, +they may also contain things like '/' and NUL characters, and so they may not +be suitable for turning directly into a filename. + +To handle this, CacheFiles will use a suitably printable filename directly and +"base-64" encode ones that aren't directly suitable. The two versions of +object filenames indicate the encoding: + + OBJECT TYPE PRINTABLE ENCODED + =============== =============== =============== + Index "I..." "J..." + Data "D..." "E..." + Special "S..." "T..." + +Intermediate directories are always "@" or "+" as appropriate. + + +Each object in the cache has an extended attribute label that holds the object +type ID (required to distinguish special objects) and the auxiliary data from +the netfs. The latter is used to detect stale objects in the cache and update +or retire them. + + +Note that CacheFiles will erase from the cache any file it doesn't recognise or +any file of an incorrect type (such as a FIFO file or a device file). + + +========================== +SECURITY MODEL AND SELINUX +========================== + +CacheFiles is implemented to deal properly with the LSM security features of +the Linux kernel and the SELinux facility. + +One of the problems that CacheFiles faces is that it is generally acting on +behalf of a process, and running in that process's context, and that includes a +security context that is not appropriate for accessing the cache - either +because the files in the cache are inaccessible to that process, or because if +the process creates a file in the cache, that file may be inaccessible to other +processes. + +The way CacheFiles works is to temporarily change the security context (fsuid, +fsgid and actor security label) that the process acts as - without changing the +security context of the process when it the target of an operation performed by +some other process (so signalling and suchlike still work correctly). + + +When the CacheFiles module is asked to bind to its cache, it: + + (1) Finds the security label attached to the root cache directory and uses + that as the security label with which it will create files. By default, + this is: + + cachefiles_var_t + + (2) Finds the security label of the process which issued the bind request + (presumed to be the cachefilesd daemon), which by default will be: + + cachefilesd_t + + and asks LSM to supply a security ID as which it should act given the + daemon's label. By default, this will be: + + cachefiles_kernel_t + + SELinux transitions the daemon's security ID to the module's security ID + based on a rule of this form in the policy. + + type_transition kernel_t : process ; + + For instance: + + type_transition cachefilesd_t kernel_t : process cachefiles_kernel_t; + + +The module's security ID gives it permission to create, move and remove files +and directories in the cache, to find and access directories and files in the +cache, to set and access extended attributes on cache objects, and to read and +write files in the cache. + +The daemon's security ID gives it only a very restricted set of permissions: it +may scan directories, stat files and erase files and directories. It may +not read or write files in the cache, and so it is precluded from accessing the +data cached therein; nor is it permitted to create new files in the cache. + + +There are policy source files available in: + + http://people.redhat.com/~dhowells/fscache/cachefilesd-0.8.tar.bz2 + +and later versions. In that tarball, see the files: + + cachefilesd.te + cachefilesd.fc + cachefilesd.if + +They are built and installed directly by the RPM. + +If a non-RPM based system is being used, then copy the above files to their own +directory and run: + + make -f /usr/share/selinux/devel/Makefile + semodule -i cachefilesd.pp + +You will need checkpolicy and selinux-policy-devel installed prior to the +build. + + +By default, the cache is located in /var/fscache, but if it is desirable that +it should be elsewhere, than either the above policy files must be altered, or +an auxiliary policy must be installed to label the alternate location of the +cache. + +For instructions on how to add an auxiliary policy to enable the cache to be +located elsewhere when SELinux is in enforcing mode, please see: + + /usr/share/doc/cachefilesd-*/move-cache.txt + +When the cachefilesd rpm is installed; alternatively, the document can be found +in the sources. + + +================== +A NOTE ON SECURITY +================== + +CacheFiles makes use of the split security in the task_struct. It allocates +its own task_security structure, and redirects current->act_as to point to it +when it acts on behalf of another process, in that process's context. + +The reason it does this is that it calls vfs_mkdir() and suchlike rather than +bypassing security and calling inode ops directly. Therefore the VFS and LSM +may deny the CacheFiles access to the cache data because under some +circumstances the caching code is running in the security context of whatever +process issued the original syscall on the netfs. + +Furthermore, should CacheFiles create a file or directory, the security +parameters with that object is created (UID, GID, security label) would be +derived from that process that issued the system call, thus potentially +preventing other processes from accessing the cache - including CacheFiles's +cache management daemon (cachefilesd). + +What is required is to temporarily override the security of the process that +issued the system call. We can't, however, just do an in-place change of the +security data as that affects the process as an object, not just as a subject. +This means it may lose signals or ptrace events for example, and affects what +the process looks like in /proc. + +So CacheFiles makes use of a logical split in the security between the +objective security (task->sec) and the subjective security (task->act_as). The +objective security holds the intrinsic security properties of a process and is +never overridden. This is what appears in /proc, and is what is used when a +process is the target of an operation by some other process (SIGKILL for +example). + +The subjective security holds the active security properties of a process, and +may be overridden. This is not seen externally, and is used whan a process +acts upon another object, for example SIGKILLing another process or opening a +file. + +LSM hooks exist that allow SELinux (or Smack or whatever) to reject a request +for CacheFiles to run in a context of a specific security label, or to create +files and directories with another security label. + + +======================= +STATISTICAL INFORMATION +======================= + +If FS-Cache is compiled with the following option enabled: + + CONFIG_CACHEFILES_HISTOGRAM=y + +then it will gather certain statistics and display them through a proc file. + + (*) /proc/fs/cachefiles/histogram + + cat /proc/fs/cachefiles/histogram + JIFS SECS LOOKUPS MKDIRS CREATES + ===== ===== ========= ========= ========= + + This shows the breakdown of the number of times each amount of time + between 0 jiffies and HZ-1 jiffies a variety of tasks took to run. The + columns are as follows: + + COLUMN TIME MEASUREMENT + ======= ======================================================= + LOOKUPS Length of time to perform a lookup on the backing fs + MKDIRS Length of time to perform a mkdir on the backing fs + CREATES Length of time to perform a create on the backing fs + + Each row shows the number of events that took a particular range of times. + Each step is 1 jiffy in size. The JIFS column indicates the particular + jiffy range covered, and the SECS field the equivalent number of seconds. + + +========= +DEBUGGING +========= + +If CONFIG_CACHEFILES_DEBUG is enabled, the CacheFiles facility can have runtime +debugging enabled by adjusting the value in: + + /sys/module/cachefiles/parameters/debug + +This is a bitmask of debugging streams to enable: + + BIT VALUE STREAM POINT + ======= ======= =============================== ======================= + 0 1 General Function entry trace + 1 2 Function exit trace + 2 4 General + +The appropriate set of values should be OR'd together and the result written to +the control file. For example: + + echo $((1|4|8)) >/sys/module/cachefiles/parameters/debug + +will turn on all function entry debugging. diff --git a/trunk/Documentation/filesystems/caching/fscache.txt b/trunk/Documentation/filesystems/caching/fscache.txt new file mode 100644 index 000000000000..9e94b9491d89 --- /dev/null +++ b/trunk/Documentation/filesystems/caching/fscache.txt @@ -0,0 +1,333 @@ + ========================== + General Filesystem Caching + ========================== + +======== +OVERVIEW +======== + +This facility is a general purpose cache for network filesystems, though it +could be used for caching other things such as ISO9660 filesystems too. + +FS-Cache mediates between cache backends (such as CacheFS) and network +filesystems: + + +---------+ + | | +--------------+ + | NFS |--+ | | + | | | +-->| CacheFS | + +---------+ | +----------+ | | /dev/hda5 | + | | | | +--------------+ + +---------+ +-->| | | + | | | |--+ + | AFS |----->| FS-Cache | + | | | |--+ + +---------+ +-->| | | + | | | | +--------------+ + +---------+ | +----------+ | | | + | | | +-->| CacheFiles | + | ISOFS |--+ | /var/cache | + | | +--------------+ + +---------+ + +Or to look at it another way, FS-Cache is a module that provides a caching +facility to a network filesystem such that the cache is transparent to the +user: + + +---------+ + | | + | Server | + | | + +---------+ + | NETWORK + ~~~~~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | + | +----------+ + V | | + +---------+ | | + | | | | + | NFS |----->| FS-Cache | + | | | |--+ + +---------+ | | | +--------------+ +--------------+ + | | | | | | | | + V +----------+ +-->| CacheFiles |-->| Ext3 | + +---------+ | /var/cache | | /dev/sda6 | + | | +--------------+ +--------------+ + | VFS | ^ ^ + | | | | + +---------+ +--------------+ | + | KERNEL SPACE | | + ~~~~~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|~~~~~~|~~~~ + | USER SPACE | | + V | | + +---------+ +--------------+ + | | | | + | Process | | cachefilesd | + | | | | + +---------+ +--------------+ + + +FS-Cache does not follow the idea of completely loading every netfs file +opened in its entirety into a cache before permitting it to be accessed and +then serving the pages out of that cache rather than the netfs inode because: + + (1) It must be practical to operate without a cache. + + (2) The size of any accessible file must not be limited to the size of the + cache. + + (3) The combined size of all opened files (this includes mapped libraries) + must not be limited to the size of the cache. + + (4) The user should not be forced to download an entire file just to do a + one-off access of a small portion of it (such as might be done with the + "file" program). + +It instead serves the cache out in PAGE_SIZE chunks as and when requested by +the netfs('s) using it. + + +FS-Cache provides the following facilities: + + (1) More than one cache can be used at once. Caches can be selected + explicitly by use of tags. + + (2) Caches can be added / removed at any time. + + (3) The netfs is provided with an interface that allows either party to + withdraw caching facilities from a file (required for (2)). + + (4) The interface to the netfs returns as few errors as possible, preferring + rather to let the netfs remain oblivious. + + (5) Cookies are used to represent indices, files and other objects to the + netfs. The simplest cookie is just a NULL pointer - indicating nothing + cached there. + + (6) The netfs is allowed to propose - dynamically - any index hierarchy it + desires, though it must be aware that the index search function is + recursive, stack space is limited, and indices can only be children of + indices. + + (7) Data I/O is done direct to and from the netfs's pages. The netfs + indicates that page A is at index B of the data-file represented by cookie + C, and that it should be read or written. The cache backend may or may + not start I/O on that page, but if it does, a netfs callback will be + invoked to indicate completion. The I/O may be either synchronous or + asynchronous. + + (8) Cookies can be "retired" upon release. At this point FS-Cache will mark + them as obsolete and the index hierarchy rooted at that point will get + recycled. + + (9) The netfs provides a "match" function for index searches. In addition to + saying whether a match was made or not, this can also specify that an + entry should be updated or deleted. + +(10) As much as possible is done asynchronously. + + +FS-Cache maintains a virtual indexing tree in which all indices, files, objects +and pages are kept. Bits of this tree may actually reside in one or more +caches. + + FSDEF + | + +------------------------------------+ + | | + NFS AFS + | | + +--------------------------+ +-----------+ + | | | | + homedir mirror afs.org redhat.com + | | | + +------------+ +---------------+ +----------+ + | | | | | | + 00001 00002 00007 00125 vol00001 vol00002 + | | | | | + +---+---+ +-----+ +---+ +------+------+ +-----+----+ + | | | | | | | | | | | | | +PG0 PG1 PG2 PG0 XATTR PG0 PG1 DIRENT DIRENT DIRENT R/W R/O Bak + | | + PG0 +-------+ + | | + 00001 00003 + | + +---+---+ + | | | + PG0 PG1 PG2 + +In the example above, you can see two netfs's being backed: NFS and AFS. These +have different index hierarchies: + + (*) The NFS primary index contains per-server indices. Each server index is + indexed by NFS file handles to get data file objects. Each data file + objects can have an array of pages, but may also have further child + objects, such as extended attributes and directory entries. Extended + attribute objects themselves have page-array contents. + + (*) The AFS primary index contains per-cell indices. Each cell index contains + per-logical-volume indices. Each of volume index contains up to three + indices for the read-write, read-only and backup mirrors of those volumes. + Each of these contains vnode data file objects, each of which contains an + array of pages. + +The very top index is the FS-Cache master index in which individual netfs's +have entries. + +Any index object may reside in more than one cache, provided it only has index +children. Any index with non-index object children will be assumed to only +reside in one cache. + + +The netfs API to FS-Cache can be found in: + + Documentation/filesystems/caching/netfs-api.txt + +The cache backend API to FS-Cache can be found in: + + Documentation/filesystems/caching/backend-api.txt + +A description of the internal representations and object state machine can be +found in: + + Documentation/filesystems/caching/object.txt + + +======================= +STATISTICAL INFORMATION +======================= + +If FS-Cache is compiled with the following options enabled: + + CONFIG_FSCACHE_STATS=y + CONFIG_FSCACHE_HISTOGRAM=y + +then it will gather certain statistics and display them through a number of +proc files. + + (*) /proc/fs/fscache/stats + + This shows counts of a number of events that can happen in FS-Cache: + + CLASS EVENT MEANING + ======= ======= ======================================================= + Cookies idx=N Number of index cookies allocated + dat=N Number of data storage cookies allocated + spc=N Number of special cookies allocated + Objects alc=N Number of objects allocated + nal=N Number of object allocation failures + avl=N Number of objects that reached the available state + ded=N Number of objects that reached the dead state + ChkAux non=N Number of objects that didn't have a coherency check + ok=N Number of objects that passed a coherency check + upd=N Number of objects that needed a coherency data update + obs=N Number of objects that were declared obsolete + Pages mrk=N Number of pages marked as being cached + unc=N Number of uncache page requests seen + Acquire n=N Number of acquire cookie requests seen + nul=N Number of acq reqs given a NULL parent + noc=N Number of acq reqs rejected due to no cache available + ok=N Number of acq reqs succeeded + nbf=N Number of acq reqs rejected due to error + oom=N Number of acq reqs failed on ENOMEM + Lookups n=N Number of lookup calls made on cache backends + neg=N Number of negative lookups made + pos=N Number of positive lookups made + crt=N Number of objects created by lookup + Updates n=N Number of update cookie requests seen + nul=N Number of upd reqs given a NULL parent + run=N Number of upd reqs granted CPU time + Relinqs n=N Number of relinquish cookie requests seen + nul=N Number of rlq reqs given a NULL parent + wcr=N Number of rlq reqs waited on completion of creation + AttrChg n=N Number of attribute changed requests seen + ok=N Number of attr changed requests queued + nbf=N Number of attr changed rejected -ENOBUFS + oom=N Number of attr changed failed -ENOMEM + run=N Number of attr changed ops given CPU time + Allocs n=N Number of allocation requests seen + ok=N Number of successful alloc reqs + wt=N Number of alloc reqs that waited on lookup completion + nbf=N Number of alloc reqs rejected -ENOBUFS + ops=N Number of alloc reqs submitted + owt=N Number of alloc reqs waited for CPU time + Retrvls n=N Number of retrieval (read) requests seen + ok=N Number of successful retr reqs + wt=N Number of retr reqs that waited on lookup completion + nod=N Number of retr reqs returned -ENODATA + nbf=N Number of retr reqs rejected -ENOBUFS + int=N Number of retr reqs aborted -ERESTARTSYS + oom=N Number of retr reqs failed -ENOMEM + ops=N Number of retr reqs submitted + owt=N Number of retr reqs waited for CPU time + Stores n=N Number of storage (write) requests seen + ok=N Number of successful store reqs + agn=N Number of store reqs on a page already pending storage + nbf=N Number of store reqs rejected -ENOBUFS + oom=N Number of store reqs failed -ENOMEM + ops=N Number of store reqs submitted + run=N Number of store reqs granted CPU time + Ops pend=N Number of times async ops added to pending queues + run=N Number of times async ops given CPU time + enq=N Number of times async ops queued for processing + dfr=N Number of async ops queued for deferred release + rel=N Number of async ops released + gc=N Number of deferred-release async ops garbage collected + + + (*) /proc/fs/fscache/histogram + + cat /proc/fs/fscache/histogram + JIFS SECS OBJ INST OP RUNS OBJ RUNS RETRV DLY RETRIEVLS + ===== ===== ========= ========= ========= ========= ========= + + This shows the breakdown of the number of times each amount of time + between 0 jiffies and HZ-1 jiffies a variety of tasks took to run. The + columns are as follows: + + COLUMN TIME MEASUREMENT + ======= ======================================================= + OBJ INST Length of time to instantiate an object + OP RUNS Length of time a call to process an operation took + OBJ RUNS Length of time a call to process an object event took + RETRV DLY Time between an requesting a read and lookup completing + RETRIEVLS Time between beginning and end of a retrieval + + Each row shows the number of events that took a particular range of times. + Each step is 1 jiffy in size. The JIFS column indicates the particular + jiffy range covered, and the SECS field the equivalent number of seconds. + + +========= +DEBUGGING +========= + +If CONFIG_FSCACHE_DEBUG is enabled, the FS-Cache facility can have runtime +debugging enabled by adjusting the value in: + + /sys/module/fscache/parameters/debug + +This is a bitmask of debugging streams to enable: + + BIT VALUE STREAM POINT + ======= ======= =============================== ======================= + 0 1 Cache management Function entry trace + 1 2 Function exit trace + 2 4 General + 3 8 Cookie management Function entry trace + 4 16 Function exit trace + 5 32 General + 6 64 Page handling Function entry trace + 7 128 Function exit trace + 8 256 General + 9 512 Operation management Function entry trace + 10 1024 Function exit trace + 11 2048 General + +The appropriate set of values should be OR'd together and the result written to +the control file. For example: + + echo $((1|8|64)) >/sys/module/fscache/parameters/debug + +will turn on all function entry debugging. diff --git a/trunk/Documentation/filesystems/caching/netfs-api.txt b/trunk/Documentation/filesystems/caching/netfs-api.txt new file mode 100644 index 000000000000..4db125b3a5c6 --- /dev/null +++ b/trunk/Documentation/filesystems/caching/netfs-api.txt @@ -0,0 +1,778 @@ + =============================== + FS-CACHE NETWORK FILESYSTEM API + =============================== + +There's an API by which a network filesystem can make use of the FS-Cache +facilities. This is based around a number of principles: + + (1) Caches can store a number of different object types. There are two main + object types: indices and files. The first is a special type used by + FS-Cache to make finding objects faster and to make retiring of groups of + objects easier. + + (2) Every index, file or other object is represented by a cookie. This cookie + may or may not have anything associated with it, but the netfs doesn't + need to care. + + (3) Barring the top-level index (one entry per cached netfs), the index + hierarchy for each netfs is structured according the whim of the netfs. + +This API is declared in . + +This document contains the following sections: + + (1) Network filesystem definition + (2) Index definition + (3) Object definition + (4) Network filesystem (un)registration + (5) Cache tag lookup + (6) Index registration + (7) Data file registration + (8) Miscellaneous object registration + (9) Setting the data file size + (10) Page alloc/read/write + (11) Page uncaching + (12) Index and data file update + (13) Miscellaneous cookie operations + (14) Cookie unregistration + (15) Index and data file invalidation + (16) FS-Cache specific page flags. + + +============================= +NETWORK FILESYSTEM DEFINITION +============================= + +FS-Cache needs a description of the network filesystem. This is specified +using a record of the following structure: + + struct fscache_netfs { + uint32_t version; + const char *name; + struct fscache_cookie *primary_index; + ... + }; + +This first two fields should be filled in before registration, and the third +will be filled in by the registration function; any other fields should just be +ignored and are for internal use only. + +The fields are: + + (1) The name of the netfs (used as the key in the toplevel index). + + (2) The version of the netfs (if the name matches but the version doesn't, the + entire in-cache hierarchy for this netfs will be scrapped and begun + afresh). + + (3) The cookie representing the primary index will be allocated according to + another parameter passed into the registration function. + +For example, kAFS (linux/fs/afs/) uses the following definitions to describe +itself: + + struct fscache_netfs afs_cache_netfs = { + .version = 0, + .name = "afs", + }; + + +================ +INDEX DEFINITION +================ + +Indices are used for two purposes: + + (1) To aid the finding of a file based on a series of keys (such as AFS's + "cell", "volume ID", "vnode ID"). + + (2) To make it easier to discard a subset of all the files cached based around + a particular key - for instance to mirror the removal of an AFS volume. + +However, since it's unlikely that any two netfs's are going to want to define +their index hierarchies in quite the same way, FS-Cache tries to impose as few +restraints as possible on how an index is structured and where it is placed in +the tree. The netfs can even mix indices and data files at the same level, but +it's not recommended. + +Each index entry consists of a key of indeterminate length plus some auxilliary +data, also of indeterminate length. + +There are some limits on indices: + + (1) Any index containing non-index objects should be restricted to a single + cache. Any such objects created within an index will be created in the + first cache only. The cache in which an index is created can be + controlled by cache tags (see below). + + (2) The entry data must be atomically journallable, so it is limited to about + 400 bytes at present. At least 400 bytes will be available. + + (3) The depth of the index tree should be judged with care as the search + function is recursive. Too many layers will run the kernel out of stack. + + +================= +OBJECT DEFINITION +================= + +To define an object, a structure of the following type should be filled out: + + struct fscache_cookie_def + { + uint8_t name[16]; + uint8_t type; + + struct fscache_cache_tag *(*select_cache)( + const void *parent_netfs_data, + const void *cookie_netfs_data); + + uint16_t (*get_key)(const void *cookie_netfs_data, + void *buffer, + uint16_t bufmax); + + void (*get_attr)(const void *cookie_netfs_data, + uint64_t *size); + + uint16_t (*get_aux)(const void *cookie_netfs_data, + void *buffer, + uint16_t bufmax); + + enum fscache_checkaux (*check_aux)(void *cookie_netfs_data, + const void *data, + uint16_t datalen); + + void (*get_context)(void *cookie_netfs_data, void *context); + + void (*put_context)(void *cookie_netfs_data, void *context); + + void (*mark_pages_cached)(void *cookie_netfs_data, + struct address_space *mapping, + struct pagevec *cached_pvec); + + void (*now_uncached)(void *cookie_netfs_data); + }; + +This has the following fields: + + (1) The type of the object [mandatory]. + + This is one of the following values: + + (*) FSCACHE_COOKIE_TYPE_INDEX + + This defines an index, which is a special FS-Cache type. + + (*) FSCACHE_COOKIE_TYPE_DATAFILE + + This defines an ordinary data file. + + (*) Any other value between 2 and 255 + + This defines an extraordinary object such as an XATTR. + + (2) The name of the object type (NUL terminated unless all 16 chars are used) + [optional]. + + (3) A function to select the cache in which to store an index [optional]. + + This function is invoked when an index needs to be instantiated in a cache + during the instantiation of a non-index object. Only the immediate index + parent for the non-index object will be queried. Any indices above that + in the hierarchy may be stored in multiple caches. This function does not + need to be supplied for any non-index object or any index that will only + have index children. + + If this function is not supplied or if it returns NULL then the first + cache in the parent's list will be chosed, or failing that, the first + cache in the master list. + + (4) A function to retrieve an object's key from the netfs [mandatory]. + + This function will be called with the netfs data that was passed to the + cookie acquisition function and the maximum length of key data that it may + provide. It should write the required key data into the given buffer and + return the quantity it wrote. + + (5) A function to retrieve attribute data from the netfs [optional]. + + This function will be called with the netfs data that was passed to the + cookie acquisition function. It should return the size of the file if + this is a data file. The size may be used to govern how much cache must + be reserved for this file in the cache. + + If the function is absent, a file size of 0 is assumed. + + (6) A function to retrieve auxilliary data from the netfs [optional]. + + This function will be called with the netfs data that was passed to the + cookie acquisition function and the maximum length of auxilliary data that + it may provide. It should write the auxilliary data into the given buffer + and return the quantity it wrote. + + If this function is absent, the auxilliary data length will be set to 0. + + The length of the auxilliary data buffer may be dependent on the key + length. A netfs mustn't rely on being able to provide more than 400 bytes + for both. + + (7) A function to check the auxilliary data [optional]. + + This function will be called to check that a match found in the cache for + this object is valid. For instance with AFS it could check the auxilliary + data against the data version number returned by the server to determine + whether the index entry in a cache is still valid. + + If this function is absent, it will be assumed that matching objects in a + cache are always valid. + + If present, the function should return one of the following values: + + (*) FSCACHE_CHECKAUX_OKAY - the entry is okay as is + (*) FSCACHE_CHECKAUX_NEEDS_UPDATE - the entry requires update + (*) FSCACHE_CHECKAUX_OBSOLETE - the entry should be deleted + + This function can also be used to extract data from the auxilliary data in + the cache and copy it into the netfs's structures. + + (8) A pair of functions to manage contexts for the completion callback + [optional]. + + The cache read/write functions are passed a context which is then passed + to the I/O completion callback function. To ensure this context remains + valid until after the I/O completion is called, two functions may be + provided: one to get an extra reference on the context, and one to drop a + reference to it. + + If the context is not used or is a type of object that won't go out of + scope, then these functions are not required. These functions are not + required for indices as indices may not contain data. These functions may + be called in interrupt context and so may not sleep. + + (9) A function to mark a page as retaining cache metadata [optional]. + + This is called by the cache to indicate that it is retaining in-memory + information for this page and that the netfs should uncache the page when + it has finished. This does not indicate whether there's data on the disk + or not. Note that several pages at once may be presented for marking. + + The PG_fscache bit is set on the pages before this function would be + called, so the function need not be provided if this is sufficient. + + This function is not required for indices as they're not permitted data. + +(10) A function to unmark all the pages retaining cache metadata [mandatory]. + + This is called by FS-Cache to indicate that a backing store is being + unbound from a cookie and that all the marks on the pages should be + cleared to prevent confusion. Note that the cache will have torn down all + its tracking information so that the pages don't need to be explicitly + uncached. + + This function is not required for indices as they're not permitted data. + + +=================================== +NETWORK FILESYSTEM (UN)REGISTRATION +=================================== + +The first step is to declare the network filesystem to the cache. This also +involves specifying the layout of the primary index (for AFS, this would be the +"cell" level). + +The registration function is: + + int fscache_register_netfs(struct fscache_netfs *netfs); + +It just takes a pointer to the netfs definition. It returns 0 or an error as +appropriate. + +For kAFS, registration is done as follows: + + ret = fscache_register_netfs(&afs_cache_netfs); + +The last step is, of course, unregistration: + + void fscache_unregister_netfs(struct fscache_netfs *netfs); + + +================ +CACHE TAG LOOKUP +================ + +FS-Cache permits the use of more than one cache. To permit particular index +subtrees to be bound to particular caches, the second step is to look up cache +representation tags. This step is optional; it can be left entirely up to +FS-Cache as to which cache should be used. The problem with doing that is that +FS-Cache will always pick the first cache that was registered. + +To get the representation for a named tag: + + struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name); + +This takes a text string as the name and returns a representation of a tag. It +will never return an error. It may return a dummy tag, however, if it runs out +of memory; this will inhibit caching with this tag. + +Any representation so obtained must be released by passing it to this function: + + void fscache_release_cache_tag(struct fscache_cache_tag *tag); + +The tag will be retrieved by FS-Cache when it calls the object definition +operation select_cache(). + + +================== +INDEX REGISTRATION +================== + +The third step is to inform FS-Cache about part of an index hierarchy that can +be used to locate files. This is done by requesting a cookie for each index in +the path to the file: + + struct fscache_cookie * + fscache_acquire_cookie(struct fscache_cookie *parent, + const struct fscache_object_def *def, + void *netfs_data); + +This function creates an index entry in the index represented by parent, +filling in the index entry by calling the operations pointed to by def. + +Note that this function never returns an error - all errors are handled +internally. It may, however, return NULL to indicate no cookie. It is quite +acceptable to pass this token back to this function as the parent to another +acquisition (or even to the relinquish cookie, read page and write page +functions - see below). + +Note also that no indices are actually created in a cache until a non-index +object needs to be created somewhere down the hierarchy. Furthermore, an index +may be created in several different caches independently at different times. +This is all handled transparently, and the netfs doesn't see any of it. + +For example, with AFS, a cell would be added to the primary index. This index +entry would have a dependent inode containing a volume location index for the +volume mappings within this cell: + + cell->cache = + fscache_acquire_cookie(afs_cache_netfs.primary_index, + &afs_cell_cache_index_def, + cell); + +Then when a volume location was accessed, it would be entered into the cell's +index and an inode would be allocated that acts as a volume type and hash chain +combination: + + vlocation->cache = + fscache_acquire_cookie(cell->cache, + &afs_vlocation_cache_index_def, + vlocation); + +And then a particular flavour of volume (R/O for example) could be added to +that index, creating another index for vnodes (AFS inode equivalents): + + volume->cache = + fscache_acquire_cookie(vlocation->cache, + &afs_volume_cache_index_def, + volume); + + +====================== +DATA FILE REGISTRATION +====================== + +The fourth step is to request a data file be created in the cache. This is +identical to index cookie acquisition. The only difference is that the type in +the object definition should be something other than index type. + + vnode->cache = + fscache_acquire_cookie(volume->cache, + &afs_vnode_cache_object_def, + vnode); + + +================================= +MISCELLANEOUS OBJECT REGISTRATION +================================= + +An optional step is to request an object of miscellaneous type be created in +the cache. This is almost identical to index cookie acquisition. The only +difference is that the type in the object definition should be something other +than index type. Whilst the parent object could be an index, it's more likely +it would be some other type of object such as a data file. + + xattr->cache = + fscache_acquire_cookie(vnode->cache, + &afs_xattr_cache_object_def, + xattr); + +Miscellaneous objects might be used to store extended attributes or directory +entries for example. + + +========================== +SETTING THE DATA FILE SIZE +========================== + +The fifth step is to set the physical attributes of the file, such as its size. +This doesn't automatically reserve any space in the cache, but permits the +cache to adjust its metadata for data tracking appropriately: + + int fscache_attr_changed(struct fscache_cookie *cookie); + +The cache will return -ENOBUFS if there is no backing cache or if there is no +space to allocate any extra metadata required in the cache. The attributes +will be accessed with the get_attr() cookie definition operation. + +Note that attempts to read or write data pages in the cache over this size may +be rebuffed with -ENOBUFS. + +This operation schedules an attribute adjustment to happen asynchronously at +some point in the future, and as such, it may happen after the function returns +to the caller. The attribute adjustment excludes read and write operations. + + +===================== +PAGE READ/ALLOC/WRITE +===================== + +And the sixth step is to store and retrieve pages in the cache. There are +three functions that are used to do this. + +Note: + + (1) A page should not be re-read or re-allocated without uncaching it first. + + (2) A read or allocated page must be uncached when the netfs page is released + from the pagecache. + + (3) A page should only be written to the cache if previous read or allocated. + +This permits the cache to maintain its page tracking in proper order. + + +PAGE READ +--------- + +Firstly, the netfs should ask FS-Cache to examine the caches and read the +contents cached for a particular page of a particular file if present, or else +allocate space to store the contents if not: + + typedef + void (*fscache_rw_complete_t)(struct page *page, + void *context, + int error); + + int fscache_read_or_alloc_page(struct fscache_cookie *cookie, + struct page *page, + fscache_rw_complete_t end_io_func, + void *context, + gfp_t gfp); + +The cookie argument must specify a cookie for an object that isn't an index, +the page specified will have the data loaded into it (and is also used to +specify the page number), and the gfp argument is used to control how any +memory allocations made are satisfied. + +If the cookie indicates the inode is not cached: + + (1) The function will return -ENOBUFS. + +Else if there's a copy of the page resident in the cache: + + (1) The mark_pages_cached() cookie operation will be called on that page. + + (2) The function will submit a request to read the data from the cache's + backing device directly into the page specified. + + (3) The function will return 0. + + (4) When the read is complete, end_io_func() will be invoked with: + + (*) The netfs data supplied when the cookie was created. + + (*) The page descriptor. + + (*) The context argument passed to the above function. This will be + maintained with the get_context/put_context functions mentioned above. + + (*) An argument that's 0 on success or negative for an error code. + + If an error occurs, it should be assumed that the page contains no usable + data. + + end_io_func() will be called in process context if the read is results in + an error, but it might be called in interrupt context if the read is + successful. + +Otherwise, if there's not a copy available in cache, but the cache may be able +to store the page: + + (1) The mark_pages_cached() cookie operation will be called on that page. + + (2) A block may be reserved in the cache and attached to the object at the + appropriate place. + + (3) The function will return -ENODATA. + +This function may also return -ENOMEM or -EINTR, in which case it won't have +read any data from the cache. + + +PAGE ALLOCATE +------------- + +Alternatively, if there's not expected to be any data in the cache for a page +because the file has been extended, a block can simply be allocated instead: + + int fscache_alloc_page(struct fscache_cookie *cookie, + struct page *page, + gfp_t gfp); + +This is similar to the fscache_read_or_alloc_page() function, except that it +never reads from the cache. It will return 0 if a block has been allocated, +rather than -ENODATA as the other would. One or the other must be performed +before writing to the cache. + +The mark_pages_cached() cookie operation will be called on the page if +successful. + + +PAGE WRITE +---------- + +Secondly, if the netfs changes the contents of the page (either due to an +initial download or if a user performs a write), then the page should be +written back to the cache: + + int fscache_write_page(struct fscache_cookie *cookie, + struct page *page, + gfp_t gfp); + +The cookie argument must specify a data file cookie, the page specified should +contain the data to be written (and is also used to specify the page number), +and the gfp argument is used to control how any memory allocations made are +satisfied. + +The page must have first been read or allocated successfully and must not have +been uncached before writing is performed. + +If the cookie indicates the inode is not cached then: + + (1) The function will return -ENOBUFS. + +Else if space can be allocated in the cache to hold this page: + + (1) PG_fscache_write will be set on the page. + + (2) The function will submit a request to write the data to cache's backing + device directly from the page specified. + + (3) The function will return 0. + + (4) When the write is complete PG_fscache_write is cleared on the page and + anyone waiting for that bit will be woken up. + +Else if there's no space available in the cache, -ENOBUFS will be returned. It +is also possible for the PG_fscache_write bit to be cleared when no write took +place if unforeseen circumstances arose (such as a disk error). + +Writing takes place asynchronously. + + +MULTIPLE PAGE READ +------------------ + +A facility is provided to read several pages at once, as requested by the +readpages() address space operation: + + int fscache_read_or_alloc_pages(struct fscache_cookie *cookie, + struct address_space *mapping, + struct list_head *pages, + int *nr_pages, + fscache_rw_complete_t end_io_func, + void *context, + gfp_t gfp); + +This works in a similar way to fscache_read_or_alloc_page(), except: + + (1) Any page it can retrieve data for is removed from pages and nr_pages and + dispatched for reading to the disk. Reads of adjacent pages on disk may + be merged for greater efficiency. + + (2) The mark_pages_cached() cookie operation will be called on several pages + at once if they're being read or allocated. + + (3) If there was an general error, then that error will be returned. + + Else if some pages couldn't be allocated or read, then -ENOBUFS will be + returned. + + Else if some pages couldn't be read but were allocated, then -ENODATA will + be returned. + + Otherwise, if all pages had reads dispatched, then 0 will be returned, the + list will be empty and *nr_pages will be 0. + + (4) end_io_func will be called once for each page being read as the reads + complete. It will be called in process context if error != 0, but it may + be called in interrupt context if there is no error. + +Note that a return of -ENODATA, -ENOBUFS or any other error does not preclude +some of the pages being read and some being allocated. Those pages will have +been marked appropriately and will need uncaching. + + +============== +PAGE UNCACHING +============== + +To uncache a page, this function should be called: + + void fscache_uncache_page(struct fscache_cookie *cookie, + struct page *page); + +This function permits the cache to release any in-memory representation it +might be holding for this netfs page. This function must be called once for +each page on which the read or write page functions above have been called to +make sure the cache's in-memory tracking information gets torn down. + +Note that pages can't be explicitly deleted from the a data file. The whole +data file must be retired (see the relinquish cookie function below). + +Furthermore, note that this does not cancel the asynchronous read or write +operation started by the read/alloc and write functions, so the page +invalidation and release functions must use: + + bool fscache_check_page_write(struct fscache_cookie *cookie, + struct page *page); + +to see if a page is being written to the cache, and: + + void fscache_wait_on_page_write(struct fscache_cookie *cookie, + struct page *page); + +to wait for it to finish if it is. + + +========================== +INDEX AND DATA FILE UPDATE +========================== + +To request an update of the index data for an index or other object, the +following function should be called: + + void fscache_update_cookie(struct fscache_cookie *cookie); + +This function will refer back to the netfs_data pointer stored in the cookie by +the acquisition function to obtain the data to write into each revised index +entry. The update method in the parent index definition will be called to +transfer the data. + +Note that partial updates may happen automatically at other times, such as when +data blocks are added to a data file object. + + +=============================== +MISCELLANEOUS COOKIE OPERATIONS +=============================== + +There are a number of operations that can be used to control cookies: + + (*) Cookie pinning: + + int fscache_pin_cookie(struct fscache_cookie *cookie); + void fscache_unpin_cookie(struct fscache_cookie *cookie); + + These operations permit data cookies to be pinned into the cache and to + have the pinning removed. They are not permitted on index cookies. + + The pinning function will return 0 if successful, -ENOBUFS in the cookie + isn't backed by a cache, -EOPNOTSUPP if the cache doesn't support pinning, + -ENOSPC if there isn't enough space to honour the operation, -ENOMEM or + -EIO if there's any other problem. + + (*) Data space reservation: + + int fscache_reserve_space(struct fscache_cookie *cookie, loff_t size); + + This permits a netfs to request cache space be reserved to store up to the + given amount of a file. It is permitted to ask for more than the current + size of the file to allow for future file expansion. + + If size is given as zero then the reservation will be cancelled. + + The function will return 0 if successful, -ENOBUFS in the cookie isn't + backed by a cache, -EOPNOTSUPP if the cache doesn't support reservations, + -ENOSPC if there isn't enough space to honour the operation, -ENOMEM or + -EIO if there's any other problem. + + Note that this doesn't pin an object in a cache; it can still be culled to + make space if it's not in use. + + +===================== +COOKIE UNREGISTRATION +===================== + +To get rid of a cookie, this function should be called. + + void fscache_relinquish_cookie(struct fscache_cookie *cookie, + int retire); + +If retire is non-zero, then the object will be marked for recycling, and all +copies of it will be removed from all active caches in which it is present. +Not only that but all child objects will also be retired. + +If retire is zero, then the object may be available again when next the +acquisition function is called. Retirement here will overrule the pinning on a +cookie. + +One very important note - relinquish must NOT be called for a cookie unless all +the cookies for "child" indices, objects and pages have been relinquished +first. + + +================================ +INDEX AND DATA FILE INVALIDATION +================================ + +There is no direct way to invalidate an index subtree or a data file. To do +this, the caller should relinquish and retire the cookie they have, and then +acquire a new one. + + +=========================== +FS-CACHE SPECIFIC PAGE FLAG +=========================== + +FS-Cache makes use of a page flag, PG_private_2, for its own purpose. This is +given the alternative name PG_fscache. + +PG_fscache is used to indicate that the page is known by the cache, and that +the cache must be informed if the page is going to go away. It's an indication +to the netfs that the cache has an interest in this page, where an interest may +be a pointer to it, resources allocated or reserved for it, or I/O in progress +upon it. + +The netfs can use this information in methods such as releasepage() to +determine whether it needs to uncache a page or update it. + +Furthermore, if this bit is set, releasepage() and invalidatepage() operations +will be called on a page to get rid of it, even if PG_private is not set. This +allows caching to attempted on a page before read_cache_pages() to be called +after fscache_read_or_alloc_pages() as the former will try and release pages it +was given under certain circumstances. + +This bit does not overlap with such as PG_private. This means that FS-Cache +can be used with a filesystem that uses the block buffering code. + +There are a number of operations defined on this flag: + + int PageFsCache(struct page *page); + void SetPageFsCache(struct page *page) + void ClearPageFsCache(struct page *page) + int TestSetPageFsCache(struct page *page) + int TestClearPageFsCache(struct page *page) + +These functions are bit test, bit set, bit clear, bit test and set and bit +test and clear operations on PG_fscache. diff --git a/trunk/Documentation/filesystems/caching/object.txt b/trunk/Documentation/filesystems/caching/object.txt new file mode 100644 index 000000000000..e8b0a35d8fe5 --- /dev/null +++ b/trunk/Documentation/filesystems/caching/object.txt @@ -0,0 +1,313 @@ + ==================================================== + IN-KERNEL CACHE OBJECT REPRESENTATION AND MANAGEMENT + ==================================================== + +By: David Howells + +Contents: + + (*) Representation + + (*) Object management state machine. + + - Provision of cpu time. + - Locking simplification. + + (*) The set of states. + + (*) The set of events. + + +============== +REPRESENTATION +============== + +FS-Cache maintains an in-kernel representation of each object that a netfs is +currently interested in. Such objects are represented by the fscache_cookie +struct and are referred to as cookies. + +FS-Cache also maintains a separate in-kernel representation of the objects that +a cache backend is currently actively caching. Such objects are represented by +the fscache_object struct. The cache backends allocate these upon request, and +are expected to embed them in their own representations. These are referred to +as objects. + +There is a 1:N relationship between cookies and objects. A cookie may be +represented by multiple objects - an index may exist in more than one cache - +or even by no objects (it may not be cached). + +Furthermore, both cookies and objects are hierarchical. The two hierarchies +correspond, but the cookies tree is a superset of the union of the object trees +of multiple caches: + + NETFS INDEX TREE : CACHE 1 : CACHE 2 + : : + : +-----------+ : + +----------->| IObject | : + +-----------+ | : +-----------+ : + | ICookie |-------+ : | : + +-----------+ | : | : +-----------+ + | +------------------------------>| IObject | + | : | : +-----------+ + | : V : | + | : +-----------+ : | + V +----------->| IObject | : | + +-----------+ | : +-----------+ : | + | ICookie |-------+ : | : V + +-----------+ | : | : +-----------+ + | +------------------------------>| IObject | + +-----+-----+ : | : +-----------+ + | | : | : | + V | : V : | + +-----------+ | : +-----------+ : | + | ICookie |------------------------->| IObject | : | + +-----------+ | : +-----------+ : | + | V : | : V + | +-----------+ : | : +-----------+ + | | ICookie |-------------------------------->| IObject | + | +-----------+ : | : +-----------+ + V | : V : | + +-----------+ | : +-----------+ : | + | DCookie |------------------------->| DObject | : | + +-----------+ | : +-----------+ : | + | : : | + +-------+-------+ : : | + | | : : | + V V : : V + +-----------+ +-----------+ : : +-----------+ + | DCookie | | DCookie |------------------------>| DObject | + +-----------+ +-----------+ : : +-----------+ + : : + +In the above illustration, ICookie and IObject represent indices and DCookie +and DObject represent data storage objects. Indices may have representation in +multiple caches, but currently, non-index objects may not. Objects of any type +may also be entirely unrepresented. + +As far as the netfs API goes, the netfs is only actually permitted to see +pointers to the cookies. The cookies themselves and any objects attached to +those cookies are hidden from it. + + +=============================== +OBJECT MANAGEMENT STATE MACHINE +=============================== + +Within FS-Cache, each active object is managed by its own individual state +machine. The state for an object is kept in the fscache_object struct, in +object->state. A cookie may point to a set of objects that are in different +states. + +Each state has an action associated with it that is invoked when the machine +wakes up in that state. There are four logical sets of states: + + (1) Preparation: states that wait for the parent objects to become ready. The + representations are hierarchical, and it is expected that an object must + be created or accessed with respect to its parent object. + + (2) Initialisation: states that perform lookups in the cache and validate + what's found and that create on disk any missing metadata. + + (3) Normal running: states that allow netfs operations on objects to proceed + and that update the state of objects. + + (4) Termination: states that detach objects from their netfs cookies, that + delete objects from disk, that handle disk and system errors and that free + up in-memory resources. + + +In most cases, transitioning between states is in response to signalled events. +When a state has finished processing, it will usually set the mask of events in +which it is interested (object->event_mask) and relinquish the worker thread. +Then when an event is raised (by calling fscache_raise_event()), if the event +is not masked, the object will be queued for processing (by calling +fscache_enqueue_object()). + + +PROVISION OF CPU TIME +--------------------- + +The work to be done by the various states is given CPU time by the threads of +the slow work facility (see Documentation/slow-work.txt). This is used in +preference to the workqueue facility because: + + (1) Threads may be completely occupied for very long periods of time by a + particular work item. These state actions may be doing sequences of + synchronous, journalled disk accesses (lookup, mkdir, create, setxattr, + getxattr, truncate, unlink, rmdir, rename). + + (2) Threads may do little actual work, but may rather spend a lot of time + sleeping on I/O. This means that single-threaded and 1-per-CPU-threaded + workqueues don't necessarily have the right numbers of threads. + + +LOCKING SIMPLIFICATION +---------------------- + +Because only one worker thread may be operating on any particular object's +state machine at once, this simplifies the locking, particularly with respect +to disconnecting the netfs's representation of a cache object (fscache_cookie) +from the cache backend's representation (fscache_object) - which may be +requested from either end. + + +================= +THE SET OF STATES +================= + +The object state machine has a set of states that it can be in. There are +preparation states in which the object sets itself up and waits for its parent +object to transit to a state that allows access to its children: + + (1) State FSCACHE_OBJECT_INIT. + + Initialise the object and wait for the parent object to become active. In + the cache, it is expected that it will not be possible to look an object + up from the parent object, until that parent object itself has been looked + up. + +There are initialisation states in which the object sets itself up and accesses +disk for the object metadata: + + (2) State FSCACHE_OBJECT_LOOKING_UP. + + Look up the object on disk, using the parent as a starting point. + FS-Cache expects the cache backend to probe the cache to see whether this + object is represented there, and if it is, to see if it's valid (coherency + management). + + The cache should call fscache_object_lookup_negative() to indicate lookup + failure for whatever reason, and should call fscache_obtained_object() to + indicate success. + + At the completion of lookup, FS-Cache will let the netfs go ahead with + read operations, no matter whether the file is yet cached. If not yet + cached, read operations will be immediately rejected with ENODATA until + the first known page is uncached - as to that point there can be no data + to be read out of the cache for that file that isn't currently also held + in the pagecache. + + (3) State FSCACHE_OBJECT_CREATING. + + Create an object on disk, using the parent as a starting point. This + happens if the lookup failed to find the object, or if the object's + coherency data indicated what's on disk is out of date. In this state, + FS-Cache expects the cache to create + + The cache should call fscache_obtained_object() if creation completes + successfully, fscache_object_lookup_negative() otherwise. + + At the completion of creation, FS-Cache will start processing write + operations the netfs has queued for an object. If creation failed, the + write ops will be transparently discarded, and nothing recorded in the + cache. + +There are some normal running states in which the object spends its time +servicing netfs requests: + + (4) State FSCACHE_OBJECT_AVAILABLE. + + A transient state in which pending operations are started, child objects + are permitted to advance from FSCACHE_OBJECT_INIT state, and temporary + lookup data is freed. + + (5) State FSCACHE_OBJECT_ACTIVE. + + The normal running state. In this state, requests the netfs makes will be + passed on to the cache. + + (6) State FSCACHE_OBJECT_UPDATING. + + The state machine comes here to update the object in the cache from the + netfs's records. This involves updating the auxiliary data that is used + to maintain coherency. + +And there are terminal states in which an object cleans itself up, deallocates +memory and potentially deletes stuff from disk: + + (7) State FSCACHE_OBJECT_LC_DYING. + + The object comes here if it is dying because of a lookup or creation + error. This would be due to a disk error or system error of some sort. + Temporary data is cleaned up, and the parent is released. + + (8) State FSCACHE_OBJECT_DYING. + + The object comes here if it is dying due to an error, because its parent + cookie has been relinquished by the netfs or because the cache is being + withdrawn. + + Any child objects waiting on this one are given CPU time so that they too + can destroy themselves. This object waits for all its children to go away + before advancing to the next state. + + (9) State FSCACHE_OBJECT_ABORT_INIT. + + The object comes to this state if it was waiting on its parent in + FSCACHE_OBJECT_INIT, but its parent died. The object will destroy itself + so that the parent may proceed from the FSCACHE_OBJECT_DYING state. + +(10) State FSCACHE_OBJECT_RELEASING. +(11) State FSCACHE_OBJECT_RECYCLING. + + The object comes to one of these two states when dying once it is rid of + all its children, if it is dying because the netfs relinquished its + cookie. In the first state, the cached data is expected to persist, and + in the second it will be deleted. + +(12) State FSCACHE_OBJECT_WITHDRAWING. + + The object transits to this state if the cache decides it wants to + withdraw the object from service, perhaps to make space, but also due to + error or just because the whole cache is being withdrawn. + +(13) State FSCACHE_OBJECT_DEAD. + + The object transits to this state when the in-memory object record is + ready to be deleted. The object processor shouldn't ever see an object in + this state. + + +THE SET OF EVENTS +----------------- + +There are a number of events that can be raised to an object state machine: + + (*) FSCACHE_OBJECT_EV_UPDATE + + The netfs requested that an object be updated. The state machine will ask + the cache backend to update the object, and the cache backend will ask the + netfs for details of the change through its cookie definition ops. + + (*) FSCACHE_OBJECT_EV_CLEARED + + This is signalled in two circumstances: + + (a) when an object's last child object is dropped and + + (b) when the last operation outstanding on an object is completed. + + This is used to proceed from the dying state. + + (*) FSCACHE_OBJECT_EV_ERROR + + This is signalled when an I/O error occurs during the processing of some + object. + + (*) FSCACHE_OBJECT_EV_RELEASE + (*) FSCACHE_OBJECT_EV_RETIRE + + These are signalled when the netfs relinquishes a cookie it was using. + The event selected depends on whether the netfs asks for the backing + object to be retired (deleted) or retained. + + (*) FSCACHE_OBJECT_EV_WITHDRAW + + This is signalled when the cache backend wants to withdraw an object. + This means that the object will have to be detached from the netfs's + cookie. + +Because the withdrawing releasing/retiring events are all handled by the object +state machine, it doesn't matter if there's a collision with both ends trying +to sever the connection at the same time. The state machine can just pick +which one it wants to honour, and that effects the other. diff --git a/trunk/Documentation/filesystems/caching/operations.txt b/trunk/Documentation/filesystems/caching/operations.txt new file mode 100644 index 000000000000..b6b070c57cbf --- /dev/null +++ b/trunk/Documentation/filesystems/caching/operations.txt @@ -0,0 +1,213 @@ + ================================ + ASYNCHRONOUS OPERATIONS HANDLING + ================================ + +By: David Howells + +Contents: + + (*) Overview. + + (*) Operation record initialisation. + + (*) Parameters. + + (*) Procedure. + + (*) Asynchronous callback. + + +======== +OVERVIEW +======== + +FS-Cache has an asynchronous operations handling facility that it uses for its +data storage and retrieval routines. Its operations are represented by +fscache_operation structs, though these are usually embedded into some other +structure. + +This facility is available to and expected to be be used by the cache backends, +and FS-Cache will create operations and pass them off to the appropriate cache +backend for completion. + +To make use of this facility, should be #included. + + +=============================== +OPERATION RECORD INITIALISATION +=============================== + +An operation is recorded in an fscache_operation struct: + + struct fscache_operation { + union { + struct work_struct fast_work; + struct slow_work slow_work; + }; + unsigned long flags; + fscache_operation_processor_t processor; + ... + }; + +Someone wanting to issue an operation should allocate something with this +struct embedded in it. They should initialise it by calling: + + void fscache_operation_init(struct fscache_operation *op, + fscache_operation_release_t release); + +with the operation to be initialised and the release function to use. + +The op->flags parameter should be set to indicate the CPU time provision and +the exclusivity (see the Parameters section). + +The op->fast_work, op->slow_work and op->processor flags should be set as +appropriate for the CPU time provision (see the Parameters section). + +FSCACHE_OP_WAITING may be set in op->flags prior to each submission of the +operation and waited for afterwards. + + +========== +PARAMETERS +========== + +There are a number of parameters that can be set in the operation record's flag +parameter. There are three options for the provision of CPU time in these +operations: + + (1) The operation may be done synchronously (FSCACHE_OP_MYTHREAD). A thread + may decide it wants to handle an operation itself without deferring it to + another thread. + + This is, for example, used in read operations for calling readpages() on + the backing filesystem in CacheFiles. Although readpages() does an + asynchronous data fetch, the determination of whether pages exist is done + synchronously - and the netfs does not proceed until this has been + determined. + + If this option is to be used, FSCACHE_OP_WAITING must be set in op->flags + before submitting the operation, and the operating thread must wait for it + to be cleared before proceeding: + + wait_on_bit(&op->flags, FSCACHE_OP_WAITING, + fscache_wait_bit, TASK_UNINTERRUPTIBLE); + + + (2) The operation may be fast asynchronous (FSCACHE_OP_FAST), in which case it + will be given to keventd to process. Such an operation is not permitted + to sleep on I/O. + + This is, for example, used by CacheFiles to copy data from a backing fs + page to a netfs page after the backing fs has read the page in. + + If this option is used, op->fast_work and op->processor must be + initialised before submitting the operation: + + INIT_WORK(&op->fast_work, do_some_work); + + + (3) The operation may be slow asynchronous (FSCACHE_OP_SLOW), in which case it + will be given to the slow work facility to process. Such an operation is + permitted to sleep on I/O. + + This is, for example, used by FS-Cache to handle background writes of + pages that have just been fetched from a remote server. + + If this option is used, op->slow_work and op->processor must be + initialised before submitting the operation: + + fscache_operation_init_slow(op, processor) + + +Furthermore, operations may be one of two types: + + (1) Exclusive (FSCACHE_OP_EXCLUSIVE). Operations of this type may not run in + conjunction with any other operation on the object being operated upon. + + An example of this is the attribute change operation, in which the file + being written to may need truncation. + + (2) Shareable. Operations of this type may be running simultaneously. It's + up to the operation implementation to prevent interference between other + operations running at the same time. + + +========= +PROCEDURE +========= + +Operations are used through the following procedure: + + (1) The submitting thread must allocate the operation and initialise it + itself. Normally this would be part of a more specific structure with the + generic op embedded within. + + (2) The submitting thread must then submit the operation for processing using + one of the following two functions: + + int fscache_submit_op(struct fscache_object *object, + struct fscache_operation *op); + + int fscache_submit_exclusive_op(struct fscache_object *object, + struct fscache_operation *op); + + The first function should be used to submit non-exclusive ops and the + second to submit exclusive ones. The caller must still set the + FSCACHE_OP_EXCLUSIVE flag. + + If successful, both functions will assign the operation to the specified + object and return 0. -ENOBUFS will be returned if the object specified is + permanently unavailable. + + The operation manager will defer operations on an object that is still + undergoing lookup or creation. The operation will also be deferred if an + operation of conflicting exclusivity is in progress on the object. + + If the operation is asynchronous, the manager will retain a reference to + it, so the caller should put their reference to it by passing it to: + + void fscache_put_operation(struct fscache_operation *op); + + (3) If the submitting thread wants to do the work itself, and has marked the + operation with FSCACHE_OP_MYTHREAD, then it should monitor + FSCACHE_OP_WAITING as described above and check the state of the object if + necessary (the object might have died whilst the thread was waiting). + + When it has finished doing its processing, it should call + fscache_put_operation() on it. + + (4) The operation holds an effective lock upon the object, preventing other + exclusive ops conflicting until it is released. The operation can be + enqueued for further immediate asynchronous processing by adjusting the + CPU time provisioning option if necessary, eg: + + op->flags &= ~FSCACHE_OP_TYPE; + op->flags |= ~FSCACHE_OP_FAST; + + and calling: + + void fscache_enqueue_operation(struct fscache_operation *op) + + This can be used to allow other things to have use of the worker thread + pools. + + +===================== +ASYNCHRONOUS CALLBACK +===================== + +When used in asynchronous mode, the worker thread pool will invoke the +processor method with a pointer to the operation. This should then get at the +container struct by using container_of(): + + static void fscache_write_op(struct fscache_operation *_op) + { + struct fscache_storage *op = + container_of(_op, struct fscache_storage, op); + ... + } + +The caller holds a reference on the operation, and will invoke +fscache_put_operation() when the processor function returns. The processor +function is at liberty to call fscache_enqueue_operation() or to take extra +references. diff --git a/trunk/Documentation/filesystems/exofs.txt b/trunk/Documentation/filesystems/exofs.txt new file mode 100644 index 000000000000..0ced74c2f73c --- /dev/null +++ b/trunk/Documentation/filesystems/exofs.txt @@ -0,0 +1,176 @@ +=============================================================================== +WHAT IS EXOFS? +=============================================================================== + +exofs is a file system that uses an OSD and exports the API of a normal Linux +file system. Users access exofs like any other local file system, and exofs +will in turn issue commands to the local OSD initiator. + +OSD is a new T10 command set that views storage devices not as a large/flat +array of sectors but as a container of objects, each having a length, quota, +time attributes and more. Each object is addressed by a 64bit ID, and is +contained in a 64bit ID partition. Each object has associated attributes +attached to it, which are integral part of the object and provide metadata about +the object. The standard defines some common obligatory attributes, but user +attributes can be added as needed. + +=============================================================================== +ENVIRONMENT +=============================================================================== + +To use this file system, you need to have an object store to run it on. You +may download a target from: +http://open-osd.org + +See Documentation/scsi/osd.txt for how to setup a working osd environment. + +=============================================================================== +USAGE +=============================================================================== + +1. Download and compile exofs and open-osd initiator: + You need an external Kernel source tree or kernel headers from your + distribution. (anything based on 2.6.26 or later). + + a. download open-osd including exofs source using: + [parent-directory]$ git clone git://git.open-osd.org/open-osd.git + + b. Build the library module like this: + [parent-directory]$ make -C KSRC=$(KER_DIR) open-osd + + This will build both the open-osd initiator as well as the exofs kernel + module. Use whatever parameters you compiled your Kernel with and + $(KER_DIR) above pointing to the Kernel you compile against. See the file + open-osd/top-level-Makefile for an example. + +2. Get the OSD initiator and target set up properly, and login to the target. + See Documentation/scsi/osd.txt for farther instructions. Also see ./do-osd + for example script that does all these steps. + +3. Insmod the exofs.ko module: + [exofs]$ insmod exofs.ko + +4. Make sure the directory where you want to mount exists. If not, create it. + (For example, mkdir /mnt/exofs) + +5. At first run you will need to invoke the mkfs.exofs application + + As an example, this will create the file system on: + /dev/osd0 partition ID 65536 + + mkfs.exofs --pid=65536 --format /dev/osd0 + + The --format is optional if not specified no OSD_FORMAT will be + preformed and a clean file system will be created in the specified pid, + in the available space of the target. (Use --format=size_in_meg to limit + the total LUN space available) + + If pid already exist it will be deleted and a new one will be created in it's + place. Be careful. + + An exofs lives inside a single OSD partition. You can create multiple exofs + filesystems on the same device using multiple pids. + + (run mkfs.exofs without any parameters for usage help message) + +6. Mount the file system. + + For example, to mount /dev/osd0, partition ID 0x10000 on /mnt/exofs: + + mount -t exofs -o pid=65536 /dev/osd0 /mnt/exofs/ + +7. For reference (See do-exofs example script): + do-exofs start - an example of how to perform the above steps. + do-exofs stop - an example of how to unmount the file system. + do-exofs format - an example of how to format and mkfs a new exofs. + +8. Extra compilation flags (uncomment in fs/exofs/Kbuild): + CONFIG_EXOFS_DEBUG - for debug messages and extra checks. + +=============================================================================== +exofs mount options +=============================================================================== +Similar to any mount command: + mount -t exofs -o exofs_options /dev/osdX mount_exofs_directory + +Where: + -t exofs: specifies the exofs file system + + /dev/osdX: X is a decimal number. /dev/osdX was created after a successful + login into an OSD target. + + mount_exofs_directory: The directory to mount the file system on + + exofs specific options: Options are separated by commas (,) + pid= - The partition number to mount/create as + container of the filesystem. + This option is mandatory + to= - Timeout in ticks for a single command + default is (60 * HZ) [for debugging only] + +=============================================================================== +DESIGN +=============================================================================== + +* The file system control block (AKA on-disk superblock) resides in an object + with a special ID (defined in common.h). + Information included in the file system control block is used to fill the + in-memory superblock structure at mount time. This object is created before + the file system is used by mkexofs.c It contains information such as: + - The file system's magic number + - The next inode number to be allocated + +* Each file resides in its own object and contains the data (and it will be + possible to extend the file over multiple objects, though this has not been + implemented yet). + +* A directory is treated as a file, and essentially contains a list of pairs for files that are found in that directory. The object + IDs correspond to the files' inode numbers and will be allocated according to + a bitmap (stored in a separate object). Now they are allocated using a + counter. + +* Each file's control block (AKA on-disk inode) is stored in its object's + attributes. This applies to both regular files and other types (directories, + device files, symlinks, etc.). + +* Credentials are generated per object (inode and superblock) when they is + created in memory (read off disk or created). The credential works for all + operations and is used as long as the object remains in memory. + +* Async OSD operations are used whenever possible, but the target may execute + them out of order. The operations that concern us are create, delete, + readpage, writepage, update_inode, and truncate. The following pairs of + operations should execute in the order written, and we need to prevent them + from executing in reverse order: + - The following are handled with the OBJ_CREATED and OBJ_2BCREATED + flags. OBJ_CREATED is set when we know the object exists on the OSD - + in create's callback function, and when we successfully do a read_inode. + OBJ_2BCREATED is set in the beginning of the create function, so we + know that we should wait. + - create/delete: delete should wait until the object is created + on the OSD. + - create/readpage: readpage should be able to return a page + full of zeroes in this case. If there was a write already + en-route (i.e. create, writepage, readpage) then the page + would be locked, and so it would really be the same as + create/writepage. + - create/writepage: if writepage is called for a sync write, it + should wait until the object is created on the OSD. + Otherwise, it should just return. + - create/truncate: truncate should wait until the object is + created on the OSD. + - create/update_inode: update_inode should wait until the + object is created on the OSD. + - Handled by VFS locks: + - readpage/delete: shouldn't happen because of page lock. + - writepage/delete: shouldn't happen because of page lock. + - readpage/writepage: shouldn't happen because of page lock. + +=============================================================================== +LICENSE/COPYRIGHT +=============================================================================== +The exofs file system is based on ext2 v0.5b (distributed with the Linux kernel +version 2.6.10). All files include the original copyrights, and the license +is GPL version 2 (only version 2, as is true for the Linux kernel). The +Linux kernel can be downloaded from www.kernel.org. diff --git a/trunk/Documentation/filesystems/ext4.txt b/trunk/Documentation/filesystems/ext4.txt index cec829bc7291..97882df04865 100644 --- a/trunk/Documentation/filesystems/ext4.txt +++ b/trunk/Documentation/filesystems/ext4.txt @@ -85,7 +85,7 @@ Note: More extensive information for getting started with ext4 can be * extent format more robust in face of on-disk corruption due to magics, * internal redundancy in tree * improved file allocation (multi-block alloc) -* fix 32000 subdirectory limit +* lift 32000 subdirectory limit imposed by i_links_count[1] * nsec timestamps for mtime, atime, ctime, create time * inode version field on disk (NFSv4, Lustre) * reduced e2fsck time via uninit_bg feature @@ -100,6 +100,9 @@ Note: More extensive information for getting started with ext4 can be * efficent new ordered mode in JBD2 and ext4(avoid using buffer head to force the ordering) +[1] Filesystems with a block size of 1k may see a limit imposed by the +directory hash tree having a maximum depth of two. + 2.2 Candidate features for future inclusion * Online defrag (patches available but not well tested) @@ -180,8 +183,8 @@ commit=nrsec (*) Ext4 can be told to sync all its data and metadata performance. barrier=<0|1(*)> This enables/disables the use of write barriers in - the jbd code. barrier=0 disables, barrier=1 enables. - This also requires an IO stack which can support +barrier(*) the jbd code. barrier=0 disables, barrier=1 enables. +nobarrier This also requires an IO stack which can support barriers, and if jbd gets an error on a barrier write, it will disable again with a warning. Write barriers enforce proper on-disk ordering @@ -189,6 +192,9 @@ barrier=<0|1(*)> This enables/disables the use of write barriers in safe to use, at some performance penalty. If your disks are battery-backed in one way or another, disabling barriers may safely improve performance. + The mount options "barrier" and "nobarrier" can + also be used to enable or disable barriers, for + consistency with other ext4 mount options. inode_readahead=n This tuning parameter controls the maximum number of inode table blocks that ext4's inode @@ -310,6 +316,24 @@ journal_ioprio=prio The I/O priority (from 0 to 7, where 0 is the a slightly higher priority than the default I/O priority. +auto_da_alloc(*) Many broken applications don't use fsync() when +noauto_da_alloc replacing existing files via patterns such as + fd = open("foo.new")/write(fd,..)/close(fd)/ + rename("foo.new", "foo"), or worse yet, + fd = open("foo", O_TRUNC)/write(fd,..)/close(fd). + If auto_da_alloc is enabled, ext4 will detect + the replace-via-rename and replace-via-truncate + patterns and force that any delayed allocation + blocks are allocated such that at the next + journal commit, in the default data=ordered + mode, the data blocks of the new file are forced + to disk before the rename() operation is + commited. This provides roughly the same level + of guarantees as ext3, and avoids the + "zero-length" problem that can happen when a + system crashes before the delayed allocation + blocks are forced to disk. + Data Mode ========= There are 3 different data modes: diff --git a/trunk/Documentation/filesystems/proc.txt b/trunk/Documentation/filesystems/proc.txt index 830bad7cce0f..ce84cfc9eae0 100644 --- a/trunk/Documentation/filesystems/proc.txt +++ b/trunk/Documentation/filesystems/proc.txt @@ -5,6 +5,7 @@ Bodo Bauer 2.4.x update Jorge Nerin November 14 2000 +move /proc/sys Shen Feng April 1 2009 ------------------------------------------------------------------------------ Version 1.3 Kernel version 2.2.12 Kernel version 2.4.0-test11-pre4 @@ -26,25 +27,17 @@ Table of Contents 1.6 Parallel port info in /proc/parport 1.7 TTY info in /proc/tty 1.8 Miscellaneous kernel statistics in /proc/stat + 1.9 Ext4 file system parameters 2 Modifying System Parameters - 2.1 /proc/sys/fs - File system data - 2.2 /proc/sys/fs/binfmt_misc - Miscellaneous binary formats - 2.3 /proc/sys/kernel - general kernel parameters - 2.4 /proc/sys/vm - The virtual memory subsystem - 2.5 /proc/sys/dev - Device specific parameters - 2.6 /proc/sys/sunrpc - Remote procedure calls - 2.7 /proc/sys/net - Networking stuff - 2.8 /proc/sys/net/ipv4 - IPV4 settings - 2.9 Appletalk - 2.10 IPX - 2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem - 2.12 /proc//oom_adj - Adjust the oom-killer score - 2.13 /proc//oom_score - Display current oom-killer score - 2.14 /proc//io - Display the IO accounting fields - 2.15 /proc//coredump_filter - Core dump filtering settings - 2.16 /proc//mountinfo - Information about mounts - 2.17 /proc/sys/fs/epoll - Configuration options for the epoll interface + + 3 Per-Process Parameters + 3.1 /proc//oom_adj - Adjust the oom-killer score + 3.2 /proc//oom_score - Display current oom-killer score + 3.3 /proc//io - Display the IO accounting fields + 3.4 /proc//coredump_filter - Core dump filtering settings + 3.5 /proc//mountinfo - Information about mounts + ------------------------------------------------------------------------------ Preface @@ -940,27 +933,6 @@ Table 1-10: Files in /proc/fs/ext4/ File Content mb_groups details of multiblock allocator buddy cache of free blocks mb_history multiblock allocation history - stats controls whether the multiblock allocator should start - collecting statistics, which are shown during the unmount - group_prealloc the multiblock allocator will round up allocation - requests to a multiple of this tuning parameter if the - stripe size is not set in the ext4 superblock - max_to_scan The maximum number of extents the multiblock allocator - will search to find the best extent - min_to_scan The minimum number of extents the multiblock allocator - will search to find the best extent - order2_req Tuning parameter which controls the minimum size for - requests (as a power of 2) where the buddy cache is - used - stream_req Files which have fewer blocks than this tunable - parameter will have their blocks allocated out of a - block group specific preallocation pool, so that small - files are packed closely together. Each large file - will have its blocks allocated out of its own unique - preallocation pool. -inode_readahead Tuning parameter which controls the maximum number of - inode table blocks that ext4's inode table readahead - algorithm will pre-read into the buffer cache .............................................................................. @@ -1011,1021 +983,24 @@ review the kernel documentation in the directory /usr/src/linux/Documentation. This chapter is heavily based on the documentation included in the pre 2.2 kernels, and became part of it in version 2.2.1 of the Linux kernel. -2.1 /proc/sys/fs - File system data ------------------------------------ - -This subdirectory contains specific file system, file handle, inode, dentry -and quota information. - -Currently, these files are in /proc/sys/fs: - -dentry-state ------------- - -Status of the directory cache. Since directory entries are dynamically -allocated and deallocated, this file indicates the current status. It holds -six values, in which the last two are not used and are always zero. The others -are listed in table 2-1. - - -Table 2-1: Status files of the directory cache -.............................................................................. - File Content - nr_dentry Almost always zero - nr_unused Number of unused cache entries - age_limit - in seconds after the entry may be reclaimed, when memory is short - want_pages internally -.............................................................................. - -dquot-nr and dquot-max ----------------------- - -The file dquot-max shows the maximum number of cached disk quota entries. - -The file dquot-nr shows the number of allocated disk quota entries and the -number of free disk quota entries. - -If the number of available cached disk quotas is very low and you have a large -number of simultaneous system users, you might want to raise the limit. - -file-nr and file-max --------------------- - -The kernel allocates file handles dynamically, but doesn't free them again at -this time. - -The value in file-max denotes the maximum number of file handles that the -Linux kernel will allocate. When you get a lot of error messages about running -out of file handles, you might want to raise this limit. The default value is -10% of RAM in kilobytes. To change it, just write the new number into the -file: - - # cat /proc/sys/fs/file-max - 4096 - # echo 8192 > /proc/sys/fs/file-max - # cat /proc/sys/fs/file-max - 8192 - - -This method of revision is useful for all customizable parameters of the -kernel - simply echo the new value to the corresponding file. - -Historically, the three values in file-nr denoted the number of allocated file -handles, the number of allocated but unused file handles, and the maximum -number of file handles. Linux 2.6 always reports 0 as the number of free file -handles -- this is not an error, it just means that the number of allocated -file handles exactly matches the number of used file handles. - -Attempts to allocate more file descriptors than file-max are reported with -printk, look for "VFS: file-max limit reached". - -inode-state and inode-nr ------------------------- - -The file inode-nr contains the first two items from inode-state, so we'll skip -to that file... - -inode-state contains two actual numbers and five dummy values. The numbers -are nr_inodes and nr_free_inodes (in order of appearance). - -nr_inodes -~~~~~~~~~ - -Denotes the number of inodes the system has allocated. This number will -grow and shrink dynamically. - -nr_open -------- - -Denotes the maximum number of file-handles a process can -allocate. Default value is 1024*1024 (1048576) which should be -enough for most machines. Actual limit depends on RLIMIT_NOFILE -resource limit. - -nr_free_inodes --------------- - -Represents the number of free inodes. Ie. The number of inuse inodes is -(nr_inodes - nr_free_inodes). - -aio-nr and aio-max-nr ---------------------- - -aio-nr is the running total of the number of events specified on the -io_setup system call for all currently active aio contexts. If aio-nr -reaches aio-max-nr then io_setup will fail with EAGAIN. Note that -raising aio-max-nr does not result in the pre-allocation or re-sizing -of any kernel data structures. - -2.2 /proc/sys/fs/binfmt_misc - Miscellaneous binary formats ------------------------------------------------------------ - -Besides these files, there is the subdirectory /proc/sys/fs/binfmt_misc. This -handles the kernel support for miscellaneous binary formats. - -Binfmt_misc provides the ability to register additional binary formats to the -Kernel without compiling an additional module/kernel. Therefore, binfmt_misc -needs to know magic numbers at the beginning or the filename extension of the -binary. - -It works by maintaining a linked list of structs that contain a description of -a binary format, including a magic with size (or the filename extension), -offset and mask, and the interpreter name. On request it invokes the given -interpreter with the original program as argument, as binfmt_java and -binfmt_em86 and binfmt_mz do. Since binfmt_misc does not define any default -binary-formats, you have to register an additional binary-format. - -There are two general files in binfmt_misc and one file per registered format. -The two general files are register and status. - -Registering a new binary format -------------------------------- - -To register a new binary format you have to issue the command - - echo :name:type:offset:magic:mask:interpreter: > /proc/sys/fs/binfmt_misc/register - - - -with appropriate name (the name for the /proc-dir entry), offset (defaults to -0, if omitted), magic, mask (which can be omitted, defaults to all 0xff) and -last but not least, the interpreter that is to be invoked (for example and -testing /bin/echo). Type can be M for usual magic matching or E for filename -extension matching (give extension in place of magic). - -Check or reset the status of the binary format handler ------------------------------------------------------- - -If you do a cat on the file /proc/sys/fs/binfmt_misc/status, you will get the -current status (enabled/disabled) of binfmt_misc. Change the status by echoing -0 (disables) or 1 (enables) or -1 (caution: this clears all previously -registered binary formats) to status. For example echo 0 > status to disable -binfmt_misc (temporarily). - -Status of a single handler --------------------------- - -Each registered handler has an entry in /proc/sys/fs/binfmt_misc. These files -perform the same function as status, but their scope is limited to the actual -binary format. By cating this file, you also receive all related information -about the interpreter/magic of the binfmt. - -Example usage of binfmt_misc (emulate binfmt_java) --------------------------------------------------- - - cd /proc/sys/fs/binfmt_misc - echo ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' > register - echo ':HTML:E::html::/usr/local/java/bin/appletviewer:' > register - echo ':Applet:M:: %o0 == childs pid, %o1 == 0 * Child --> %o0 == parents pid, %o1 == 1 */ -int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, +int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { diff --git a/trunk/arch/sparc/mm/highmem.c b/trunk/arch/sparc/mm/highmem.c index 752d0c9fb544..7916feba6e4a 100644 --- a/trunk/arch/sparc/mm/highmem.c +++ b/trunk/arch/sparc/mm/highmem.c @@ -39,6 +39,7 @@ void *kmap_atomic(struct page *page, enum km_type type) if (!PageHighMem(page)) return page_address(page); + debug_kmap_atomic(type); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); diff --git a/trunk/arch/um/drivers/net_kern.c b/trunk/arch/um/drivers/net_kern.c index 434224e2229f..434ba121e3c5 100644 --- a/trunk/arch/um/drivers/net_kern.c +++ b/trunk/arch/um/drivers/net_kern.c @@ -757,7 +757,7 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, void (*proc)(unsigned char *, unsigned char *, void *); unsigned char addr_buf[4], netmask_buf[4]; - if (dev->open != uml_net_open) + if (dev->netdev_ops->ndo_open != uml_net_open) return NOTIFY_DONE; lp = netdev_priv(dev); diff --git a/trunk/arch/um/drivers/pcap_user.h b/trunk/arch/um/drivers/pcap_user.h index 96b80b565eeb..d8ba6153f912 100644 --- a/trunk/arch/um/drivers/pcap_user.h +++ b/trunk/arch/um/drivers/pcap_user.h @@ -19,13 +19,3 @@ extern const struct net_user_info pcap_user_info; extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/port.h b/trunk/arch/um/drivers/port.h index 9117609a575d..372a80c0556a 100644 --- a/trunk/arch/um/drivers/port.h +++ b/trunk/arch/um/drivers/port.h @@ -18,13 +18,3 @@ extern void port_remove_dev(void *d); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/ssl.h b/trunk/arch/um/drivers/ssl.h index 98412aa66607..314d17725ce6 100644 --- a/trunk/arch/um/drivers/ssl.h +++ b/trunk/arch/um/drivers/ssl.h @@ -11,13 +11,3 @@ extern void ssl_receive_char(int line, char ch); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/stdio_console.h b/trunk/arch/um/drivers/stdio_console.h index 505a3d5bea5e..6d8275f71fd4 100644 --- a/trunk/arch/um/drivers/stdio_console.h +++ b/trunk/arch/um/drivers/stdio_console.h @@ -9,13 +9,3 @@ extern void save_console_flags(void); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/drivers/ubd_kern.c b/trunk/arch/um/drivers/ubd_kern.c index 0a868118cf06..f934225fd8ef 100644 --- a/trunk/arch/um/drivers/ubd_kern.c +++ b/trunk/arch/um/drivers/ubd_kern.c @@ -17,12 +17,12 @@ * James McMechan */ -#define MAJOR_NR UBD_MAJOR #define UBD_SHIFT 4 #include "linux/kernel.h" #include "linux/module.h" #include "linux/blkdev.h" +#include "linux/ata.h" #include "linux/hdreg.h" #include "linux/init.h" #include "linux/cdrom.h" @@ -115,7 +115,7 @@ static struct block_device_operations ubd_blops = { }; /* Protected by ubd_lock */ -static int fake_major = MAJOR_NR; +static int fake_major = UBD_MAJOR; static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; @@ -299,7 +299,7 @@ static int ubd_setup_common(char *str, int *index_out, char **error_out) } mutex_lock(&ubd_lock); - if(fake_major != MAJOR_NR){ + if (fake_major != UBD_MAJOR) { *error_out = "Can't assign a fake major twice"; goto out1; } @@ -818,13 +818,13 @@ static int ubd_disk_register(int major, u64 size, int unit, disk->first_minor = unit << UBD_SHIFT; disk->fops = &ubd_blops; set_capacity(disk, size / 512); - if(major == MAJOR_NR) + if (major == UBD_MAJOR) sprintf(disk->disk_name, "ubd%c", 'a' + unit); else sprintf(disk->disk_name, "ubd_fake%d", unit); /* sysfs register (not for ide fake devices) */ - if (major == MAJOR_NR) { + if (major == UBD_MAJOR) { ubd_devs[unit].pdev.id = unit; ubd_devs[unit].pdev.name = DRIVER_NAME; ubd_devs[unit].pdev.dev.release = ubd_device_release; @@ -871,13 +871,13 @@ static int ubd_add(int n, char **error_out) ubd_dev->queue->queuedata = ubd_dev; blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG); - err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); + err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]); if(err){ *error_out = "Failed to register device"; goto out_cleanup; } - if(fake_major != MAJOR_NR) + if (fake_major != UBD_MAJOR) ubd_disk_register(fake_major, ubd_dev->size, n, &fake_gendisk[n]); @@ -1059,10 +1059,10 @@ static int __init ubd_init(void) char *error; int i, err; - if (register_blkdev(MAJOR_NR, "ubd")) + if (register_blkdev(UBD_MAJOR, "ubd")) return -1; - if (fake_major != MAJOR_NR) { + if (fake_major != UBD_MAJOR) { char name[sizeof("ubd_nnn\0")]; snprintf(name, sizeof(name), "ubd_%d", fake_major); @@ -1309,16 +1309,15 @@ static int ubd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct ubd *ubd_dev = bdev->bd_disk->private_data; - struct hd_driveid ubd_id = { - .cyls = 0, - .heads = 128, - .sectors = 32, - }; + u16 ubd_id[ATA_ID_WORDS]; switch (cmd) { struct cdrom_volctrl volume; case HDIO_GET_IDENTITY: - ubd_id.cyls = ubd_dev->size / (128 * 32 * 512); + memset(&ubd_id, 0, ATA_ID_WORDS * 2); + ubd_id[ATA_ID_CYLS] = ubd_dev->size / (128 * 32 * 512); + ubd_id[ATA_ID_HEADS] = 128; + ubd_id[ATA_ID_SECTORS] = 32; if(copy_to_user((char __user *) arg, (char *) &ubd_id, sizeof(ubd_id))) return -EFAULT; diff --git a/trunk/arch/um/drivers/xterm.h b/trunk/arch/um/drivers/xterm.h index f33a6e77b186..56b9c4aba423 100644 --- a/trunk/arch/um/drivers/xterm.h +++ b/trunk/arch/um/drivers/xterm.h @@ -10,13 +10,3 @@ extern int xterm_fd(int socket, int *pid_out); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/asm/irq_vectors.h b/trunk/arch/um/include/asm/irq_vectors.h index 62ddba6fc733..272a81e0ce14 100644 --- a/trunk/arch/um/include/asm/irq_vectors.h +++ b/trunk/arch/um/include/asm/irq_vectors.h @@ -8,13 +8,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/asm/mmu.h b/trunk/arch/um/include/asm/mmu.h index 2cf35c21d694..cf259de51531 100644 --- a/trunk/arch/um/include/asm/mmu.h +++ b/trunk/arch/um/include/asm/mmu.h @@ -10,13 +10,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/asm/pda.h b/trunk/arch/um/include/asm/pda.h index 0d8bf33ffd42..ddcd774fc2a0 100644 --- a/trunk/arch/um/include/asm/pda.h +++ b/trunk/arch/um/include/asm/pda.h @@ -19,13 +19,3 @@ extern struct foo me; #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/asm/pgalloc.h b/trunk/arch/um/include/asm/pgalloc.h index 9062a6e72241..718984359f8c 100644 --- a/trunk/arch/um/include/asm/pgalloc.h +++ b/trunk/arch/um/include/asm/pgalloc.h @@ -60,13 +60,3 @@ static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/asm/pgtable-3level.h b/trunk/arch/um/include/asm/pgtable-3level.h index 0446f456b428..084de4a9fc70 100644 --- a/trunk/arch/um/include/asm/pgtable-3level.h +++ b/trunk/arch/um/include/asm/pgtable-3level.h @@ -134,13 +134,3 @@ static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot) #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/shared/frame_kern.h b/trunk/arch/um/include/shared/frame_kern.h index ce9514f57211..76078490c258 100644 --- a/trunk/arch/um/include/shared/frame_kern.h +++ b/trunk/arch/um/include/shared/frame_kern.h @@ -20,13 +20,3 @@ extern int setup_signal_stack_si(unsigned long stack_top, int sig, #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/shared/initrd.h b/trunk/arch/um/include/shared/initrd.h index 439b9a814985..22673bcc273d 100644 --- a/trunk/arch/um/include/shared/initrd.h +++ b/trunk/arch/um/include/shared/initrd.h @@ -10,13 +10,3 @@ extern int load_initrd(char *filename, void *buf, int size); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/shared/irq_kern.h b/trunk/arch/um/include/shared/irq_kern.h index fba3895274f9..b05d22f3d84e 100644 --- a/trunk/arch/um/include/shared/irq_kern.h +++ b/trunk/arch/um/include/shared/irq_kern.h @@ -16,13 +16,3 @@ extern int um_request_irq(unsigned int irq, int fd, int type, #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/shared/mem_kern.h b/trunk/arch/um/include/shared/mem_kern.h index cb7e196d366b..69be0fd0ce4b 100644 --- a/trunk/arch/um/include/shared/mem_kern.h +++ b/trunk/arch/um/include/shared/mem_kern.h @@ -18,13 +18,3 @@ extern void register_remapper(struct remapper *info); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/include/shared/ubd_user.h b/trunk/arch/um/include/shared/ubd_user.h index bb66517f0739..3845051f1b10 100644 --- a/trunk/arch/um/include/shared/ubd_user.h +++ b/trunk/arch/um/include/shared/ubd_user.h @@ -14,13 +14,3 @@ extern int kernel_fd; #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/kernel/Makefile b/trunk/arch/um/kernel/Makefile index 499e5e95e609..388ec0a3ea9b 100644 --- a/trunk/arch/um/kernel/Makefile +++ b/trunk/arch/um/kernel/Makefile @@ -28,7 +28,7 @@ $(obj)/config.tmp: $(objtree)/.config FORCE $(call if_changed,quote1) quiet_cmd_quote1 = QUOTE $@ - cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' \ + cmd_quote1 = sed -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n",/' \ $< > $@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE @@ -36,9 +36,9 @@ $(obj)/config.c: $(src)/config.c.in $(obj)/config.tmp FORCE quiet_cmd_quote2 = QUOTE $@ cmd_quote2 = sed -e '/CONFIG/{' \ - -e 's/"CONFIG"\;/""/' \ + -e 's/"CONFIG"//' \ -e 'r $(obj)/config.tmp' \ -e 'a \' \ - -e '""\;' \ + -e '""' \ -e '}' \ $< > $@ diff --git a/trunk/arch/um/kernel/config.c.in b/trunk/arch/um/kernel/config.c.in index c062cbfe386e..b7a43feafde7 100644 --- a/trunk/arch/um/kernel/config.c.in +++ b/trunk/arch/um/kernel/config.c.in @@ -7,11 +7,15 @@ #include #include "init.h" -static __initdata char *config = "CONFIG"; +static __initdata const char *config[] = { +"CONFIG" +}; static int __init print_config(char *line, int *add) { - printf("%s", config); + int i; + for (i = 0; i < sizeof(config)/sizeof(config[0]); i++) + printf("%s", config[i]); exit(0); } @@ -20,13 +24,3 @@ __uml_setup("--showconfig", print_config, " Prints the config file that this UML binary was generated from.\n\n" ); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/kernel/process.c b/trunk/arch/um/kernel/process.c index a1c6d07cac3e..4a28a1568d85 100644 --- a/trunk/arch/um/kernel/process.c +++ b/trunk/arch/um/kernel/process.c @@ -179,7 +179,7 @@ void fork_handler(void) userspace(¤t->thread.regs.regs); } -int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, +int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { diff --git a/trunk/arch/um/kernel/syscall.c b/trunk/arch/um/kernel/syscall.c index c4df705b8359..a4625c7b2bf9 100644 --- a/trunk/arch/um/kernel/syscall.c +++ b/trunk/arch/um/kernel/syscall.c @@ -127,7 +127,8 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[]) fs = get_fs(); set_fs(KERNEL_DS); - ret = um_execve(filename, argv, envp); + ret = um_execve((char *)filename, (char __user *__user *)argv, + (char __user *__user *) envp); set_fs(fs); return ret; diff --git a/trunk/arch/um/os-Linux/start_up.c b/trunk/arch/um/os-Linux/start_up.c index 183db26d01bf..02ee9adff54a 100644 --- a/trunk/arch/um/os-Linux/start_up.c +++ b/trunk/arch/um/os-Linux/start_up.c @@ -244,7 +244,7 @@ static void __init check_sysemu(void) if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *) PTRACE_O_TRACESYSGOOD) < 0)) - fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); + fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); while (1) { count++; @@ -252,12 +252,12 @@ static void __init check_sysemu(void) goto fail; CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if (n < 0) - fatal_perror("check_ptrace : wait failed"); + fatal_perror("check_sysemu: wait failed"); if (WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))) { if (!count) { - non_fatal("check_ptrace : SYSEMU_SINGLESTEP " + non_fatal("check_sysemu: SYSEMU_SINGLESTEP " "doesn't singlestep"); goto fail; } @@ -271,7 +271,7 @@ static void __init check_sysemu(void) else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) count++; else { - non_fatal("check_ptrace : expected SIGTRAP or " + non_fatal("check_sysemu: expected SIGTRAP or " "(SIGTRAP | 0x80), got status = %d\n", status); goto fail; diff --git a/trunk/arch/um/sys-i386/asm/archparam.h b/trunk/arch/um/sys-i386/asm/archparam.h index 93fd723344e5..2a18a884ca1b 100644 --- a/trunk/arch/um/sys-i386/asm/archparam.h +++ b/trunk/arch/um/sys-i386/asm/archparam.h @@ -14,13 +14,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-i386/shared/sysdep/checksum.h b/trunk/arch/um/sys-i386/shared/sysdep/checksum.h index 0cb4645cbeb8..ed47445f3905 100644 --- a/trunk/arch/um/sys-i386/shared/sysdep/checksum.h +++ b/trunk/arch/um/sys-i386/shared/sysdep/checksum.h @@ -199,13 +199,3 @@ static __inline__ __wsum csum_and_copy_to_user(const void *src, #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-i386/sys_call_table.S b/trunk/arch/um/sys-i386/sys_call_table.S index 00e5f5203eea..c6260dd6ebb9 100644 --- a/trunk/arch/um/sys-i386/sys_call_table.S +++ b/trunk/arch/um/sys-i386/sys_call_table.S @@ -9,6 +9,17 @@ #define old_mmap old_mmap_i386 +#define ptregs_fork sys_fork +#define ptregs_execve sys_execve +#define ptregs_iopl sys_iopl +#define ptregs_vm86old sys_vm86old +#define ptregs_sigreturn sys_sigreturn +#define ptregs_clone sys_clone +#define ptregs_vm86 sys_vm86 +#define ptregs_rt_sigreturn sys_rt_sigreturn +#define ptregs_sigaltstack sys_sigaltstack +#define ptregs_vfork sys_vfork + .section .rodata,"a" #include "../../x86/kernel/syscall_table_32.S" diff --git a/trunk/arch/um/sys-ia64/sysdep/ptrace.h b/trunk/arch/um/sys-ia64/sysdep/ptrace.h index 42dd8fb6f2f9..0f0f4e6fd334 100644 --- a/trunk/arch/um/sys-ia64/sysdep/ptrace.h +++ b/trunk/arch/um/sys-ia64/sysdep/ptrace.h @@ -14,13 +14,3 @@ struct sys_pt_regs { #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ia64/sysdep/sigcontext.h b/trunk/arch/um/sys-ia64/sysdep/sigcontext.h index f15fb25260ba..76b43161e779 100644 --- a/trunk/arch/um/sys-ia64/sysdep/sigcontext.h +++ b/trunk/arch/um/sys-ia64/sysdep/sigcontext.h @@ -8,13 +8,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ia64/sysdep/syscalls.h b/trunk/arch/um/sys-ia64/sysdep/syscalls.h index 4a1f46ef1ebc..5f6700c41558 100644 --- a/trunk/arch/um/sys-ia64/sysdep/syscalls.h +++ b/trunk/arch/um/sys-ia64/sysdep/syscalls.h @@ -8,13 +8,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ppc/miscthings.c b/trunk/arch/um/sys-ppc/miscthings.c index 373061c50129..1c11aed9c719 100644 --- a/trunk/arch/um/sys-ppc/miscthings.c +++ b/trunk/arch/um/sys-ppc/miscthings.c @@ -40,14 +40,3 @@ void shove_aux_table(unsigned long sp) } /* END stuff taken from arch/ppc/kernel/process.c */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ppc/ptrace.c b/trunk/arch/um/sys-ppc/ptrace.c index 8e71b47f2b8e..66ef155248f1 100644 --- a/trunk/arch/um/sys-ppc/ptrace.c +++ b/trunk/arch/um/sys-ppc/ptrace.c @@ -56,13 +56,3 @@ int peek_user(struct task_struct *child, long addr, long data) return put_user(tmp, (unsigned long *) data); } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ppc/ptrace_user.c b/trunk/arch/um/sys-ppc/ptrace_user.c index ff0b9c077a13..224d2403c37b 100644 --- a/trunk/arch/um/sys-ppc/ptrace_user.c +++ b/trunk/arch/um/sys-ppc/ptrace_user.c @@ -27,13 +27,3 @@ int ptrace_setregs(long pid, unsigned long *regs_in) } return 0; } -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ppc/shared/sysdep/ptrace.h b/trunk/arch/um/sys-ppc/shared/sysdep/ptrace.h index df2397dba3e5..0e3230e937e1 100644 --- a/trunk/arch/um/sys-ppc/shared/sysdep/ptrace.h +++ b/trunk/arch/um/sys-ppc/shared/sysdep/ptrace.h @@ -91,13 +91,3 @@ extern void shove_aux_table(unsigned long sp); #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ppc/shared/sysdep/sigcontext.h b/trunk/arch/um/sys-ppc/shared/sysdep/sigcontext.h index f20d965de9c7..b7286f0a1e00 100644 --- a/trunk/arch/um/sys-ppc/shared/sysdep/sigcontext.h +++ b/trunk/arch/um/sys-ppc/shared/sysdep/sigcontext.h @@ -50,13 +50,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ppc/shared/sysdep/syscalls.h b/trunk/arch/um/sys-ppc/shared/sysdep/syscalls.h index 679df351e19b..1ff81552251c 100644 --- a/trunk/arch/um/sys-ppc/shared/sysdep/syscalls.h +++ b/trunk/arch/um/sys-ppc/shared/sysdep/syscalls.h @@ -41,13 +41,3 @@ int old_mmap(unsigned long addr, unsigned long len, #define LAST_ARCH_SYSCALL __NR_fadvise64 -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-ppc/sigcontext.c b/trunk/arch/um/sys-ppc/sigcontext.c index 4bdc15c89edd..40694d0f3d15 100644 --- a/trunk/arch/um/sys-ppc/sigcontext.c +++ b/trunk/arch/um/sys-ppc/sigcontext.c @@ -2,13 +2,3 @@ #include "asm/sigcontext.h" #include "sysdep/ptrace.h" -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-x86_64/asm/archparam.h b/trunk/arch/um/sys-x86_64/asm/archparam.h index 270ed9586b68..6c083663b8d9 100644 --- a/trunk/arch/um/sys-x86_64/asm/archparam.h +++ b/trunk/arch/um/sys-x86_64/asm/archparam.h @@ -14,13 +14,3 @@ #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-x86_64/asm/module.h b/trunk/arch/um/sys-x86_64/asm/module.h index 35b5491d3e96..8eb79c2d07d5 100644 --- a/trunk/arch/um/sys-x86_64/asm/module.h +++ b/trunk/arch/um/sys-x86_64/asm/module.h @@ -18,13 +18,3 @@ struct mod_arch_specific #endif -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/um/sys-x86_64/mem.c b/trunk/arch/um/sys-x86_64/mem.c index 3f59a0a4f156..3f8df8abf347 100644 --- a/trunk/arch/um/sys-x86_64/mem.c +++ b/trunk/arch/um/sys-x86_64/mem.c @@ -14,12 +14,3 @@ unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; unsigned long vm_force_exec32 = PROT_EXEC; -/* Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig index 45161b816313..3f27e5c0c9c9 100644 --- a/trunk/arch/x86/Kconfig +++ b/trunk/arch/x86/Kconfig @@ -165,6 +165,9 @@ config AUDIT_ARCH config ARCH_SUPPORTS_OPTIMIZED_INLINING def_bool y +config ARCH_SUPPORTS_DEBUG_PAGEALLOC + def_bool y + # Use the generic interrupt handling code in kernel/irq/: config GENERIC_HARDIRQS bool @@ -1834,8 +1837,8 @@ config PCI_MMCONFIG config DMAR bool "Support for DMA Remapping Devices (EXPERIMENTAL)" - depends on X86_64 && PCI_MSI && ACPI && EXPERIMENTAL - ---help--- + depends on PCI_MSI && ACPI && EXPERIMENTAL + help DMA remapping (DMAR) devices support enables independent address translations for Direct Memory Access (DMA) from devices. These DMA remapping devices are reported via ACPI tables diff --git a/trunk/arch/x86/Kconfig.debug b/trunk/arch/x86/Kconfig.debug index fdb45df608b6..d8359e73317f 100644 --- a/trunk/arch/x86/Kconfig.debug +++ b/trunk/arch/x86/Kconfig.debug @@ -72,14 +72,6 @@ config DEBUG_STACK_USAGE This option will slow down process creation somewhat. -config DEBUG_PAGEALLOC - bool "Debug page memory allocations" - depends on DEBUG_KERNEL - ---help--- - Unmap pages from the kernel linear mapping after free_pages(). - This results in a large slowdown, but helps to find certain types - of memory corruptions. - config DEBUG_PER_CPU_MAPS bool "Debug access to per_cpu maps" depends on DEBUG_KERNEL diff --git a/trunk/arch/x86/boot/memory.c b/trunk/arch/x86/boot/memory.c index 8c3c25f35578..5054c2ddd1a0 100644 --- a/trunk/arch/x86/boot/memory.c +++ b/trunk/arch/x86/boot/memory.c @@ -2,6 +2,7 @@ * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin * * This file is part of the Linux kernel, and is made available under * the terms of the GNU General Public License version 2. @@ -16,24 +17,38 @@ #define SMAP 0x534d4150 /* ASCII "SMAP" */ +struct e820_ext_entry { + struct e820entry std; + u32 ext_flags; +} __attribute__((packed)); + static int detect_memory_e820(void) { int count = 0; u32 next = 0; - u32 size, id; + u32 size, id, edi; u8 err; struct e820entry *desc = boot_params.e820_map; + static struct e820_ext_entry buf; /* static so it is zeroed */ + + /* + * Set this here so that if the BIOS doesn't change this field + * but still doesn't change %ecx, we're still okay... + */ + buf.ext_flags = 1; do { - size = sizeof(struct e820entry); + size = sizeof buf; - /* Important: %edx is clobbered by some BIOSes, - so it must be either used for the error output - or explicitly marked clobbered. */ - asm("int $0x15; setc %0" + /* Important: %edx and %esi are clobbered by some BIOSes, + so they must be either used for the error output + or explicitly marked clobbered. Given that, assume there + is something out there clobbering %ebp and %edi, too. */ + asm("pushl %%ebp; int $0x15; popl %%ebp; setc %0" : "=d" (err), "+b" (next), "=a" (id), "+c" (size), - "=m" (*desc) - : "D" (desc), "d" (SMAP), "a" (0xe820)); + "=D" (edi), "+m" (buf) + : "D" (&buf), "d" (SMAP), "a" (0xe820) + : "esi"); /* BIOSes which terminate the chain with CF = 1 as opposed to %ebx = 0 don't always report the SMAP signature on @@ -51,8 +66,14 @@ static int detect_memory_e820(void) break; } + /* ACPI 3.0 added the extended flags support. If bit 0 + in the extended flags is zero, we're supposed to simply + ignore the entry -- a backwards incompatible change! */ + if (size > 20 && !(buf.ext_flags & 1)) + continue; + + *desc++ = buf.std; count++; - desc++; } while (next && count < ARRAY_SIZE(boot_params.e820_map)); return boot_params.e820_entries = count; diff --git a/trunk/arch/x86/ia32/ia32entry.S b/trunk/arch/x86/ia32/ia32entry.S index db0c803170ab..a505202086e8 100644 --- a/trunk/arch/x86/ia32/ia32entry.S +++ b/trunk/arch/x86/ia32/ia32entry.S @@ -828,4 +828,6 @@ ia32_sys_call_table: .quad sys_dup3 /* 330 */ .quad sys_pipe2 .quad sys_inotify_init1 + .quad compat_sys_preadv + .quad compat_sys_pwritev ia32_syscall_end: diff --git a/trunk/arch/x86/include/asm/pci.h b/trunk/arch/x86/include/asm/pci.h index a977de23cb4d..a0301bfeb954 100644 --- a/trunk/arch/x86/include/asm/pci.h +++ b/trunk/arch/x86/include/asm/pci.h @@ -86,6 +86,9 @@ static inline void early_quirks(void) { } extern void pci_iommu_alloc(void); +/* MSI arch hook */ +#define arch_setup_msi_irqs arch_setup_msi_irqs + #endif /* __KERNEL__ */ #ifdef CONFIG_X86_32 diff --git a/trunk/arch/x86/include/asm/spinlock.h b/trunk/arch/x86/include/asm/spinlock.h index 3a5696656680..e5e6caffec87 100644 --- a/trunk/arch/x86/include/asm/spinlock.h +++ b/trunk/arch/x86/include/asm/spinlock.h @@ -295,6 +295,9 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw) : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory"); } +#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock) +#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock) + #define _raw_spin_relax(lock) cpu_relax() #define _raw_read_relax(lock) cpu_relax() #define _raw_write_relax(lock) cpu_relax() diff --git a/trunk/arch/x86/include/asm/suspend_32.h b/trunk/arch/x86/include/asm/suspend_32.h index a5074bd0f8be..48dcfa62ea07 100644 --- a/trunk/arch/x86/include/asm/suspend_32.h +++ b/trunk/arch/x86/include/asm/suspend_32.h @@ -24,28 +24,4 @@ struct saved_context { unsigned long return_address; } __attribute__((packed)); -#ifdef CONFIG_ACPI -extern unsigned long saved_eip; -extern unsigned long saved_esp; -extern unsigned long saved_ebp; -extern unsigned long saved_ebx; -extern unsigned long saved_esi; -extern unsigned long saved_edi; - -static inline void acpi_save_register_state(unsigned long return_point) -{ - saved_eip = return_point; - asm volatile("movl %%esp,%0" : "=m" (saved_esp)); - asm volatile("movl %%ebp,%0" : "=m" (saved_ebp)); - asm volatile("movl %%ebx,%0" : "=m" (saved_ebx)); - asm volatile("movl %%edi,%0" : "=m" (saved_edi)); - asm volatile("movl %%esi,%0" : "=m" (saved_esi)); -} - -#define acpi_restore_register_state() do {} while (0) - -/* routines for saving/restoring kernel state */ -extern int acpi_save_state_mem(void); -#endif - #endif /* _ASM_X86_SUSPEND_32_H */ diff --git a/trunk/arch/x86/include/asm/unistd_32.h b/trunk/arch/x86/include/asm/unistd_32.h index f2bba78430a4..6e72d74cf8dc 100644 --- a/trunk/arch/x86/include/asm/unistd_32.h +++ b/trunk/arch/x86/include/asm/unistd_32.h @@ -338,6 +338,8 @@ #define __NR_dup3 330 #define __NR_pipe2 331 #define __NR_inotify_init1 332 +#define __NR_preadv 333 +#define __NR_pwritev 334 #ifdef __KERNEL__ diff --git a/trunk/arch/x86/include/asm/unistd_64.h b/trunk/arch/x86/include/asm/unistd_64.h index d2e415e6666f..f81829462325 100644 --- a/trunk/arch/x86/include/asm/unistd_64.h +++ b/trunk/arch/x86/include/asm/unistd_64.h @@ -653,6 +653,10 @@ __SYSCALL(__NR_dup3, sys_dup3) __SYSCALL(__NR_pipe2, sys_pipe2) #define __NR_inotify_init1 294 __SYSCALL(__NR_inotify_init1, sys_inotify_init1) +#define __NR_preadv 295 +__SYSCALL(__NR_preadv, sys_preadv) +#define __NR_pwritev 296 +__SYSCALL(__NR_pwritev, sys_pwritev) #ifndef __NO_STUBS diff --git a/trunk/arch/x86/include/asm/uv/uv_hub.h b/trunk/arch/x86/include/asm/uv/uv_hub.h index 9f4dfba33b28..d3a98ea1062e 100644 --- a/trunk/arch/x86/include/asm/uv/uv_hub.h +++ b/trunk/arch/x86/include/asm/uv/uv_hub.h @@ -11,11 +11,13 @@ #ifndef _ASM_X86_UV_UV_HUB_H #define _ASM_X86_UV_UV_HUB_H +#ifdef CONFIG_X86_64 #include #include #include #include #include +#include /* @@ -397,6 +399,7 @@ static inline void uv_set_scir_bits(unsigned char value) uv_write_local_mmr8(uv_hub_info->scir.offset, value); } } + static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) { if (uv_cpu_hub_info(cpu)->scir.state != value) { @@ -405,4 +408,15 @@ static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) } } +static inline void uv_hub_send_ipi(int pnode, int apicid, int vector) +{ + unsigned long val; + + val = (1UL << UVH_IPI_INT_SEND_SHFT) | + ((apicid & 0x3f) << UVH_IPI_INT_APIC_ID_SHFT) | + (vector << UVH_IPI_INT_VECTOR_SHFT); + uv_write_global_mmr64(pnode, UVH_IPI_INT, val); +} + +#endif /* CONFIG_X86_64 */ #endif /* _ASM_X86_UV_UV_HUB_H */ diff --git a/trunk/arch/x86/include/asm/uv/uv_mmrs.h b/trunk/arch/x86/include/asm/uv/uv_mmrs.h index dd627793a234..db68ac8a5ac2 100644 --- a/trunk/arch/x86/include/asm/uv/uv_mmrs.h +++ b/trunk/arch/x86/include/asm/uv/uv_mmrs.h @@ -1,3 +1,4 @@ + /* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -242,6 +243,158 @@ union uvh_event_occurred0_u { #define UVH_EVENT_OCCURRED0_ALIAS 0x0000000000070008UL #define UVH_EVENT_OCCURRED0_ALIAS_32 0x005f0 +/* ========================================================================= */ +/* UVH_GR0_TLB_INT0_CONFIG */ +/* ========================================================================= */ +#define UVH_GR0_TLB_INT0_CONFIG 0x61b00UL + +#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_SHFT 0 +#define UVH_GR0_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_GR0_TLB_INT0_CONFIG_DM_SHFT 8 +#define UVH_GR0_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_SHFT 11 +#define UVH_GR0_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_GR0_TLB_INT0_CONFIG_STATUS_SHFT 12 +#define UVH_GR0_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_GR0_TLB_INT0_CONFIG_P_SHFT 13 +#define UVH_GR0_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_GR0_TLB_INT0_CONFIG_T_SHFT 15 +#define UVH_GR0_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_GR0_TLB_INT0_CONFIG_M_SHFT 16 +#define UVH_GR0_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_SHFT 32 +#define UVH_GR0_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL + +union uvh_gr0_tlb_int0_config_u { + unsigned long v; + struct uvh_gr0_tlb_int0_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; +}; + +/* ========================================================================= */ +/* UVH_GR0_TLB_INT1_CONFIG */ +/* ========================================================================= */ +#define UVH_GR0_TLB_INT1_CONFIG 0x61b40UL + +#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_SHFT 0 +#define UVH_GR0_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_GR0_TLB_INT1_CONFIG_DM_SHFT 8 +#define UVH_GR0_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_SHFT 11 +#define UVH_GR0_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_GR0_TLB_INT1_CONFIG_STATUS_SHFT 12 +#define UVH_GR0_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_GR0_TLB_INT1_CONFIG_P_SHFT 13 +#define UVH_GR0_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_GR0_TLB_INT1_CONFIG_T_SHFT 15 +#define UVH_GR0_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_GR0_TLB_INT1_CONFIG_M_SHFT 16 +#define UVH_GR0_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_SHFT 32 +#define UVH_GR0_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL + +union uvh_gr0_tlb_int1_config_u { + unsigned long v; + struct uvh_gr0_tlb_int1_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; +}; + +/* ========================================================================= */ +/* UVH_GR1_TLB_INT0_CONFIG */ +/* ========================================================================= */ +#define UVH_GR1_TLB_INT0_CONFIG 0x61f00UL + +#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_SHFT 0 +#define UVH_GR1_TLB_INT0_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_GR1_TLB_INT0_CONFIG_DM_SHFT 8 +#define UVH_GR1_TLB_INT0_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_SHFT 11 +#define UVH_GR1_TLB_INT0_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_GR1_TLB_INT0_CONFIG_STATUS_SHFT 12 +#define UVH_GR1_TLB_INT0_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_GR1_TLB_INT0_CONFIG_P_SHFT 13 +#define UVH_GR1_TLB_INT0_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_GR1_TLB_INT0_CONFIG_T_SHFT 15 +#define UVH_GR1_TLB_INT0_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_GR1_TLB_INT0_CONFIG_M_SHFT 16 +#define UVH_GR1_TLB_INT0_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_SHFT 32 +#define UVH_GR1_TLB_INT0_CONFIG_APIC_ID_MASK 0xffffffff00000000UL + +union uvh_gr1_tlb_int0_config_u { + unsigned long v; + struct uvh_gr1_tlb_int0_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; +}; + +/* ========================================================================= */ +/* UVH_GR1_TLB_INT1_CONFIG */ +/* ========================================================================= */ +#define UVH_GR1_TLB_INT1_CONFIG 0x61f40UL + +#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_SHFT 0 +#define UVH_GR1_TLB_INT1_CONFIG_VECTOR_MASK 0x00000000000000ffUL +#define UVH_GR1_TLB_INT1_CONFIG_DM_SHFT 8 +#define UVH_GR1_TLB_INT1_CONFIG_DM_MASK 0x0000000000000700UL +#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_SHFT 11 +#define UVH_GR1_TLB_INT1_CONFIG_DESTMODE_MASK 0x0000000000000800UL +#define UVH_GR1_TLB_INT1_CONFIG_STATUS_SHFT 12 +#define UVH_GR1_TLB_INT1_CONFIG_STATUS_MASK 0x0000000000001000UL +#define UVH_GR1_TLB_INT1_CONFIG_P_SHFT 13 +#define UVH_GR1_TLB_INT1_CONFIG_P_MASK 0x0000000000002000UL +#define UVH_GR1_TLB_INT1_CONFIG_T_SHFT 15 +#define UVH_GR1_TLB_INT1_CONFIG_T_MASK 0x0000000000008000UL +#define UVH_GR1_TLB_INT1_CONFIG_M_SHFT 16 +#define UVH_GR1_TLB_INT1_CONFIG_M_MASK 0x0000000000010000UL +#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_SHFT 32 +#define UVH_GR1_TLB_INT1_CONFIG_APIC_ID_MASK 0xffffffff00000000UL + +union uvh_gr1_tlb_int1_config_u { + unsigned long v; + struct uvh_gr1_tlb_int1_config_s { + unsigned long vector_ : 8; /* RW */ + unsigned long dm : 3; /* RW */ + unsigned long destmode : 1; /* RW */ + unsigned long status : 1; /* RO */ + unsigned long p : 1; /* RO */ + unsigned long rsvd_14 : 1; /* */ + unsigned long t : 1; /* RO */ + unsigned long m : 1; /* RW */ + unsigned long rsvd_17_31: 15; /* */ + unsigned long apic_id : 32; /* RW */ + } s; +}; + /* ========================================================================= */ /* UVH_INT_CMPB */ /* ========================================================================= */ diff --git a/trunk/arch/x86/kernel/amd_iommu.c b/trunk/arch/x86/kernel/amd_iommu.c index c5962fe3796f..a97db99dad52 100644 --- a/trunk/arch/x86/kernel/amd_iommu.c +++ b/trunk/arch/x86/kernel/amd_iommu.c @@ -1928,6 +1928,12 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom, return paddr; } +static int amd_iommu_domain_has_cap(struct iommu_domain *domain, + unsigned long cap) +{ + return 0; +} + static struct iommu_ops amd_iommu_ops = { .domain_init = amd_iommu_domain_init, .domain_destroy = amd_iommu_domain_destroy, @@ -1936,5 +1942,6 @@ static struct iommu_ops amd_iommu_ops = { .map = amd_iommu_map_range, .unmap = amd_iommu_unmap_range, .iova_to_phys = amd_iommu_iova_to_phys, + .domain_has_cap = amd_iommu_domain_has_cap, }; diff --git a/trunk/arch/x86/kernel/apic/io_apic.c b/trunk/arch/x86/kernel/apic/io_apic.c index da99ffcdfde6..1bb5c6cee3eb 100644 --- a/trunk/arch/x86/kernel/apic/io_apic.c +++ b/trunk/arch/x86/kernel/apic/io_apic.c @@ -3468,6 +3468,10 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) struct intel_iommu *iommu = NULL; int index = 0; + /* x86 doesn't support multiple MSI yet */ + if (type == PCI_CAP_ID_MSI && nvec > 1) + return 1; + irq_want = nr_irqs_gsi; sub_handle = 0; list_for_each_entry(msidesc, &dev->msi_list, list) { diff --git a/trunk/arch/x86/kernel/apic/x2apic_uv_x.c b/trunk/arch/x86/kernel/apic/x2apic_uv_x.c index 1bd6da1f8fad..1248318436e8 100644 --- a/trunk/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/trunk/arch/x86/kernel/apic/x2apic_uv_x.c @@ -118,17 +118,12 @@ static int uv_wakeup_secondary(int phys_apicid, unsigned long start_rip) static void uv_send_IPI_one(int cpu, int vector) { - unsigned long val, apicid; + unsigned long apicid; int pnode; apicid = per_cpu(x86_cpu_to_apicid, cpu); pnode = uv_apicid_to_pnode(apicid); - - val = (1UL << UVH_IPI_INT_SEND_SHFT) | - (apicid << UVH_IPI_INT_APIC_ID_SHFT) | - (vector << UVH_IPI_INT_VECTOR_SHFT); - - uv_write_global_mmr64(pnode, UVH_IPI_INT, val); + uv_hub_send_ipi(pnode, apicid, vector); } static void uv_send_IPI_mask(const struct cpumask *mask, int vector) diff --git a/trunk/arch/x86/kernel/asm-offsets_32.c b/trunk/arch/x86/kernel/asm-offsets_32.c index fbf2f33e3080..5a6aa1c1162f 100644 --- a/trunk/arch/x86/kernel/asm-offsets_32.c +++ b/trunk/arch/x86/kernel/asm-offsets_32.c @@ -18,6 +18,7 @@ #include #include #include +#include #include diff --git a/trunk/arch/x86/kernel/asm-offsets_64.c b/trunk/arch/x86/kernel/asm-offsets_64.c index 8793ab33e2c1..e72f062fb4b5 100644 --- a/trunk/arch/x86/kernel/asm-offsets_64.c +++ b/trunk/arch/x86/kernel/asm-offsets_64.c @@ -16,6 +16,7 @@ #include #include #include +#include #include diff --git a/trunk/arch/x86/kernel/pci-dma.c b/trunk/arch/x86/kernel/pci-dma.c index c7c4776ff630..90f5b9ef5def 100644 --- a/trunk/arch/x86/kernel/pci-dma.c +++ b/trunk/arch/x86/kernel/pci-dma.c @@ -300,8 +300,7 @@ fs_initcall(pci_iommu_init); static __devinit void via_no_dac(struct pci_dev *dev) { if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) { - printk(KERN_INFO - "PCI: VIA PCI bridge detected. Disabling DAC.\n"); + dev_info(&dev->dev, "disabling DAC on VIA PCI bridge\n"); forbid_dac = 1; } } diff --git a/trunk/arch/x86/kernel/process_32.c b/trunk/arch/x86/kernel/process_32.c index 14014d766cad..76f8f84043a2 100644 --- a/trunk/arch/x86/kernel/process_32.c +++ b/trunk/arch/x86/kernel/process_32.c @@ -245,7 +245,7 @@ void prepare_to_copy(struct task_struct *tsk) unlazy_fpu(tsk); } -int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, +int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { diff --git a/trunk/arch/x86/kernel/process_64.c b/trunk/arch/x86/kernel/process_64.c index abb7e6a7f0c6..b751a41392b1 100644 --- a/trunk/arch/x86/kernel/process_64.c +++ b/trunk/arch/x86/kernel/process_64.c @@ -278,7 +278,7 @@ void prepare_to_copy(struct task_struct *tsk) unlazy_fpu(tsk); } -int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, +int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { diff --git a/trunk/arch/x86/kernel/ptrace.c b/trunk/arch/x86/kernel/ptrace.c index 19378715f415..b7cc21bc6ae0 100644 --- a/trunk/arch/x86/kernel/ptrace.c +++ b/trunk/arch/x86/kernel/ptrace.c @@ -1455,6 +1455,6 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs) * system call instruction. */ if (test_thread_flag(TIF_SINGLESTEP) && - tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL)) + tracehook_consider_fatal_signal(current, SIGTRAP)) send_sigtrap(current, regs, 0, TRAP_BRKPT); } diff --git a/trunk/arch/x86/kernel/syscall_table_32.S b/trunk/arch/x86/kernel/syscall_table_32.S index 3bdb64829b82..ff5c8736b491 100644 --- a/trunk/arch/x86/kernel/syscall_table_32.S +++ b/trunk/arch/x86/kernel/syscall_table_32.S @@ -332,3 +332,5 @@ ENTRY(sys_call_table) .long sys_dup3 /* 330 */ .long sys_pipe2 .long sys_inotify_init1 + .long sys_preadv + .long sys_pwritev diff --git a/trunk/arch/x86/mm/highmem_32.c b/trunk/arch/x86/mm/highmem_32.c index 522db5e3d0bf..8126e8d1a2a4 100644 --- a/trunk/arch/x86/mm/highmem_32.c +++ b/trunk/arch/x86/mm/highmem_32.c @@ -19,49 +19,6 @@ void kunmap(struct page *page) kunmap_high(page); } -static void debug_kmap_atomic_prot(enum km_type type) -{ -#ifdef CONFIG_DEBUG_HIGHMEM - static unsigned warn_count = 10; - - if (unlikely(warn_count == 0)) - return; - - if (unlikely(in_interrupt())) { - if (in_irq()) { - if (type != KM_IRQ0 && type != KM_IRQ1 && - type != KM_BIO_SRC_IRQ && type != KM_BIO_DST_IRQ && - type != KM_BOUNCE_READ) { - WARN_ON(1); - warn_count--; - } - } else if (!irqs_disabled()) { /* softirq */ - if (type != KM_IRQ0 && type != KM_IRQ1 && - type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 && - type != KM_SKB_SUNRPC_DATA && - type != KM_SKB_DATA_SOFTIRQ && - type != KM_BOUNCE_READ) { - WARN_ON(1); - warn_count--; - } - } - } - - if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ || - type == KM_BIO_SRC_IRQ || type == KM_BIO_DST_IRQ) { - if (!irqs_disabled()) { - WARN_ON(1); - warn_count--; - } - } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) { - if (irq_count() == 0 && !irqs_disabled()) { - WARN_ON(1); - warn_count--; - } - } -#endif -} - /* * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because * no global lock is needed and because the kmap code must perform a global TLB @@ -81,7 +38,7 @@ void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) if (!PageHighMem(page)) return page_address(page); - debug_kmap_atomic_prot(type); + debug_kmap_atomic(type); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); diff --git a/trunk/arch/x86/mm/iomap_32.c b/trunk/arch/x86/mm/iomap_32.c index 699c9b2895ae..e331f77348a7 100644 --- a/trunk/arch/x86/mm/iomap_32.c +++ b/trunk/arch/x86/mm/iomap_32.c @@ -19,6 +19,7 @@ #include #include #include +#include int is_io_mapping_possible(resource_size_t base, unsigned long size) { @@ -38,6 +39,7 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot) pagefault_disable(); + debug_kmap_atomic(type); idx = type + KM_TYPE_NR * smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); set_pte(kmap_pte - idx, pfn_pte(pfn, prot)); diff --git a/trunk/arch/x86/pci/early.c b/trunk/arch/x86/pci/early.c index f6adf2c6d751..aaf26ae58cd5 100644 --- a/trunk/arch/x86/pci/early.c +++ b/trunk/arch/x86/pci/early.c @@ -69,11 +69,12 @@ void early_dump_pci_device(u8 bus, u8 slot, u8 func) int j; u32 val; - printk(KERN_INFO "PCI: %02x:%02x:%02x", bus, slot, func); + printk(KERN_INFO "pci 0000:%02x:%02x.%d config space:", + bus, slot, func); for (i = 0; i < 256; i += 4) { if (!(i & 0x0f)) - printk("\n%04x:",i); + printk("\n %02x:",i); val = read_pci_config(bus, slot, func, i); for (j = 0; j < 4; j++) { @@ -96,20 +97,22 @@ void early_dump_pci_devices(void) for (func = 0; func < 8; func++) { u32 class; u8 type; + class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION); if (class == 0xffffffff) - break; + continue; early_dump_pci_device(bus, slot, func); - /* No multi-function device? */ - type = read_pci_config_byte(bus, slot, func, + if (func == 0) { + type = read_pci_config_byte(bus, slot, + func, PCI_HEADER_TYPE); - if (!(type & 0x80)) - break; + if (!(type & 0x80)) + break; + } } } } } - diff --git a/trunk/arch/x86/pci/fixup.c b/trunk/arch/x86/pci/fixup.c index 9c49919e4d1c..6dd89555fbfa 100644 --- a/trunk/arch/x86/pci/fixup.c +++ b/trunk/arch/x86/pci/fixup.c @@ -494,26 +494,6 @@ static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015, pci_siemens_interrupt_controller); -/* - * Regular PCI devices have 256 bytes, but AMD Family 10h/11h CPUs have - * 4096 bytes configuration space for each function of their processor - * configuration space. - */ -static void amd_cpu_pci_cfg_space_size(struct pci_dev *dev) -{ - dev->cfg_size = pci_cfg_space_size_ext(dev); -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1300, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1301, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1302, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1303, amd_cpu_pci_cfg_space_size); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1304, amd_cpu_pci_cfg_space_size); - /* * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from * confusing the PCI engine: diff --git a/trunk/arch/x86/pci/legacy.c b/trunk/arch/x86/pci/legacy.c index f1065b129e9c..4061bb0f267d 100644 --- a/trunk/arch/x86/pci/legacy.c +++ b/trunk/arch/x86/pci/legacy.c @@ -50,8 +50,6 @@ static int __init pci_legacy_init(void) if (pci_root_bus) pci_bus_add_devices(pci_root_bus); - pcibios_fixup_peer_bridges(); - return 0; } @@ -67,6 +65,7 @@ int __init pci_subsys_init(void) pci_visws_init(); #endif pci_legacy_init(); + pcibios_fixup_peer_bridges(); pcibios_irq_init(); pcibios_init(); diff --git a/trunk/arch/x86/pci/mmconfig-shared.c b/trunk/arch/x86/pci/mmconfig-shared.c index 89bf9242c80a..905bb526b133 100644 --- a/trunk/arch/x86/pci/mmconfig-shared.c +++ b/trunk/arch/x86/pci/mmconfig-shared.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,24 +25,49 @@ /* Indicate if the mmcfg resources have been placed into the resource table. */ static int __initdata pci_mmcfg_resources_inserted; +static __init int extend_mmcfg(int num) +{ + struct acpi_mcfg_allocation *new; + int new_num = pci_mmcfg_config_num + num; + + new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL); + if (!new) + return -1; + + if (pci_mmcfg_config) { + memcpy(new, pci_mmcfg_config, + sizeof(pci_mmcfg_config[0]) * new_num); + kfree(pci_mmcfg_config); + } + pci_mmcfg_config = new; + + return 0; +} + +static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end) +{ + int i = pci_mmcfg_config_num; + + pci_mmcfg_config_num++; + pci_mmcfg_config[i].address = addr; + pci_mmcfg_config[i].pci_segment = segment; + pci_mmcfg_config[i].start_bus_number = start; + pci_mmcfg_config[i].end_bus_number = end; +} + static const char __init *pci_mmcfg_e7520(void) { u32 win; raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win); win = win & 0xf000; - if(win == 0x0000 || win == 0xf000) - pci_mmcfg_config_num = 0; - else { - pci_mmcfg_config_num = 1; - pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); - if (!pci_mmcfg_config) - return NULL; - pci_mmcfg_config[0].address = win << 16; - pci_mmcfg_config[0].pci_segment = 0; - pci_mmcfg_config[0].start_bus_number = 0; - pci_mmcfg_config[0].end_bus_number = 255; - } + if (win == 0x0000 || win == 0xf000) + return NULL; + + if (extend_mmcfg(1) == -1) + return NULL; + + fill_one_mmcfg(win << 16, 0, 0, 255); return "Intel Corporation E7520 Memory Controller Hub"; } @@ -50,13 +76,11 @@ static const char __init *pci_mmcfg_intel_945(void) { u32 pciexbar, mask = 0, len = 0; - pci_mmcfg_config_num = 1; - raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar); /* Enable bit */ if (!(pciexbar & 1)) - pci_mmcfg_config_num = 0; + return NULL; /* Size bits */ switch ((pciexbar >> 1) & 3) { @@ -73,28 +97,23 @@ static const char __init *pci_mmcfg_intel_945(void) len = 0x04000000U; break; default: - pci_mmcfg_config_num = 0; + return NULL; } /* Errata #2, things break when not aligned on a 256Mb boundary */ /* Can only happen in 64M/128M mode */ if ((pciexbar & mask) & 0x0fffffffU) - pci_mmcfg_config_num = 0; + return NULL; /* Don't hit the APIC registers and their friends */ if ((pciexbar & mask) >= 0xf0000000U) - pci_mmcfg_config_num = 0; - - if (pci_mmcfg_config_num) { - pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); - if (!pci_mmcfg_config) - return NULL; - pci_mmcfg_config[0].address = pciexbar & mask; - pci_mmcfg_config[0].pci_segment = 0; - pci_mmcfg_config[0].start_bus_number = 0; - pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1; - } + return NULL; + + if (extend_mmcfg(1) == -1) + return NULL; + + fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1); return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; } @@ -138,22 +157,77 @@ static const char __init *pci_mmcfg_amd_fam10h(void) busnbits = 8; } - pci_mmcfg_config_num = (1 << segnbits); - pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) * - pci_mmcfg_config_num, GFP_KERNEL); - if (!pci_mmcfg_config) + if (extend_mmcfg(1 << segnbits) == -1) return NULL; - for (i = 0; i < (1 << segnbits); i++) { - pci_mmcfg_config[i].address = base + (1<<28) * i; - pci_mmcfg_config[i].pci_segment = i; - pci_mmcfg_config[i].start_bus_number = 0; - pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1; - } + for (i = 0; i < (1 << segnbits); i++) + fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1); return "AMD Family 10h NB"; } +static bool __initdata mcp55_checked; +static const char __init *pci_mmcfg_nvidia_mcp55(void) +{ + int bus; + int mcp55_mmconf_found = 0; + + static const u32 extcfg_regnum = 0x90; + static const u32 extcfg_regsize = 4; + static const u32 extcfg_enable_mask = 1<<31; + static const u32 extcfg_start_mask = 0xff<<16; + static const int extcfg_start_shift = 16; + static const u32 extcfg_size_mask = 0x3<<28; + static const int extcfg_size_shift = 28; + static const int extcfg_sizebus[] = {0x100, 0x80, 0x40, 0x20}; + static const u32 extcfg_base_mask[] = {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff}; + static const int extcfg_base_lshift = 25; + + /* + * do check if amd fam10h already took over + */ + if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked) + return NULL; + + mcp55_checked = true; + for (bus = 0; bus < 256; bus++) { + u64 base; + u32 l, extcfg; + u16 vendor, device; + int start, size_index, end; + + raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), 0, 4, &l); + vendor = l & 0xffff; + device = (l >> 16) & 0xffff; + + if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device) + continue; + + raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), extcfg_regnum, + extcfg_regsize, &extcfg); + + if (!(extcfg & extcfg_enable_mask)) + continue; + + if (extend_mmcfg(1) == -1) + continue; + + size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; + base = extcfg & extcfg_base_mask[size_index]; + /* base could > 4G */ + base <<= extcfg_base_lshift; + start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; + end = start + extcfg_sizebus[size_index] - 1; + fill_one_mmcfg(base, 0, start, end); + mcp55_mmconf_found++; + } + + if (!mcp55_mmconf_found) + return NULL; + + return "nVidia MCP55"; +} + struct pci_mmcfg_hostbridge_probe { u32 bus; u32 devfn; @@ -171,8 +245,52 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { 0x1200, pci_mmcfg_amd_fam10h }, { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, 0x1200, pci_mmcfg_amd_fam10h }, + { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA, + 0x0369, pci_mmcfg_nvidia_mcp55 }, }; +static int __init cmp_mmcfg(const void *x1, const void *x2) +{ + const typeof(pci_mmcfg_config[0]) *m1 = x1; + const typeof(pci_mmcfg_config[0]) *m2 = x2; + int start1, start2; + + start1 = m1->start_bus_number; + start2 = m2->start_bus_number; + + return start1 - start2; +} + +static void __init pci_mmcfg_check_end_bus_number(void) +{ + int i; + typeof(pci_mmcfg_config[0]) *cfg, *cfgx; + + /* sort them at first */ + sort(pci_mmcfg_config, pci_mmcfg_config_num, + sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL); + + /* last one*/ + if (pci_mmcfg_config_num > 0) { + i = pci_mmcfg_config_num - 1; + cfg = &pci_mmcfg_config[i]; + if (cfg->end_bus_number < cfg->start_bus_number) + cfg->end_bus_number = 255; + } + + /* don't overlap please */ + for (i = 0; i < pci_mmcfg_config_num - 1; i++) { + cfg = &pci_mmcfg_config[i]; + cfgx = &pci_mmcfg_config[i+1]; + + if (cfg->end_bus_number < cfg->start_bus_number) + cfg->end_bus_number = 255; + + if (cfg->end_bus_number >= cfgx->start_bus_number) + cfg->end_bus_number = cfgx->start_bus_number - 1; + } +} + static int __init pci_mmcfg_check_hostbridge(void) { u32 l; @@ -186,31 +304,33 @@ static int __init pci_mmcfg_check_hostbridge(void) pci_mmcfg_config_num = 0; pci_mmcfg_config = NULL; - name = NULL; - for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { + for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) { bus = pci_mmcfg_probes[i].bus; devfn = pci_mmcfg_probes[i].devfn; raw_pci_ops->read(0, bus, devfn, 0, 4, &l); vendor = l & 0xffff; device = (l >> 16) & 0xffff; + name = NULL; if (pci_mmcfg_probes[i].vendor == vendor && pci_mmcfg_probes[i].device == device) name = pci_mmcfg_probes[i].probe(); - } - if (name) { - printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n", - name, pci_mmcfg_config_num ? "with" : "without"); + if (name) + printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n", + name); } - return name != NULL; + /* some end_bus_number is crazy, fix it */ + pci_mmcfg_check_end_bus_number(); + + return pci_mmcfg_config_num != 0; } static void __init pci_mmcfg_insert_resources(void) { -#define PCI_MMCFG_RESOURCE_NAME_LEN 19 +#define PCI_MMCFG_RESOURCE_NAME_LEN 24 int i; struct resource *res; char *names; @@ -228,9 +348,10 @@ static void __init pci_mmcfg_insert_resources(void) struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; res->name = names; - snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u", - cfg->pci_segment); - res->start = cfg->address; + snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, + "PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment, + cfg->start_bus_number, cfg->end_bus_number); + res->start = cfg->address + (cfg->start_bus_number << 20); res->end = res->start + (num_buses << 20) - 1; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; insert_resource(&iomem_resource, res); @@ -354,8 +475,6 @@ static void __init pci_mmcfg_reject_broken(int early) (pci_mmcfg_config[0].address == 0)) return; - cfg = &pci_mmcfg_config[0]; - for (i = 0; i < pci_mmcfg_config_num; i++) { int valid = 0; u64 addr, size; @@ -423,10 +542,10 @@ static void __init __pci_mmcfg_init(int early) known_bridge = 1; } - if (!known_bridge) { + if (!known_bridge) acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); - pci_mmcfg_reject_broken(early); - } + + pci_mmcfg_reject_broken(early); if ((pci_mmcfg_config_num == 0) || (pci_mmcfg_config == NULL) || diff --git a/trunk/arch/x86/pci/mmconfig_64.c b/trunk/arch/x86/pci/mmconfig_64.c index 30007ffc8e11..94349f8b2f96 100644 --- a/trunk/arch/x86/pci/mmconfig_64.c +++ b/trunk/arch/x86/pci/mmconfig_64.c @@ -112,13 +112,18 @@ static struct pci_raw_ops pci_mmcfg = { static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg) { void __iomem *addr; - u32 size; - - size = (cfg->end_bus_number + 1) << 20; - addr = ioremap_nocache(cfg->address, size); + u64 start, size; + + start = cfg->start_bus_number; + start <<= 20; + start += cfg->address; + size = cfg->end_bus_number + 1 - cfg->start_bus_number; + size <<= 20; + addr = ioremap_nocache(start, size); if (addr) { printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n", - cfg->address, cfg->address + size - 1); + start, start + size - 1); + addr -= cfg->start_bus_number << 20; } return addr; } @@ -157,7 +162,7 @@ void __init pci_mmcfg_arch_free(void) for (i = 0; i < pci_mmcfg_config_num; ++i) { if (pci_mmcfg_virt[i].virt) { - iounmap(pci_mmcfg_virt[i].virt); + iounmap(pci_mmcfg_virt[i].virt + (pci_mmcfg_virt[i].cfg->start_bus_number << 20)); pci_mmcfg_virt[i].virt = NULL; pci_mmcfg_virt[i].cfg = NULL; } diff --git a/trunk/arch/x86/power/cpu_32.c b/trunk/arch/x86/power/cpu_32.c index 274d06082f48..ce702c5b3a2c 100644 --- a/trunk/arch/x86/power/cpu_32.c +++ b/trunk/arch/x86/power/cpu_32.c @@ -12,6 +12,7 @@ #include #include #include +#include static struct saved_context saved_context; diff --git a/trunk/arch/x86/power/cpu_64.c b/trunk/arch/x86/power/cpu_64.c index e3b6cf70d62c..5343540f2607 100644 --- a/trunk/arch/x86/power/cpu_64.c +++ b/trunk/arch/x86/power/cpu_64.c @@ -15,6 +15,7 @@ #include #include #include +#include static void fix_processor_context(void); diff --git a/trunk/arch/x86/power/hibernate_64.c b/trunk/arch/x86/power/hibernate_64.c index 6dd000dd7933..65fdc86e923f 100644 --- a/trunk/arch/x86/power/hibernate_64.c +++ b/trunk/arch/x86/power/hibernate_64.c @@ -14,6 +14,7 @@ #include #include #include +#include /* References to section boundaries */ extern const void __nosave_begin, __nosave_end; diff --git a/trunk/arch/xtensa/kernel/process.c b/trunk/arch/xtensa/kernel/process.c index 9185597eb6a0..031f36685710 100644 --- a/trunk/arch/xtensa/kernel/process.c +++ b/trunk/arch/xtensa/kernel/process.c @@ -172,7 +172,7 @@ void prepare_to_copy(struct task_struct *tsk) * childregs. */ -int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, +int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long unused, struct task_struct * p, struct pt_regs * regs) { diff --git a/trunk/arch/xtensa/platforms/iss/console.c b/trunk/arch/xtensa/platforms/iss/console.c index 25d46c84eb08..4c559cf7da2d 100644 --- a/trunk/arch/xtensa/platforms/iss/console.c +++ b/trunk/arch/xtensa/platforms/iss/console.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -176,22 +177,24 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) /* Stub, once again.. */ } -static int rs_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int rs_proc_show(struct seq_file *m, void *v) { - int len = 0; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); - *eof = 1; - - if (off >= len + begin) - return 0; + seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); + return 0; +} - *start = page + (off - begin); - return ((count < begin + len - off) ? count : begin + len - off); +static int rs_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, rs_proc_show, NULL); } +static const struct file_operations rs_proc_fops = { + .owner = THIS_MODULE, + .open = rs_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; static struct tty_operations serial_ops = { .open = rs_open, @@ -203,7 +206,7 @@ static struct tty_operations serial_ops = { .chars_in_buffer = rs_chars_in_buffer, .hangup = rs_hangup, .wait_until_sent = rs_wait_until_sent, - .read_proc = rs_read_proc + .proc_fops = &rs_proc_fops, }; int __init rs_init(void) diff --git a/trunk/crypto/shash.c b/trunk/crypto/shash.c index 7a659733f94a..2ccc8b0076ce 100644 --- a/trunk/crypto/shash.c +++ b/trunk/crypto/shash.c @@ -77,6 +77,9 @@ static int shash_update_unaligned(struct shash_desc *desc, const u8 *data, u8 buf[shash_align_buffer_size(unaligned_len, alignmask)] __attribute__ ((aligned)); + if (unaligned_len > len) + unaligned_len = len; + memcpy(buf, data, unaligned_len); return shash->update(desc, buf, unaligned_len) ?: diff --git a/trunk/crypto/xor.c b/trunk/crypto/xor.c index b2e6db075e49..996b6ee57d9e 100644 --- a/trunk/crypto/xor.c +++ b/trunk/crypto/xor.c @@ -18,8 +18,8 @@ #define BH_TRACE 0 #include -#include #include +#include #include /* The xor routines to use. */ diff --git a/trunk/drivers/acpi/pci_root.c b/trunk/drivers/acpi/pci_root.c index 5b38a026d122..196f97d00956 100644 --- a/trunk/drivers/acpi/pci_root.c +++ b/trunk/drivers/acpi/pci_root.c @@ -66,11 +66,18 @@ struct acpi_pci_root { struct acpi_device * device; struct acpi_pci_id id; struct pci_bus *bus; + + u32 osc_support_set; /* _OSC state of support bits */ + u32 osc_control_set; /* _OSC state of control bits */ + u32 osc_control_qry; /* the latest _OSC query result */ + + u32 osc_queried:1; /* has _OSC control been queried? */ }; static LIST_HEAD(acpi_pci_roots); static struct acpi_pci_driver *sub_driver; +static DEFINE_MUTEX(osc_lock); int acpi_pci_register_driver(struct acpi_pci_driver *driver) { @@ -185,6 +192,175 @@ static void acpi_pci_bridge_scan(struct acpi_device *device) } } +static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, + 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; + +static acpi_status acpi_pci_run_osc(acpi_handle handle, + const u32 *capbuf, u32 *retval) +{ + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[4]; + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *out_obj; + u32 errors; + + /* Setting up input parameters */ + input.count = 4; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = 16; + in_params[0].buffer.pointer = OSC_UUID; + in_params[1].type = ACPI_TYPE_INTEGER; + in_params[1].integer.value = 1; + in_params[2].type = ACPI_TYPE_INTEGER; + in_params[2].integer.value = 3; + in_params[3].type = ACPI_TYPE_BUFFER; + in_params[3].buffer.length = 12; + in_params[3].buffer.pointer = (u8 *)capbuf; + + status = acpi_evaluate_object(handle, "_OSC", &input, &output); + if (ACPI_FAILURE(status)) + return status; + + if (!output.length) + return AE_NULL_OBJECT; + + out_obj = output.pointer; + if (out_obj->type != ACPI_TYPE_BUFFER) { + printk(KERN_DEBUG "_OSC evaluation returned wrong type\n"); + status = AE_TYPE; + goto out_kfree; + } + /* Need to ignore the bit0 in result code */ + errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); + if (errors) { + if (errors & OSC_REQUEST_ERROR) + printk(KERN_DEBUG "_OSC request failed\n"); + if (errors & OSC_INVALID_UUID_ERROR) + printk(KERN_DEBUG "_OSC invalid UUID\n"); + if (errors & OSC_INVALID_REVISION_ERROR) + printk(KERN_DEBUG "_OSC invalid revision\n"); + if (errors & OSC_CAPABILITIES_MASK_ERROR) { + if (capbuf[OSC_QUERY_TYPE] & OSC_QUERY_ENABLE) + goto out_success; + printk(KERN_DEBUG + "Firmware did not grant requested _OSC control\n"); + status = AE_SUPPORT; + goto out_kfree; + } + status = AE_ERROR; + goto out_kfree; + } +out_success: + *retval = *((u32 *)(out_obj->buffer.pointer + 8)); + status = AE_OK; + +out_kfree: + kfree(output.pointer); + return status; +} + +static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags) +{ + acpi_status status; + u32 support_set, result, capbuf[3]; + + /* do _OSC query for all possible controls */ + support_set = root->osc_support_set | (flags & OSC_SUPPORT_MASKS); + capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; + capbuf[OSC_SUPPORT_TYPE] = support_set; + capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; + + status = acpi_pci_run_osc(root->device->handle, capbuf, &result); + if (ACPI_SUCCESS(status)) { + root->osc_support_set = support_set; + root->osc_control_qry = result; + root->osc_queried = 1; + } + return status; +} + +static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(root->device->handle, "_OSC", &tmp); + if (ACPI_FAILURE(status)) + return status; + mutex_lock(&osc_lock); + status = acpi_pci_query_osc(root, flags); + mutex_unlock(&osc_lock); + return status; +} + +static struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) +{ + struct acpi_pci_root *root; + list_for_each_entry(root, &acpi_pci_roots, node) { + if (root->device->handle == handle) + return root; + } + return NULL; +} + +/** + * acpi_pci_osc_control_set - commit requested control to Firmware + * @handle: acpi_handle for the target ACPI object + * @flags: driver's requested control bits + * + * Attempt to take control from Firmware on requested control bits. + **/ +acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) +{ + acpi_status status; + u32 control_req, result, capbuf[3]; + acpi_handle tmp; + struct acpi_pci_root *root; + + status = acpi_get_handle(handle, "_OSC", &tmp); + if (ACPI_FAILURE(status)) + return status; + + control_req = (flags & OSC_CONTROL_MASKS); + if (!control_req) + return AE_TYPE; + + root = acpi_pci_find_root(handle); + if (!root) + return AE_NOT_EXIST; + + mutex_lock(&osc_lock); + /* No need to evaluate _OSC if the control was already granted. */ + if ((root->osc_control_set & control_req) == control_req) + goto out; + + /* Need to query controls first before requesting them */ + if (!root->osc_queried) { + status = acpi_pci_query_osc(root, root->osc_support_set); + if (ACPI_FAILURE(status)) + goto out; + } + if ((root->osc_control_qry & control_req) != control_req) { + printk(KERN_DEBUG + "Firmware did not grant requested _OSC control\n"); + status = AE_SUPPORT; + goto out; + } + + capbuf[OSC_QUERY_TYPE] = 0; + capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set; + capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req; + status = acpi_pci_run_osc(handle, capbuf, &result); + if (ACPI_SUCCESS(status)) + root->osc_control_set = result; +out: + mutex_unlock(&osc_lock); + return status; +} +EXPORT_SYMBOL(acpi_pci_osc_control_set); + static int __devinit acpi_pci_root_add(struct acpi_device *device) { int result = 0; @@ -217,7 +393,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) * PCI domains, so we indicate this in _OSC support capabilities. */ flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT; - pci_acpi_osc_support(device->handle, flags); + acpi_pci_osc_support(root, flags); /* * Segment @@ -353,7 +529,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (pci_msi_enabled()) flags |= OSC_MSI_SUPPORT; if (flags != base_flags) - pci_acpi_osc_support(device->handle, flags); + acpi_pci_osc_support(root, flags); end: if (result) { diff --git a/trunk/drivers/auxdisplay/Kconfig b/trunk/drivers/auxdisplay/Kconfig index 14b9d5f4c203..c07e725ea93d 100644 --- a/trunk/drivers/auxdisplay/Kconfig +++ b/trunk/drivers/auxdisplay/Kconfig @@ -6,7 +6,6 @@ # menuconfig AUXDISPLAY - depends on PARPORT bool "Auxiliary Display support" ---help--- Say Y here to get to see options for auxiliary display drivers. @@ -14,7 +13,7 @@ menuconfig AUXDISPLAY If you say N, all options in this submenu will be skipped and disabled. -if AUXDISPLAY && PARPORT +if AUXDISPLAY config KS0108 tristate "KS0108 LCD Controller" diff --git a/trunk/drivers/base/iommu.c b/trunk/drivers/base/iommu.c index c2d1eed90376..9f0e672f4be8 100644 --- a/trunk/drivers/base/iommu.c +++ b/trunk/drivers/base/iommu.c @@ -98,3 +98,10 @@ phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, return iommu_ops->iova_to_phys(domain, iova); } EXPORT_SYMBOL_GPL(iommu_iova_to_phys); + +int iommu_domain_has_cap(struct iommu_domain *domain, + unsigned long cap) +{ + return iommu_ops->domain_has_cap(domain, cap); +} +EXPORT_SYMBOL_GPL(iommu_domain_has_cap); diff --git a/trunk/drivers/block/aoe/aoecmd.c b/trunk/drivers/block/aoe/aoecmd.c index 45c5a33daf49..31693bc24444 100644 --- a/trunk/drivers/block/aoe/aoecmd.c +++ b/trunk/drivers/block/aoe/aoecmd.c @@ -4,6 +4,7 @@ * Filesystem request handling methods */ +#include #include #include #include @@ -267,7 +268,7 @@ aoecmd_ata_rw(struct aoedev *d) writebit = 0; } - ah->cmdstat = WIN_READ | writebit | extbit; + ah->cmdstat = ATA_CMD_PIO_READ | writebit | extbit; /* mark all tracking fields and load out */ buf->nframesout += 1; @@ -362,10 +363,10 @@ resend(struct aoedev *d, struct aoetgt *t, struct frame *f) switch (ah->cmdstat) { default: break; - case WIN_READ: - case WIN_READ_EXT: - case WIN_WRITE: - case WIN_WRITE_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PIO_WRITE: + case ATA_CMD_PIO_WRITE_EXT: put_lba(ah, f->lba); n = f->bcnt; @@ -812,8 +813,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) d->htgt = NULL; n = ahout->scnt << 9; switch (ahout->cmdstat) { - case WIN_READ: - case WIN_READ_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_READ_EXT: if (skb->len - sizeof *hin - sizeof *ahin < n) { printk(KERN_ERR "aoe: %s. skb->len=%d need=%ld\n", @@ -823,8 +824,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) return; } memcpy(f->bufaddr, ahin+1, n); - case WIN_WRITE: - case WIN_WRITE_EXT: + case ATA_CMD_PIO_WRITE: + case ATA_CMD_PIO_WRITE_EXT: ifp = getif(t, skb->dev); if (ifp) { ifp->lost = 0; @@ -838,7 +839,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) goto xmit; } break; - case WIN_IDENTIFY: + case ATA_CMD_ID_ATA: if (skb->len - sizeof *hin - sizeof *ahin < 512) { printk(KERN_INFO "aoe: runt data size in ataid. skb->len=%d\n", @@ -914,7 +915,7 @@ aoecmd_ata_id(struct aoedev *d) /* set up ata header */ ah->scnt = 1; - ah->cmdstat = WIN_IDENTIFY; + ah->cmdstat = ATA_CMD_ID_ATA; ah->lba3 = 0xa0; skb->dev = t->ifp->nd; diff --git a/trunk/drivers/block/floppy.c b/trunk/drivers/block/floppy.c index c2c95e614506..1300df6f1642 100644 --- a/trunk/drivers/block/floppy.c +++ b/trunk/drivers/block/floppy.c @@ -177,6 +177,7 @@ static int print_unex = 1; #include #include #include +#include #include /* for invalidate_buffers() */ #include @@ -4597,6 +4598,13 @@ MODULE_AUTHOR("Alain L. Knaff"); MODULE_SUPPORTED_DEVICE("fd"); MODULE_LICENSE("GPL"); +/* This doesn't actually get used other than for module information */ +static const struct pnp_device_id floppy_pnpids[] = { + { "PNP0700", 0 }, + { } +}; +MODULE_DEVICE_TABLE(pnp, floppy_pnpids); + #else __setup("floppy=", floppy_setup); diff --git a/trunk/drivers/block/hd.c b/trunk/drivers/block/hd.c index 482c0c4b964f..3c11f062a18c 100644 --- a/trunk/drivers/block/hd.c +++ b/trunk/drivers/block/hd.c @@ -42,6 +42,8 @@ #include #include +#define HD_IRQ 14 + #define REALLY_SLOW_IO #include #include diff --git a/trunk/drivers/block/loop.c b/trunk/drivers/block/loop.c index 2621ed2ce6d2..40b17d3b55a1 100644 --- a/trunk/drivers/block/loop.c +++ b/trunk/drivers/block/loop.c @@ -1192,6 +1192,30 @@ loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) { return err; } +static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev) +{ + int err; + sector_t sec; + loff_t sz; + + err = -ENXIO; + if (unlikely(lo->lo_state != Lo_bound)) + goto out; + err = figure_loop_size(lo); + if (unlikely(err)) + goto out; + sec = get_capacity(lo->lo_disk); + /* the width of sector_t may be narrow for bit-shift */ + sz = sec; + sz <<= 9; + mutex_lock(&bdev->bd_mutex); + bd_set_size(bdev, sz); + mutex_unlock(&bdev->bd_mutex); + + out: + return err; +} + static int lo_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { @@ -1224,6 +1248,11 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, case LOOP_GET_STATUS64: err = loop_get_status64(lo, (struct loop_info64 __user *) arg); break; + case LOOP_SET_CAPACITY: + err = -EPERM; + if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) + err = loop_set_capacity(lo, bdev); + break; default: err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; } @@ -1371,6 +1400,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, lo, (struct compat_loop_info __user *) arg); mutex_unlock(&lo->lo_ctl_mutex); break; + case LOOP_SET_CAPACITY: case LOOP_CLR_FD: case LOOP_GET_STATUS64: case LOOP_SET_STATUS64: diff --git a/trunk/drivers/block/nbd.c b/trunk/drivers/block/nbd.c index 8299e2d3b611..4d6de4f15ccb 100644 --- a/trunk/drivers/block/nbd.c +++ b/trunk/drivers/block/nbd.c @@ -4,7 +4,7 @@ * Note that you can not swap over this thing, yet. Seems to work but * deadlocks sometimes - you can not swap over TCP in general. * - * Copyright 1997-2000 Pavel Machek + * Copyright 1997-2000, 2008 Pavel Machek * Parts copyright 2001 Steven Whitehouse * * This file is released under GPLv2 or later. @@ -276,7 +276,7 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req) return 0; error_out: - return 1; + return -EIO; } static struct request *nbd_find_request(struct nbd_device *lo, @@ -467,9 +467,7 @@ static void nbd_handle_req(struct nbd_device *lo, struct request *req) mutex_unlock(&lo->tx_lock); printk(KERN_ERR "%s: Attempted send on closed socket\n", lo->disk->disk_name); - req->errors++; - nbd_end_request(req); - return; + goto error_out; } lo->active_req = req; @@ -531,7 +529,7 @@ static int nbd_thread(void *data) * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } */ -static void do_nbd_request(struct request_queue * q) +static void do_nbd_request(struct request_queue *q) { struct request *req; @@ -568,27 +566,17 @@ static void do_nbd_request(struct request_queue * q) } } -static int nbd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct nbd_device *lo = bdev->bd_disk->private_data; - struct file *file; - int error; - struct request sreq ; - struct task_struct *thread; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - BUG_ON(lo->magic != LO_MAGIC); - - /* Anyone capable of this syscall can do *real bad* things */ - dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n", - lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); +/* Must be called with tx_lock held */ +static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo, + unsigned int cmd, unsigned long arg) +{ switch (cmd) { - case NBD_DISCONNECT: + case NBD_DISCONNECT: { + struct request sreq; + printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); + blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; nbd_cmd(&sreq) = NBD_CMD_DISC; @@ -599,29 +587,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, */ sreq.sector = 0; sreq.nr_sectors = 0; - if (!lo->sock) + if (!lo->sock) return -EINVAL; - mutex_lock(&lo->tx_lock); - nbd_send_req(lo, &sreq); - mutex_unlock(&lo->tx_lock); + nbd_send_req(lo, &sreq); return 0; + } - case NBD_CLEAR_SOCK: - error = 0; - mutex_lock(&lo->tx_lock); + case NBD_CLEAR_SOCK: { + struct file *file; + lo->sock = NULL; - mutex_unlock(&lo->tx_lock); file = lo->file; lo->file = NULL; nbd_clear_que(lo); BUG_ON(!list_empty(&lo->queue_head)); if (file) fput(file); - return error; - case NBD_SET_SOCK: + return 0; + } + + case NBD_SET_SOCK: { + struct file *file; if (lo->file) return -EBUSY; - error = -EINVAL; file = fget(arg); if (file) { struct inode *inode = file->f_path.dentry->d_inode; @@ -630,12 +618,14 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, lo->sock = SOCKET_I(inode); if (max_part > 0) bdev->bd_invalidated = 1; - error = 0; + return 0; } else { fput(file); } } - return error; + return -EINVAL; + } + case NBD_SET_BLKSIZE: lo->blksize = arg; lo->bytesize &= ~(lo->blksize-1); @@ -643,35 +633,50 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; + case NBD_SET_SIZE: lo->bytesize = arg & ~(lo->blksize-1); bdev->bd_inode->i_size = lo->bytesize; set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; + case NBD_SET_TIMEOUT: lo->xmit_timeout = arg * HZ; return 0; + case NBD_SET_SIZE_BLOCKS: lo->bytesize = ((u64) arg) * lo->blksize; bdev->bd_inode->i_size = lo->bytesize; set_blocksize(bdev, lo->blksize); set_capacity(lo->disk, lo->bytesize >> 9); return 0; - case NBD_DO_IT: + + case NBD_DO_IT: { + struct task_struct *thread; + struct file *file; + int error; + if (lo->pid) return -EBUSY; if (!lo->file) return -EINVAL; + + mutex_unlock(&lo->tx_lock); + thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); - if (IS_ERR(thread)) + if (IS_ERR(thread)) { + mutex_lock(&lo->tx_lock); return PTR_ERR(thread); + } wake_up_process(thread); error = nbd_do_it(lo); kthread_stop(thread); + + mutex_lock(&lo->tx_lock); if (error) return error; - sock_shutdown(lo, 1); + sock_shutdown(lo, 0); file = lo->file; lo->file = NULL; nbd_clear_que(lo); @@ -684,6 +689,8 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, if (max_part > 0) ioctl_by_bdev(bdev, BLKRRPART, 0); return lo->harderror; + } + case NBD_CLEAR_QUE: /* * This is for compatibility only. The queue is always cleared @@ -691,6 +698,7 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, */ BUG_ON(!lo->sock && !list_empty(&lo->queue_head)); return 0; + case NBD_PRINT_DEBUG: printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n", bdev->bd_disk->disk_name, @@ -698,7 +706,29 @@ static int nbd_ioctl(struct block_device *bdev, fmode_t mode, &lo->queue_head); return 0; } - return -EINVAL; + return -ENOTTY; +} + +static int nbd_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct nbd_device *lo = bdev->bd_disk->private_data; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + BUG_ON(lo->magic != LO_MAGIC); + + /* Anyone capable of this syscall can do *real bad* things */ + dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n", + lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg); + + mutex_lock(&lo->tx_lock); + error = __nbd_ioctl(bdev, lo, cmd, arg); + mutex_unlock(&lo->tx_lock); + + return error; } static struct block_device_operations nbd_fops = diff --git a/trunk/drivers/block/xsysace.c b/trunk/drivers/block/xsysace.c index 119be3442f28..6cccdc3f5220 100644 --- a/trunk/drivers/block/xsysace.c +++ b/trunk/drivers/block/xsysace.c @@ -89,6 +89,7 @@ #include #include #include +#include #include #include #if defined(CONFIG_OF) @@ -208,7 +209,7 @@ struct ace_device { struct gendisk *gd; /* Inserted CF card parameters */ - struct hd_driveid cf_id; + u16 cf_id[ATA_ID_WORDS]; }; static int ace_major; @@ -402,21 +403,14 @@ static void ace_dump_regs(struct ace_device *ace) ace_in32(ace, ACE_CFGLBA), ace_in(ace, ACE_FATSTAT)); } -void ace_fix_driveid(struct hd_driveid *id) +void ace_fix_driveid(u16 *id) { #if defined(__BIG_ENDIAN) - u16 *buf = (void *)id; int i; /* All half words have wrong byte order; swap the bytes */ - for (i = 0; i < sizeof(struct hd_driveid); i += 2, buf++) - *buf = le16_to_cpu(*buf); - - /* Some of the data values are 32bit; swap the half words */ - id->lba_capacity = ((id->lba_capacity >> 16) & 0x0000FFFF) | - ((id->lba_capacity << 16) & 0xFFFF0000); - id->spg = ((id->spg >> 16) & 0x0000FFFF) | - ((id->spg << 16) & 0xFFFF0000); + for (i = 0; i < ATA_ID_WORDS; i++, id++) + *id = le16_to_cpu(*id); #endif } @@ -614,7 +608,7 @@ static void ace_fsm_dostate(struct ace_device *ace) break; case ACE_FSM_STATE_IDENTIFY_COMPLETE: - ace_fix_driveid(&ace->cf_id); + ace_fix_driveid(&ace->cf_id[0]); ace_dump_mem(&ace->cf_id, 512); /* Debug: Dump out disk ID */ if (ace->data_result) { @@ -627,9 +621,10 @@ static void ace_fsm_dostate(struct ace_device *ace) ace->media_change = 0; /* Record disk parameters */ - set_capacity(ace->gd, ace->cf_id.lba_capacity); + set_capacity(ace->gd, + ata_id_u32(&ace->cf_id, ATA_ID_LBA_CAPACITY)); dev_info(ace->dev, "capacity: %i sectors\n", - ace->cf_id.lba_capacity); + ata_id_u32(&ace->cf_id, ATA_ID_LBA_CAPACITY)); } /* We're done, drop to IDLE state and notify waiters */ @@ -928,12 +923,13 @@ static int ace_release(struct gendisk *disk, fmode_t mode) static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct ace_device *ace = bdev->bd_disk->private_data; + u16 *cf_id = &ace->cf_id[0]; dev_dbg(ace->dev, "ace_getgeo()\n"); - geo->heads = ace->cf_id.heads; - geo->sectors = ace->cf_id.sectors; - geo->cylinders = ace->cf_id.cyls; + geo->heads = cf_id[ATA_ID_HEADS]; + geo->sectors = cf_id[ATA_ID_SECTORS]; + geo->cylinders = cf_id[ATA_ID_CYLS]; return 0; } diff --git a/trunk/drivers/char/amiserial.c b/trunk/drivers/char/amiserial.c index a58869ea8513..fd3ebd1be570 100644 --- a/trunk/drivers/char/amiserial.c +++ b/trunk/drivers/char/amiserial.c @@ -79,6 +79,7 @@ static char *serial_version = "4.30"; #include #include #include +#include #include #include #include @@ -1825,14 +1826,13 @@ static int rs_open(struct tty_struct *tty, struct file * filp) * /proc fs routines.... */ -static inline int line_info(char *buf, struct serial_state *state) +static inline void line_info(struct seq_file *m, struct serial_state *state) { struct async_struct *info = state->info, scr_info; char stat_buf[30], control, status; - int ret; unsigned long flags; - ret = sprintf(buf, "%d: uart:amiga_builtin",state->line); + seq_printf(m, "%d: uart:amiga_builtin",state->line); /* * Figure out the current RS-232 lines @@ -1864,55 +1864,49 @@ static inline int line_info(char *buf, struct serial_state *state) strcat(stat_buf, "|CD"); if (info->quot) { - ret += sprintf(buf+ret, " baud:%d", - state->baud_base / info->quot); + seq_printf(m, " baud:%d", state->baud_base / info->quot); } - ret += sprintf(buf+ret, " tx:%d rx:%d", - state->icount.tx, state->icount.rx); + seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx); if (state->icount.frame) - ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + seq_printf(m, " fe:%d", state->icount.frame); if (state->icount.parity) - ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + seq_printf(m, " pe:%d", state->icount.parity); if (state->icount.brk) - ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + seq_printf(m, " brk:%d", state->icount.brk); if (state->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + seq_printf(m, " oe:%d", state->icount.overrun); /* * Last thing is the RS-232 status lines */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); - return ret; + seq_printf(m, " %s\n", stat_buf+1); } -static int rs_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int rs_proc_show(struct seq_file *m, void *v) { - int len = 0, l; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); - l = line_info(page + len, &rs_table[0]); - len += l; - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); + seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); + line_info(m, &rs_table[0]); + return 0; } +static int rs_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, rs_proc_show, NULL); +} + +static const struct file_operations rs_proc_fops = { + .owner = THIS_MODULE, + .open = rs_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * --------------------------------------------------------------------- * rs_init() and friends @@ -1951,9 +1945,9 @@ static const struct tty_operations serial_ops = { .break_ctl = rs_break, .send_xchar = rs_send_xchar, .wait_until_sent = rs_wait_until_sent, - .read_proc = rs_read_proc, .tiocmget = rs_tiocmget, .tiocmset = rs_tiocmset, + .proc_fops = &rs_proc_fops, }; /* diff --git a/trunk/drivers/char/cyclades.c b/trunk/drivers/char/cyclades.c index 6a59f72a9c21..272db0e2b491 100644 --- a/trunk/drivers/char/cyclades.c +++ b/trunk/drivers/char/cyclades.c @@ -657,6 +657,7 @@ #include #include +#include static void cy_throttle(struct tty_struct *tty); static void cy_send_xchar(struct tty_struct *tty, char ch); @@ -868,8 +869,6 @@ static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32); static unsigned detect_isa_irq(void __iomem *); #endif /* CONFIG_ISA */ -static int cyclades_get_proc_info(char *, char **, off_t, int, int *, void *); - #ifndef CONFIG_CYZ_INTR static void cyz_poll(unsigned long); @@ -5216,31 +5215,22 @@ static struct pci_driver cy_pci_driver = { }; #endif -static int -cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, - int *eof, void *data) +static int cyclades_proc_show(struct seq_file *m, void *v) { struct cyclades_port *info; unsigned int i, j; - int len = 0; - off_t begin = 0; - off_t pos = 0; - int size; __u32 cur_jifs = jiffies; - size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn " + seq_puts(m, "Dev TimeOpen BytesOut IdleOut BytesIn " "IdleIn Overruns Ldisc\n"); - pos += size; - len += size; - /* Output one line for each known port */ for (i = 0; i < NR_CARDS; i++) for (j = 0; j < cy_card[i].nports; j++) { info = &cy_card[i].ports[j]; if (info->port.count) - size = sprintf(buf + len, "%3d %8lu %10lu %8lu " + seq_printf(m, "%3d %8lu %10lu %8lu " "%10lu %8lu %9lu %6ld\n", info->line, (cur_jifs - info->idle_stats.in_use) / HZ, info->idle_stats.xmit_bytes, @@ -5251,30 +5241,26 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, /* FIXME: double check locking */ (long)info->port.tty->ldisc.ops->num); else - size = sprintf(buf + len, "%3d %8lu %10lu %8lu " + seq_printf(m, "%3d %8lu %10lu %8lu " "%10lu %8lu %9lu %6ld\n", info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto done; } - *eof = 1; -done: - *start = buf + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - len = length; /* Ending slop */ - if (len < 0) - len = 0; - return len; + return 0; +} + +static int cyclades_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, cyclades_proc_show, NULL); } +static const struct file_operations cyclades_proc_fops = { + .owner = THIS_MODULE, + .open = cyclades_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* The serial driver boot-time initialization code! Hardware I/O ports are mapped to character special devices on a first found, first allocated manner. That is, this code searches @@ -5311,9 +5297,9 @@ static const struct tty_operations cy_ops = { .hangup = cy_hangup, .break_ctl = cy_break, .wait_until_sent = cy_wait_until_sent, - .read_proc = cyclades_get_proc_info, .tiocmget = cy_tiocmget, .tiocmset = cy_tiocmset, + .proc_fops = &cyclades_proc_fops, }; static int __init cy_init(void) diff --git a/trunk/drivers/char/hpet.c b/trunk/drivers/char/hpet.c index 32b8bbf5003e..50dfa3bc71ce 100644 --- a/trunk/drivers/char/hpet.c +++ b/trunk/drivers/char/hpet.c @@ -713,7 +713,7 @@ static struct ctl_table_header *sysctl_header; */ #define TICK_CALIBRATE (1000UL) -static unsigned long hpet_calibrate(struct hpets *hpetp) +static unsigned long __hpet_calibrate(struct hpets *hpetp) { struct hpet_timer __iomem *timer = NULL; unsigned long t, m, count, i, flags, start; @@ -750,6 +750,26 @@ static unsigned long hpet_calibrate(struct hpets *hpetp) return (m - start) / i; } +static unsigned long hpet_calibrate(struct hpets *hpetp) +{ + unsigned long ret = -1; + unsigned long tmp; + + /* + * Try to calibrate until return value becomes stable small value. + * If SMI interruption occurs in calibration loop, the return value + * will be big. This avoids its impact. + */ + for ( ; ; ) { + tmp = __hpet_calibrate(hpetp); + if (ret <= tmp) + break; + ret = tmp; + } + + return ret; +} + int hpet_alloc(struct hpet_data *hdp) { u64 cap, mcfg; diff --git a/trunk/drivers/char/hw_random/timeriomem-rng.c b/trunk/drivers/char/hw_random/timeriomem-rng.c index 10ad41be5897..dcd352ad0e7f 100644 --- a/trunk/drivers/char/hw_random/timeriomem-rng.c +++ b/trunk/drivers/char/hw_random/timeriomem-rng.c @@ -90,10 +90,30 @@ static struct hwrng timeriomem_rng_ops = { static int __init timeriomem_rng_probe(struct platform_device *pdev) { + struct resource *res, *mem; int ret; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) + return -ENOENT; + + mem = request_mem_region(res->start, res->end - res->start + 1, + pdev->name); + if (mem == NULL) + return -EBUSY; + + dev_set_drvdata(&pdev->dev, mem); + timeriomem_rng_data = pdev->dev.platform_data; + timeriomem_rng_data->address = ioremap(res->start, + res->end - res->start + 1); + if (!timeriomem_rng_data->address) { + ret = -ENOMEM; + goto err_ioremap; + } + if (timeriomem_rng_data->period != 0 && usecs_to_jiffies(timeriomem_rng_data->period) > 0) { timeriomem_rng_timer.expires = jiffies; @@ -104,23 +124,34 @@ static int __init timeriomem_rng_probe(struct platform_device *pdev) timeriomem_rng_data->present = 1; ret = hwrng_register(&timeriomem_rng_ops); - if (ret) { - dev_err(&pdev->dev, "problem registering\n"); - return ret; - } + if (ret) + goto err_register; dev_info(&pdev->dev, "32bits from 0x%p @ %dus\n", timeriomem_rng_data->address, timeriomem_rng_data->period); return 0; + +err_register: + dev_err(&pdev->dev, "problem registering\n"); + iounmap(timeriomem_rng_data->address); +err_ioremap: + release_resource(mem); + + return ret; } static int __devexit timeriomem_rng_remove(struct platform_device *pdev) { + struct resource *mem = dev_get_drvdata(&pdev->dev); + del_timer_sync(&timeriomem_rng_timer); hwrng_unregister(&timeriomem_rng_ops); + iounmap(timeriomem_rng_data->address); + release_resource(mem); + return 0; } diff --git a/trunk/drivers/char/ip2/ip2main.c b/trunk/drivers/char/ip2/ip2main.c index 70e0ebc30bd0..afd9247cf082 100644 --- a/trunk/drivers/char/ip2/ip2main.c +++ b/trunk/drivers/char/ip2/ip2main.c @@ -139,7 +139,7 @@ #include static const struct file_operations ip2mem_proc_fops; -static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); +static const struct file_operations ip2_proc_fops; /********************/ /* Type Definitions */ @@ -446,9 +446,9 @@ static const struct tty_operations ip2_ops = { .stop = ip2_stop, .start = ip2_start, .hangup = ip2_hangup, - .read_proc = ip2_read_proc, .tiocmget = ip2_tiocmget, .tiocmset = ip2_tiocmset, + .proc_fops = &ip2_proc_fops, }; /******************************************************************************/ @@ -3029,19 +3029,17 @@ static const struct file_operations ip2mem_proc_fops = { * different sources including ip2mkdev.c and a couple of other drivers. * The bugs are all mine. :-) =mhw= */ -static int ip2_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int ip2_proc_show(struct seq_file *m, void *v) { int i, j, box; - int len = 0; int boxes = 0; int ports = 0; int tports = 0; - off_t begin = 0; i2eBordStrPtr pB; + char *sep; - len += sprintf(page, "ip2info: 1.0 driver: %s\n", pcVersion ); - len += sprintf(page+len, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n", + seq_printf(m, "ip2info: 1.0 driver: %s\n", pcVersion); + seq_printf(m, "Driver: SMajor=%d CMajor=%d IMajor=%d MaxBoards=%d MaxBoxes=%d MaxPorts=%d\n", IP2_TTY_MAJOR, IP2_CALLOUT_MAJOR, IP2_IPL_MAJOR, IP2_MAX_BOARDS, ABS_MAX_BOXES, ABS_BIGGEST_BOX); @@ -3053,7 +3051,8 @@ static int ip2_read_proc(char *page, char **start, off_t off, switch( pB->i2ePom.e.porID & ~POR_ID_RESERVED ) { case POR_ID_FIIEX: - len += sprintf( page+len, "Board %d: EX ports=", i ); + seq_printf(m, "Board %d: EX ports=", i); + sep = ""; for( box = 0; box < ABS_MAX_BOXES; ++box ) { ports = 0; @@ -3065,79 +3064,74 @@ static int ip2_read_proc(char *page, char **start, off_t off, ++ports; } } - len += sprintf( page+len, "%d,", ports ); + seq_printf(m, "%s%d", sep, ports); + sep = ","; tports += ports; } - - --len; /* Backup over that last comma */ - - len += sprintf( page+len, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8 ); + seq_printf(m, " boxes=%d width=%d", boxes, pB->i2eDataWidth16 ? 16 : 8); break; case POR_ID_II_4: - len += sprintf(page+len, "Board %d: ISA-4 ports=4 boxes=1", i ); + seq_printf(m, "Board %d: ISA-4 ports=4 boxes=1", i); tports = ports = 4; break; case POR_ID_II_8: - len += sprintf(page+len, "Board %d: ISA-8-std ports=8 boxes=1", i ); + seq_printf(m, "Board %d: ISA-8-std ports=8 boxes=1", i); tports = ports = 8; break; case POR_ID_II_8R: - len += sprintf(page+len, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i ); + seq_printf(m, "Board %d: ISA-8-RJ11 ports=8 boxes=1", i); tports = ports = 8; break; default: - len += sprintf(page+len, "Board %d: unknown", i ); + seq_printf(m, "Board %d: unknown", i); /* Don't try and probe for minor numbers */ tports = ports = 0; } } else { /* Don't try and probe for minor numbers */ - len += sprintf(page+len, "Board %d: vacant", i ); + seq_printf(m, "Board %d: vacant", i); tports = ports = 0; } if( tports ) { - len += sprintf(page+len, " minors=" ); - + seq_puts(m, " minors="); + sep = ""; for ( box = 0; box < ABS_MAX_BOXES; ++box ) { for ( j = 0; j < ABS_BIGGEST_BOX; ++j ) { if ( pB->i2eChannelMap[box] & (1 << j) ) { - len += sprintf (page+len,"%d,", + seq_printf(m, "%s%d", sep, j + ABS_BIGGEST_BOX * (box+i*ABS_MAX_BOXES)); + sep = ","; } } } - - page[ len - 1 ] = '\n'; /* Overwrite that last comma */ - } else { - len += sprintf (page+len,"\n" ); - } - - if (len+begin > off+count) - break; - if (len+begin < off) { - begin += len; - len = 0; } + seq_putc(m, '\n'); } + return 0; + } - if (i >= IP2_MAX_BOARDS) - *eof = 1; - if (off >= len+begin) - return 0; +static int ip2_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ip2_proc_show, NULL); +} - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); - } +static const struct file_operations ip2_proc_fops = { + .owner = THIS_MODULE, + .open = ip2_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; /******************************************************************************/ /* Function: ip2trace() */ diff --git a/trunk/drivers/char/istallion.c b/trunk/drivers/char/istallion.c index 5c3dc6b8411c..fff19f7e29d2 100644 --- a/trunk/drivers/char/istallion.c +++ b/trunk/drivers/char/istallion.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -613,7 +614,6 @@ static int stli_breakctl(struct tty_struct *tty, int state); static void stli_waituntilsent(struct tty_struct *tty, int timeout); static void stli_sendxchar(struct tty_struct *tty, char ch); static void stli_hangup(struct tty_struct *tty); -static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos); static int stli_brdinit(struct stlibrd *brdp); static int stli_startbrd(struct stlibrd *brdp); @@ -1893,20 +1893,10 @@ static void stli_sendxchar(struct tty_struct *tty, char ch) stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0); } -/*****************************************************************************/ - -#define MAXLINE 80 - -/* - * Format info for a specified port. The line is deliberately limited - * to 80 characters. (If it is too long it will be truncated, if too - * short then padded with spaces). - */ - -static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos) +static void stli_portinfo(struct seq_file *m, struct stlibrd *brdp, struct stliport *portp, int portnr) { - char *sp, *uart; - int rc, cnt; + char *uart; + int rc; rc = stli_portcmdstats(NULL, portp); @@ -1918,44 +1908,50 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn default:uart = "CD1400"; break; } } - - sp = pos; - sp += sprintf(sp, "%d: uart:%s ", portnr, uart); + seq_printf(m, "%d: uart:%s ", portnr, uart); if ((brdp->state & BST_STARTED) && (rc >= 0)) { - sp += sprintf(sp, "tx:%d rx:%d", (int) stli_comstats.txtotal, + char sep; + + seq_printf(m, "tx:%d rx:%d", (int) stli_comstats.txtotal, (int) stli_comstats.rxtotal); if (stli_comstats.rxframing) - sp += sprintf(sp, " fe:%d", + seq_printf(m, " fe:%d", (int) stli_comstats.rxframing); if (stli_comstats.rxparity) - sp += sprintf(sp, " pe:%d", + seq_printf(m, " pe:%d", (int) stli_comstats.rxparity); if (stli_comstats.rxbreaks) - sp += sprintf(sp, " brk:%d", + seq_printf(m, " brk:%d", (int) stli_comstats.rxbreaks); if (stli_comstats.rxoverrun) - sp += sprintf(sp, " oe:%d", + seq_printf(m, " oe:%d", (int) stli_comstats.rxoverrun); - cnt = sprintf(sp, "%s%s%s%s%s ", - (stli_comstats.signals & TIOCM_RTS) ? "|RTS" : "", - (stli_comstats.signals & TIOCM_CTS) ? "|CTS" : "", - (stli_comstats.signals & TIOCM_DTR) ? "|DTR" : "", - (stli_comstats.signals & TIOCM_CD) ? "|DCD" : "", - (stli_comstats.signals & TIOCM_DSR) ? "|DSR" : ""); - *sp = ' '; - sp += cnt; + sep = ' '; + if (stli_comstats.signals & TIOCM_RTS) { + seq_printf(m, "%c%s", sep, "RTS"); + sep = '|'; + } + if (stli_comstats.signals & TIOCM_CTS) { + seq_printf(m, "%c%s", sep, "CTS"); + sep = '|'; + } + if (stli_comstats.signals & TIOCM_DTR) { + seq_printf(m, "%c%s", sep, "DTR"); + sep = '|'; + } + if (stli_comstats.signals & TIOCM_CD) { + seq_printf(m, "%c%s", sep, "DCD"); + sep = '|'; + } + if (stli_comstats.signals & TIOCM_DSR) { + seq_printf(m, "%c%s", sep, "DSR"); + sep = '|'; + } } - - for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++) - *sp++ = ' '; - if (cnt >= MAXLINE) - pos[(MAXLINE - 2)] = '+'; - pos[(MAXLINE - 1)] = '\n'; - - return(MAXLINE); + seq_putc(m, '\n'); } /*****************************************************************************/ @@ -1964,26 +1960,15 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn * Port info, read from the /proc file system. */ -static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) +static int stli_proc_show(struct seq_file *m, void *v) { struct stlibrd *brdp; struct stliport *portp; unsigned int brdnr, portnr, totalport; - int curoff, maxoff; - char *pos; - pos = page; totalport = 0; - curoff = 0; - - if (off == 0) { - pos += sprintf(pos, "%s: version %s", stli_drvtitle, - stli_drvversion); - while (pos < (page + MAXLINE - 1)) - *pos++ = ' '; - *pos++ = '\n'; - } - curoff = MAXLINE; + + seq_printf(m, "%s: version %s\n", stli_drvtitle, stli_drvversion); /* * We scan through for each board, panel and port. The offset is @@ -1996,33 +1981,31 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo if (brdp->state == 0) continue; - maxoff = curoff + (brdp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - continue; - } - totalport = brdnr * STL_MAXPORTS; for (portnr = 0; (portnr < brdp->nrports); portnr++, totalport++) { portp = brdp->ports[portnr]; if (portp == NULL) continue; - if (off >= (curoff += MAXLINE)) - continue; - if ((pos - page + MAXLINE) > count) - goto stli_readdone; - pos += stli_portinfo(brdp, portp, totalport, pos); + stli_portinfo(m, brdp, portp, totalport); } } + return 0; +} - *eof = 1; - -stli_readdone: - *start = page; - return(pos - page); +static int stli_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stli_proc_show, NULL); } +static const struct file_operations stli_proc_fops = { + .owner = THIS_MODULE, + .open = stli_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /*****************************************************************************/ /* @@ -4427,9 +4410,9 @@ static const struct tty_operations stli_ops = { .break_ctl = stli_breakctl, .wait_until_sent = stli_waituntilsent, .send_xchar = stli_sendxchar, - .read_proc = stli_readproc, .tiocmget = stli_tiocmget, .tiocmset = stli_tiocmset, + .proc_fops = &stli_proc_fops, }; static const struct tty_port_operations stli_port_ops = { diff --git a/trunk/drivers/char/pcmcia/synclink_cs.c b/trunk/drivers/char/pcmcia/synclink_cs.c index 5608a1e5a3b3..19d79fc54461 100644 --- a/trunk/drivers/char/pcmcia/synclink_cs.c +++ b/trunk/drivers/char/pcmcia/synclink_cs.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -2619,13 +2620,12 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) * /proc fs routines.... */ -static inline int line_info(char *buf, MGSLPC_INFO *info) +static inline void line_info(struct seq_file *m, MGSLPC_INFO *info) { char stat_buf[30]; - int ret; unsigned long flags; - ret = sprintf(buf, "%s:io:%04X irq:%d", + seq_printf(m, "%s:io:%04X irq:%d", info->device_name, info->io_base, info->irq_level); /* output current serial signal states */ @@ -2649,75 +2649,70 @@ static inline int line_info(char *buf, MGSLPC_INFO *info) strcat(stat_buf, "|RI"); if (info->params.mode == MGSL_MODE_HDLC) { - ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d", + seq_printf(m, " HDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) - ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); + seq_printf(m, " txunder:%d", info->icount.txunder); if (info->icount.txabort) - ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); + seq_printf(m, " txabort:%d", info->icount.txabort); if (info->icount.rxshort) - ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); + seq_printf(m, " rxshort:%d", info->icount.rxshort); if (info->icount.rxlong) - ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); + seq_printf(m, " rxlong:%d", info->icount.rxlong); if (info->icount.rxover) - ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); + seq_printf(m, " rxover:%d", info->icount.rxover); if (info->icount.rxcrc) - ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); + seq_printf(m, " rxcrc:%d", info->icount.rxcrc); } else { - ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d", + seq_printf(m, " ASYNC tx:%d rx:%d", info->icount.tx, info->icount.rx); if (info->icount.frame) - ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + seq_printf(m, " fe:%d", info->icount.frame); if (info->icount.parity) - ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + seq_printf(m, " pe:%d", info->icount.parity); if (info->icount.brk) - ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + seq_printf(m, " brk:%d", info->icount.brk); if (info->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + seq_printf(m, " oe:%d", info->icount.overrun); } /* Append serial signal status to end */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); + seq_printf(m, " %s\n", stat_buf+1); - ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", + seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", info->tx_active,info->bh_requested,info->bh_running, info->pending_bh); - - return ret; } /* Called to print information about devices */ -static int mgslpc_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int mgslpc_proc_show(struct seq_file *m, void *v) { - int len = 0, l; - off_t begin = 0; MGSLPC_INFO *info; - len += sprintf(page, "synclink driver:%s\n", driver_version); + seq_printf(m, "synclink driver:%s\n", driver_version); info = mgslpc_device_list; while( info ) { - l = line_info(page + len, info); - len += l; - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } + line_info(m, info); info = info->next_device; } + return 0; +} - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); +static int mgslpc_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mgslpc_proc_show, NULL); } +static const struct file_operations mgslpc_proc_fops = { + .owner = THIS_MODULE, + .open = mgslpc_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int rx_alloc_buffers(MGSLPC_INFO *info) { /* each buffer has header and data */ @@ -2861,13 +2856,13 @@ static const struct tty_operations mgslpc_ops = { .send_xchar = mgslpc_send_xchar, .break_ctl = mgslpc_break, .wait_until_sent = mgslpc_wait_until_sent, - .read_proc = mgslpc_read_proc, .set_termios = mgslpc_set_termios, .stop = tx_pause, .start = tx_release, .hangup = mgslpc_hangup, .tiocmget = tiocmget, .tiocmset = tiocmset, + .proc_fops = &mgslpc_proc_fops, }; static void synclink_cs_cleanup(void) diff --git a/trunk/drivers/char/random.c b/trunk/drivers/char/random.c index 7c43ae782b26..f824ef8a9273 100644 --- a/trunk/drivers/char/random.c +++ b/trunk/drivers/char/random.c @@ -1488,7 +1488,8 @@ static void rekey_seq_generator(struct work_struct *work) keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS; smp_wmb(); ip_cnt++; - schedule_delayed_work(&rekey_work, REKEY_INTERVAL); + schedule_delayed_work(&rekey_work, + round_jiffies_relative(REKEY_INTERVAL)); } static inline struct keydata *get_keyptr(void) diff --git a/trunk/drivers/char/stallion.c b/trunk/drivers/char/stallion.c index e1e0dd89ac9a..2ad813a801dc 100644 --- a/trunk/drivers/char/stallion.c +++ b/trunk/drivers/char/stallion.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1379,52 +1380,47 @@ static void stl_sendxchar(struct tty_struct *tty, char ch) stl_putchar(tty, ch); } -/*****************************************************************************/ - -#define MAXLINE 80 - -/* - * Format info for a specified port. The line is deliberately limited - * to 80 characters. (If it is too long it will be truncated, if too - * short then padded with spaces). - */ - -static int stl_portinfo(struct stlport *portp, int portnr, char *pos) +static void stl_portinfo(struct seq_file *m, struct stlport *portp, int portnr) { - char *sp; - int sigs, cnt; + int sigs; + char sep; - sp = pos; - sp += sprintf(sp, "%d: uart:%s tx:%d rx:%d", + seq_printf(m, "%d: uart:%s tx:%d rx:%d", portnr, (portp->hwid == 1) ? "SC26198" : "CD1400", (int) portp->stats.txtotal, (int) portp->stats.rxtotal); if (portp->stats.rxframing) - sp += sprintf(sp, " fe:%d", (int) portp->stats.rxframing); + seq_printf(m, " fe:%d", (int) portp->stats.rxframing); if (portp->stats.rxparity) - sp += sprintf(sp, " pe:%d", (int) portp->stats.rxparity); + seq_printf(m, " pe:%d", (int) portp->stats.rxparity); if (portp->stats.rxbreaks) - sp += sprintf(sp, " brk:%d", (int) portp->stats.rxbreaks); + seq_printf(m, " brk:%d", (int) portp->stats.rxbreaks); if (portp->stats.rxoverrun) - sp += sprintf(sp, " oe:%d", (int) portp->stats.rxoverrun); + seq_printf(m, " oe:%d", (int) portp->stats.rxoverrun); sigs = stl_getsignals(portp); - cnt = sprintf(sp, "%s%s%s%s%s ", - (sigs & TIOCM_RTS) ? "|RTS" : "", - (sigs & TIOCM_CTS) ? "|CTS" : "", - (sigs & TIOCM_DTR) ? "|DTR" : "", - (sigs & TIOCM_CD) ? "|DCD" : "", - (sigs & TIOCM_DSR) ? "|DSR" : ""); - *sp = ' '; - sp += cnt; - - for (cnt = sp - pos; cnt < (MAXLINE - 1); cnt++) - *sp++ = ' '; - if (cnt >= MAXLINE) - pos[(MAXLINE - 2)] = '+'; - pos[(MAXLINE - 1)] = '\n'; - - return MAXLINE; + sep = ' '; + if (sigs & TIOCM_RTS) { + seq_printf(m, "%c%s", sep, "RTS"); + sep = '|'; + } + if (sigs & TIOCM_CTS) { + seq_printf(m, "%c%s", sep, "CTS"); + sep = '|'; + } + if (sigs & TIOCM_DTR) { + seq_printf(m, "%c%s", sep, "DTR"); + sep = '|'; + } + if (sigs & TIOCM_CD) { + seq_printf(m, "%c%s", sep, "DCD"); + sep = '|'; + } + if (sigs & TIOCM_DSR) { + seq_printf(m, "%c%s", sep, "DSR"); + sep = '|'; + } + seq_putc(m, '\n'); } /*****************************************************************************/ @@ -1433,30 +1429,17 @@ static int stl_portinfo(struct stlport *portp, int portnr, char *pos) * Port info, read from the /proc file system. */ -static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data) +static int stl_proc_show(struct seq_file *m, void *v) { struct stlbrd *brdp; struct stlpanel *panelp; struct stlport *portp; unsigned int brdnr, panelnr, portnr; - int totalport, curoff, maxoff; - char *pos; + int totalport; - pr_debug("stl_readproc(page=%p,start=%p,off=%lx,count=%d,eof=%p," - "data=%p\n", page, start, off, count, eof, data); - - pos = page; totalport = 0; - curoff = 0; - - if (off == 0) { - pos += sprintf(pos, "%s: version %s", stl_drvtitle, - stl_drvversion); - while (pos < (page + MAXLINE - 1)) - *pos++ = ' '; - *pos++ = '\n'; - } - curoff = MAXLINE; + + seq_printf(m, "%s: version %s\n", stl_drvtitle, stl_drvversion); /* * We scan through for each board, panel and port. The offset is @@ -1469,46 +1452,37 @@ static int stl_readproc(char *page, char **start, off_t off, int count, int *eof if (brdp->state == 0) continue; - maxoff = curoff + (brdp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - continue; - } - totalport = brdnr * STL_MAXPORTS; for (panelnr = 0; panelnr < brdp->nrpanels; panelnr++) { panelp = brdp->panels[panelnr]; if (panelp == NULL) continue; - maxoff = curoff + (panelp->nrports * MAXLINE); - if (off >= maxoff) { - curoff = maxoff; - totalport += panelp->nrports; - continue; - } - for (portnr = 0; portnr < panelp->nrports; portnr++, totalport++) { portp = panelp->ports[portnr]; if (portp == NULL) continue; - if (off >= (curoff += MAXLINE)) - continue; - if ((pos - page + MAXLINE) > count) - goto stl_readdone; - pos += stl_portinfo(portp, totalport, pos); + stl_portinfo(m, portp, totalport); } } } + return 0; +} - *eof = 1; - -stl_readdone: - *start = page; - return pos - page; +static int stl_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, stl_proc_show, NULL); } +static const struct file_operations stl_proc_fops = { + .owner = THIS_MODULE, + .open = stl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /*****************************************************************************/ /* @@ -2566,9 +2540,9 @@ static const struct tty_operations stl_ops = { .break_ctl = stl_breakctl, .wait_until_sent = stl_waituntilsent, .send_xchar = stl_sendxchar, - .read_proc = stl_readproc, .tiocmget = stl_tiocmget, .tiocmset = stl_tiocmset, + .proc_fops = &stl_proc_fops, }; static const struct tty_port_operations stl_port_ops = { diff --git a/trunk/drivers/char/synclink.c b/trunk/drivers/char/synclink.c index 0057a8f58cb1..afd0b26ca056 100644 --- a/trunk/drivers/char/synclink.c +++ b/trunk/drivers/char/synclink.c @@ -79,6 +79,7 @@ #include #include #include +#include #include #include #include @@ -3459,18 +3460,17 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) * /proc fs routines.... */ -static inline int line_info(char *buf, struct mgsl_struct *info) +static inline void line_info(struct seq_file *m, struct mgsl_struct *info) { char stat_buf[30]; - int ret; unsigned long flags; if (info->bus_type == MGSL_BUS_TYPE_PCI) { - ret = sprintf(buf, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X", + seq_printf(m, "%s:PCI io:%04X irq:%d mem:%08X lcr:%08X", info->device_name, info->io_base, info->irq_level, info->phys_memory_base, info->phys_lcr_base); } else { - ret = sprintf(buf, "%s:(E)ISA io:%04X irq:%d dma:%d", + seq_printf(m, "%s:(E)ISA io:%04X irq:%d dma:%d", info->device_name, info->io_base, info->irq_level, info->dma_level); } @@ -3497,37 +3497,37 @@ static inline int line_info(char *buf, struct mgsl_struct *info) if (info->params.mode == MGSL_MODE_HDLC || info->params.mode == MGSL_MODE_RAW ) { - ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d", + seq_printf(m, " HDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) - ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); + seq_printf(m, " txunder:%d", info->icount.txunder); if (info->icount.txabort) - ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); + seq_printf(m, " txabort:%d", info->icount.txabort); if (info->icount.rxshort) - ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); + seq_printf(m, " rxshort:%d", info->icount.rxshort); if (info->icount.rxlong) - ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); + seq_printf(m, " rxlong:%d", info->icount.rxlong); if (info->icount.rxover) - ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); + seq_printf(m, " rxover:%d", info->icount.rxover); if (info->icount.rxcrc) - ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); + seq_printf(m, " rxcrc:%d", info->icount.rxcrc); } else { - ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d", + seq_printf(m, " ASYNC tx:%d rx:%d", info->icount.tx, info->icount.rx); if (info->icount.frame) - ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + seq_printf(m, " fe:%d", info->icount.frame); if (info->icount.parity) - ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + seq_printf(m, " pe:%d", info->icount.parity); if (info->icount.brk) - ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + seq_printf(m, " brk:%d", info->icount.brk); if (info->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + seq_printf(m, " oe:%d", info->icount.overrun); } /* Append serial signal status to end */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); + seq_printf(m, " %s\n", stat_buf+1); - ret += sprintf(buf+ret, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", + seq_printf(m, "txactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", info->tx_active,info->bh_requested,info->bh_running, info->pending_bh); @@ -3544,60 +3544,40 @@ static inline int line_info(char *buf, struct mgsl_struct *info) u16 Tmr = usc_InReg( info, TMR ); u16 Tccr = usc_InReg( info, TCCR ); u16 Ccar = inw( info->io_base + CCAR ); - ret += sprintf(buf+ret, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n" + seq_printf(m, "tcsr=%04X tdmr=%04X ticr=%04X rcsr=%04X rdmr=%04X\n" "ricr=%04X icr =%04X dccr=%04X tmr=%04X tccr=%04X ccar=%04X\n", Tcsr,Tdmr,Ticr,Rscr,Rdmr,Ricr,Icr,Dccr,Tmr,Tccr,Ccar ); } spin_unlock_irqrestore(&info->irq_spinlock,flags); - - return ret; - -} /* end of line_info() */ +} -/* mgsl_read_proc() - * - * Called to print information about devices - * - * Arguments: - * page page of memory to hold returned info - * start - * off - * count - * eof - * data - * - * Return Value: - */ -static int mgsl_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +/* Called to print information about devices */ +static int mgsl_proc_show(struct seq_file *m, void *v) { - int len = 0, l; - off_t begin = 0; struct mgsl_struct *info; - len += sprintf(page, "synclink driver:%s\n", driver_version); + seq_printf(m, "synclink driver:%s\n", driver_version); info = mgsl_device_list; while( info ) { - l = line_info(page + len, info); - len += l; - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } + line_info(m, info); info = info->next_device; } + return 0; +} - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); - -} /* end of mgsl_read_proc() */ +static int mgsl_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mgsl_proc_show, NULL); +} + +static const struct file_operations mgsl_proc_fops = { + .owner = THIS_MODULE, + .open = mgsl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; /* mgsl_allocate_dma_buffers() * @@ -4335,13 +4315,13 @@ static const struct tty_operations mgsl_ops = { .send_xchar = mgsl_send_xchar, .break_ctl = mgsl_break, .wait_until_sent = mgsl_wait_until_sent, - .read_proc = mgsl_read_proc, .set_termios = mgsl_set_termios, .stop = mgsl_stop, .start = mgsl_start, .hangup = mgsl_hangup, .tiocmget = tiocmget, .tiocmset = tiocmset, + .proc_fops = &mgsl_proc_fops, }; /* diff --git a/trunk/drivers/char/synclink_gt.c b/trunk/drivers/char/synclink_gt.c index efb3dc928a43..5e256494686a 100644 --- a/trunk/drivers/char/synclink_gt.c +++ b/trunk/drivers/char/synclink_gt.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -154,7 +155,6 @@ static void tx_hold(struct tty_struct *tty); static void tx_release(struct tty_struct *tty); static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static int read_proc(char *page, char **start, off_t off, int count,int *eof, void *data); static int chars_in_buffer(struct tty_struct *tty); static void throttle(struct tty_struct * tty); static void unthrottle(struct tty_struct * tty); @@ -298,6 +298,7 @@ struct slgt_info { unsigned int rbuf_fill_level; unsigned int if_mode; + unsigned int base_clock; /* device status */ @@ -1156,22 +1157,26 @@ static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *ne return -EFAULT; spin_lock(&info->lock); - info->params.mode = tmp_params.mode; - info->params.loopback = tmp_params.loopback; - info->params.flags = tmp_params.flags; - info->params.encoding = tmp_params.encoding; - info->params.clock_speed = tmp_params.clock_speed; - info->params.addr_filter = tmp_params.addr_filter; - info->params.crc_type = tmp_params.crc_type; - info->params.preamble_length = tmp_params.preamble_length; - info->params.preamble = tmp_params.preamble; - info->params.data_rate = tmp_params.data_rate; - info->params.data_bits = tmp_params.data_bits; - info->params.stop_bits = tmp_params.stop_bits; - info->params.parity = tmp_params.parity; + if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) { + info->base_clock = tmp_params.clock_speed; + } else { + info->params.mode = tmp_params.mode; + info->params.loopback = tmp_params.loopback; + info->params.flags = tmp_params.flags; + info->params.encoding = tmp_params.encoding; + info->params.clock_speed = tmp_params.clock_speed; + info->params.addr_filter = tmp_params.addr_filter; + info->params.crc_type = tmp_params.crc_type; + info->params.preamble_length = tmp_params.preamble_length; + info->params.preamble = tmp_params.preamble; + info->params.data_rate = tmp_params.data_rate; + info->params.data_bits = tmp_params.data_bits; + info->params.stop_bits = tmp_params.stop_bits; + info->params.parity = tmp_params.parity; + } spin_unlock(&info->lock); - change_params(info); + program_hw(info); return 0; } @@ -1229,13 +1234,12 @@ static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file, /* * proc fs support */ -static inline int line_info(char *buf, struct slgt_info *info) +static inline void line_info(struct seq_file *m, struct slgt_info *info) { char stat_buf[30]; - int ret; unsigned long flags; - ret = sprintf(buf, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n", + seq_printf(m, "%s: IO=%08X IRQ=%d MaxFrameSize=%u\n", info->device_name, info->phys_reg_addr, info->irq_level, info->max_frame_size); @@ -1260,75 +1264,70 @@ static inline int line_info(char *buf, struct slgt_info *info) strcat(stat_buf, "|RI"); if (info->params.mode != MGSL_MODE_ASYNC) { - ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d", + seq_printf(m, "\tHDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) - ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); + seq_printf(m, " txunder:%d", info->icount.txunder); if (info->icount.txabort) - ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); + seq_printf(m, " txabort:%d", info->icount.txabort); if (info->icount.rxshort) - ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); + seq_printf(m, " rxshort:%d", info->icount.rxshort); if (info->icount.rxlong) - ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); + seq_printf(m, " rxlong:%d", info->icount.rxlong); if (info->icount.rxover) - ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); + seq_printf(m, " rxover:%d", info->icount.rxover); if (info->icount.rxcrc) - ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); + seq_printf(m, " rxcrc:%d", info->icount.rxcrc); } else { - ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d", + seq_printf(m, "\tASYNC tx:%d rx:%d", info->icount.tx, info->icount.rx); if (info->icount.frame) - ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + seq_printf(m, " fe:%d", info->icount.frame); if (info->icount.parity) - ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + seq_printf(m, " pe:%d", info->icount.parity); if (info->icount.brk) - ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + seq_printf(m, " brk:%d", info->icount.brk); if (info->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + seq_printf(m, " oe:%d", info->icount.overrun); } /* Append serial signal status to end */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); + seq_printf(m, " %s\n", stat_buf+1); - ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", + seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", info->tx_active,info->bh_requested,info->bh_running, info->pending_bh); - - return ret; } /* Called to print information about devices */ -static int read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int synclink_gt_proc_show(struct seq_file *m, void *v) { - int len = 0, l; - off_t begin = 0; struct slgt_info *info; - len += sprintf(page, "synclink_gt driver\n"); + seq_puts(m, "synclink_gt driver\n"); info = slgt_device_list; while( info ) { - l = line_info(page + len, info); - len += l; - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } + line_info(m, info); info = info->next_device; } + return 0; +} - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); +static int synclink_gt_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, synclink_gt_proc_show, NULL); } +static const struct file_operations synclink_gt_proc_fops = { + .owner = THIS_MODULE, + .open = synclink_gt_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * return count of bytes in transmit buffer */ @@ -2565,10 +2564,13 @@ static int set_params(struct slgt_info *info, MGSL_PARAMS __user *new_params) return -EFAULT; spin_lock_irqsave(&info->lock, flags); - memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS)); + if (tmp_params.mode == MGSL_MODE_BASE_CLOCK) + info->base_clock = tmp_params.clock_speed; + else + memcpy(&info->params, &tmp_params, sizeof(MGSL_PARAMS)); spin_unlock_irqrestore(&info->lock, flags); - change_params(info); + program_hw(info); return 0; } @@ -3438,6 +3440,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev info->magic = MGSL_MAGIC; INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; + info->base_clock = 14745600; info->rbuf_fill_level = DMABUFSIZE; info->port.close_delay = 5*HZ/10; info->port.closing_wait = 30*HZ; @@ -3562,13 +3565,13 @@ static const struct tty_operations ops = { .send_xchar = send_xchar, .break_ctl = set_break, .wait_until_sent = wait_until_sent, - .read_proc = read_proc, .set_termios = set_termios, .stop = tx_hold, .start = tx_release, .hangup = hangup, .tiocmget = tiocmget, .tiocmset = tiocmset, + .proc_fops = &synclink_gt_proc_fops, }; static void slgt_cleanup(void) @@ -3785,7 +3788,7 @@ static void enable_loopback(struct slgt_info *info) static void set_rate(struct slgt_info *info, u32 rate) { unsigned int div; - static unsigned int osc = 14745600; + unsigned int osc = info->base_clock; /* div = osc/rate - 1 * @@ -4089,18 +4092,27 @@ static void async_mode(struct slgt_info *info) * 06 CTS IRQ enable * 05 DCD IRQ enable * 04 RI IRQ enable - * 03 reserved, must be zero + * 03 0=16x sampling, 1=8x sampling * 02 1=txd->rxd internal loopback enable * 01 reserved, must be zero * 00 1=master IRQ enable */ val = BIT15 + BIT14 + BIT0; + /* JCR[8] : 1 = x8 async mode feature available */ + if ((rd_reg32(info, JCR) & BIT8) && info->params.data_rate && + ((info->base_clock < (info->params.data_rate * 16)) || + (info->base_clock % (info->params.data_rate * 16)))) { + /* use 8x sampling */ + val |= BIT3; + set_rate(info, info->params.data_rate * 8); + } else { + /* use 16x sampling */ + set_rate(info, info->params.data_rate * 16); + } wr_reg16(info, SCR, val); slgt_irq_on(info, IRQ_RXBREAK | IRQ_RXOVER); - set_rate(info, info->params.data_rate * 16); - if (info->params.loopback) enable_loopback(info); } diff --git a/trunk/drivers/char/synclinkmp.c b/trunk/drivers/char/synclinkmp.c index 8eb6c89a980e..26de60efe4b2 100644 --- a/trunk/drivers/char/synclinkmp.c +++ b/trunk/drivers/char/synclinkmp.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -520,7 +521,6 @@ static void tx_hold(struct tty_struct *tty); static void tx_release(struct tty_struct *tty); static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static int read_proc(char *page, char **start, off_t off, int count,int *eof, void *data); static int chars_in_buffer(struct tty_struct *tty); static void throttle(struct tty_struct * tty); static void unthrottle(struct tty_struct * tty); @@ -1354,13 +1354,12 @@ static int ioctl(struct tty_struct *tty, struct file *file, * /proc fs routines.... */ -static inline int line_info(char *buf, SLMP_INFO *info) +static inline void line_info(struct seq_file *m, SLMP_INFO *info) { char stat_buf[30]; - int ret; unsigned long flags; - ret = sprintf(buf, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n" + seq_printf(m, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n" "\tIRQ=%d MaxFrameSize=%u\n", info->device_name, info->phys_sca_base, @@ -1391,75 +1390,70 @@ static inline int line_info(char *buf, SLMP_INFO *info) strcat(stat_buf, "|RI"); if (info->params.mode == MGSL_MODE_HDLC) { - ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d", + seq_printf(m, "\tHDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) - ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); + seq_printf(m, " txunder:%d", info->icount.txunder); if (info->icount.txabort) - ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); + seq_printf(m, " txabort:%d", info->icount.txabort); if (info->icount.rxshort) - ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); + seq_printf(m, " rxshort:%d", info->icount.rxshort); if (info->icount.rxlong) - ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); + seq_printf(m, " rxlong:%d", info->icount.rxlong); if (info->icount.rxover) - ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); + seq_printf(m, " rxover:%d", info->icount.rxover); if (info->icount.rxcrc) - ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc); + seq_printf(m, " rxlong:%d", info->icount.rxcrc); } else { - ret += sprintf(buf+ret, "\tASYNC tx:%d rx:%d", + seq_printf(m, "\tASYNC tx:%d rx:%d", info->icount.tx, info->icount.rx); if (info->icount.frame) - ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + seq_printf(m, " fe:%d", info->icount.frame); if (info->icount.parity) - ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + seq_printf(m, " pe:%d", info->icount.parity); if (info->icount.brk) - ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + seq_printf(m, " brk:%d", info->icount.brk); if (info->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + seq_printf(m, " oe:%d", info->icount.overrun); } /* Append serial signal status to end */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); + seq_printf(m, " %s\n", stat_buf+1); - ret += sprintf(buf+ret, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", + seq_printf(m, "\ttxactive=%d bh_req=%d bh_run=%d pending_bh=%x\n", info->tx_active,info->bh_requested,info->bh_running, info->pending_bh); - - return ret; } /* Called to print information about devices */ -static int read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int synclinkmp_proc_show(struct seq_file *m, void *v) { - int len = 0, l; - off_t begin = 0; SLMP_INFO *info; - len += sprintf(page, "synclinkmp driver:%s\n", driver_version); + seq_printf(m, "synclinkmp driver:%s\n", driver_version); info = synclinkmp_device_list; while( info ) { - l = line_info(page + len, info); - len += l; - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } + line_info(m, info); info = info->next_device; } + return 0; +} - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); +static int synclinkmp_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, synclinkmp_proc_show, NULL); } +static const struct file_operations synclinkmp_proc_fops = { + .owner = THIS_MODULE, + .open = synclinkmp_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* Return the count of bytes in transmit buffer */ static int chars_in_buffer(struct tty_struct *tty) @@ -3905,13 +3899,13 @@ static const struct tty_operations ops = { .send_xchar = send_xchar, .break_ctl = set_break, .wait_until_sent = wait_until_sent, - .read_proc = read_proc, .set_termios = set_termios, .stop = tx_hold, .start = tx_release, .hangup = hangup, .tiocmget = tiocmget, .tiocmset = tiocmset, + .proc_fops = &synclinkmp_proc_fops, }; diff --git a/trunk/drivers/char/sysrq.c b/trunk/drivers/char/sysrq.c index 33a9351c896d..ebea9b2c30a5 100644 --- a/trunk/drivers/char/sysrq.c +++ b/trunk/drivers/char/sysrq.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include @@ -346,6 +346,19 @@ static struct sysrq_key_op sysrq_moom_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; +#ifdef CONFIG_BLOCK +static void sysrq_handle_thaw(int key, struct tty_struct *tty) +{ + emergency_thaw_all(); +} +static struct sysrq_key_op sysrq_thaw_op = { + .handler = sysrq_handle_thaw, + .help_msg = "thaw-filesystems(J)", + .action_msg = "Emergency Thaw of all frozen filesystems", + .enable_mask = SYSRQ_ENABLE_SIGNAL, +}; +#endif + static void sysrq_handle_kill(int key, struct tty_struct *tty) { send_sig_all(SIGKILL); @@ -396,9 +409,13 @@ static struct sysrq_key_op *sysrq_key_table[36] = { &sysrq_moom_op, /* f */ /* g: May be registered by ppc for kgdb */ NULL, /* g */ - NULL, /* h */ + NULL, /* h - reserved for help */ &sysrq_kill_op, /* i */ +#ifdef CONFIG_BLOCK + &sysrq_thaw_op, /* j */ +#else NULL, /* j */ +#endif &sysrq_SAK_op, /* k */ #ifdef CONFIG_SMP &sysrq_showallcpus_op, /* l */ diff --git a/trunk/drivers/char/tty_audit.c b/trunk/drivers/char/tty_audit.c index 34ab6d798f81..55ba6f142883 100644 --- a/trunk/drivers/char/tty_audit.c +++ b/trunk/drivers/char/tty_audit.c @@ -10,8 +10,6 @@ */ #include -#include -#include #include struct tty_audit_buf { diff --git a/trunk/drivers/char/tty_io.c b/trunk/drivers/char/tty_io.c index 224f271d8cbe..66b99a2049e3 100644 --- a/trunk/drivers/char/tty_io.c +++ b/trunk/drivers/char/tty_io.c @@ -464,7 +464,7 @@ void tty_wakeup(struct tty_struct *tty) tty_ldisc_deref(ld); } } - wake_up_interruptible(&tty->write_wait); + wake_up_interruptible_poll(&tty->write_wait, POLLOUT); } EXPORT_SYMBOL_GPL(tty_wakeup); @@ -587,8 +587,8 @@ static void do_tty_hangup(struct work_struct *work) * FIXME: Once we trust the LDISC code better we can wait here for * ldisc completion and fix the driver call race */ - wake_up_interruptible(&tty->write_wait); - wake_up_interruptible(&tty->read_wait); + wake_up_interruptible_poll(&tty->write_wait, POLLOUT); + wake_up_interruptible_poll(&tty->read_wait, POLLIN); /* * Shutdown the current line discipline, and reset it to * N_TTY. @@ -879,7 +879,7 @@ void stop_tty(struct tty_struct *tty) if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_START; tty->ctrl_status |= TIOCPKT_STOP; - wake_up_interruptible(&tty->link->read_wait); + wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); } spin_unlock_irqrestore(&tty->ctrl_lock, flags); if (tty->ops->stop) @@ -913,7 +913,7 @@ void start_tty(struct tty_struct *tty) if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_STOP; tty->ctrl_status |= TIOCPKT_START; - wake_up_interruptible(&tty->link->read_wait); + wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); } spin_unlock_irqrestore(&tty->ctrl_lock, flags); if (tty->ops->start) @@ -970,7 +970,7 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, void tty_write_unlock(struct tty_struct *tty) { mutex_unlock(&tty->atomic_write_lock); - wake_up_interruptible(&tty->write_wait); + wake_up_interruptible_poll(&tty->write_wait, POLLOUT); } int tty_write_lock(struct tty_struct *tty, int ndelay) @@ -1623,21 +1623,21 @@ void tty_release_dev(struct file *filp) if (tty_closing) { if (waitqueue_active(&tty->read_wait)) { - wake_up(&tty->read_wait); + wake_up_poll(&tty->read_wait, POLLIN); do_sleep++; } if (waitqueue_active(&tty->write_wait)) { - wake_up(&tty->write_wait); + wake_up_poll(&tty->write_wait, POLLOUT); do_sleep++; } } if (o_tty_closing) { if (waitqueue_active(&o_tty->read_wait)) { - wake_up(&o_tty->read_wait); + wake_up_poll(&o_tty->read_wait, POLLIN); do_sleep++; } if (waitqueue_active(&o_tty->write_wait)) { - wake_up(&o_tty->write_wait); + wake_up_poll(&o_tty->write_wait, POLLOUT); do_sleep++; } } @@ -1758,7 +1758,7 @@ static int __tty_open(struct inode *inode, struct file *filp) struct tty_driver *driver; int index; dev_t device = inode->i_rdev; - unsigned short saved_flags = filp->f_flags; + unsigned saved_flags = filp->f_flags; nonseekable_open(inode, filp); @@ -2681,7 +2681,7 @@ void __do_SAK(struct tty_struct *tty) /* Kill the entire session */ do_each_pid_task(session, PIDTYPE_SID, p) { printk(KERN_NOTICE "SAK: killed process %d" - " (%s): task_session_nr(p)==tty->session\n", + " (%s): task_session(p)==tty->session\n", task_pid_nr(p), p->comm); send_sig(SIGKILL, p, 1); } while_each_pid_task(session, PIDTYPE_SID, p); @@ -2691,7 +2691,7 @@ void __do_SAK(struct tty_struct *tty) do_each_thread(g, p) { if (p->signal->tty == tty) { printk(KERN_NOTICE "SAK: killed process %d" - " (%s): task_session_nr(p)==tty->session\n", + " (%s): task_session(p)==tty->session\n", task_pid_nr(p), p->comm); send_sig(SIGKILL, p, 1); continue; diff --git a/trunk/drivers/char/tty_ldisc.c b/trunk/drivers/char/tty_ldisc.c index 7a84b406a952..f78f5b0127a8 100644 --- a/trunk/drivers/char/tty_ldisc.c +++ b/trunk/drivers/char/tty_ldisc.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/crypto/hifn_795x.c b/trunk/drivers/crypto/hifn_795x.c index 0c79fe7f1567..4d85402a9e4a 100644 --- a/trunk/drivers/crypto/hifn_795x.c +++ b/trunk/drivers/crypto/hifn_795x.c @@ -1882,7 +1882,7 @@ static void hifn_clear_rings(struct hifn_device *dev, int error) static void hifn_work(struct work_struct *work) { - struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct delayed_work *dw = to_delayed_work(work); struct hifn_device *dev = container_of(dw, struct hifn_device, work); unsigned long flags; int reset = 0; diff --git a/trunk/drivers/crypto/ixp4xx_crypto.c b/trunk/drivers/crypto/ixp4xx_crypto.c index d9e751be8c5f..af9761ccf9f1 100644 --- a/trunk/drivers/crypto/ixp4xx_crypto.c +++ b/trunk/drivers/crypto/ixp4xx_crypto.c @@ -101,6 +101,7 @@ struct buffer_desc { u32 phys_addr; u32 __reserved[4]; struct buffer_desc *next; + enum dma_data_direction dir; }; struct crypt_ctl { @@ -132,14 +133,10 @@ struct crypt_ctl { struct ablk_ctx { struct buffer_desc *src; struct buffer_desc *dst; - unsigned src_nents; - unsigned dst_nents; }; struct aead_ctx { struct buffer_desc *buffer; - unsigned short assoc_nents; - unsigned short src_nents; struct scatterlist ivlist; /* used when the hmac is not on one sg entry */ u8 *hmac_virt; @@ -312,7 +309,7 @@ static struct crypt_ctl *get_crypt_desc_emerg(void) } } -static void free_buf_chain(struct buffer_desc *buf, u32 phys) +static void free_buf_chain(struct device *dev, struct buffer_desc *buf,u32 phys) { while (buf) { struct buffer_desc *buf1; @@ -320,6 +317,7 @@ static void free_buf_chain(struct buffer_desc *buf, u32 phys) buf1 = buf->next; phys1 = buf->phys_next; + dma_unmap_single(dev, buf->phys_next, buf->buf_len, buf->dir); dma_pool_free(buffer_pool, buf, phys); buf = buf1; phys = phys1; @@ -348,7 +346,6 @@ static void one_packet(dma_addr_t phys) struct crypt_ctl *crypt; struct ixp_ctx *ctx; int failed; - enum dma_data_direction src_direction = DMA_BIDIRECTIONAL; failed = phys & 0x1 ? -EBADMSG : 0; phys &= ~0x3; @@ -358,13 +355,8 @@ static void one_packet(dma_addr_t phys) case CTL_FLAG_PERFORM_AEAD: { struct aead_request *req = crypt->data.aead_req; struct aead_ctx *req_ctx = aead_request_ctx(req); - dma_unmap_sg(dev, req->assoc, req_ctx->assoc_nents, - DMA_TO_DEVICE); - dma_unmap_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL); - dma_unmap_sg(dev, req->src, req_ctx->src_nents, - DMA_BIDIRECTIONAL); - free_buf_chain(req_ctx->buffer, crypt->src_buf); + free_buf_chain(dev, req_ctx->buffer, crypt->src_buf); if (req_ctx->hmac_virt) { finish_scattered_hmac(crypt); } @@ -374,16 +366,11 @@ static void one_packet(dma_addr_t phys) case CTL_FLAG_PERFORM_ABLK: { struct ablkcipher_request *req = crypt->data.ablk_req; struct ablk_ctx *req_ctx = ablkcipher_request_ctx(req); - int nents; + if (req_ctx->dst) { - nents = req_ctx->dst_nents; - dma_unmap_sg(dev, req->dst, nents, DMA_FROM_DEVICE); - free_buf_chain(req_ctx->dst, crypt->dst_buf); - src_direction = DMA_TO_DEVICE; + free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); } - nents = req_ctx->src_nents; - dma_unmap_sg(dev, req->src, nents, src_direction); - free_buf_chain(req_ctx->src, crypt->src_buf); + free_buf_chain(dev, req_ctx->src, crypt->src_buf); req->base.complete(&req->base, failed); break; } @@ -750,56 +737,35 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt, return 0; } -static int count_sg(struct scatterlist *sg, int nbytes) +static struct buffer_desc *chainup_buffers(struct device *dev, + struct scatterlist *sg, unsigned nbytes, + struct buffer_desc *buf, gfp_t flags, + enum dma_data_direction dir) { - int i; - for (i = 0; nbytes > 0; i++, sg = sg_next(sg)) - nbytes -= sg->length; - return i; -} - -static struct buffer_desc *chainup_buffers(struct scatterlist *sg, - unsigned nbytes, struct buffer_desc *buf, gfp_t flags) -{ - int nents = 0; - - while (nbytes > 0) { + for (;nbytes > 0; sg = scatterwalk_sg_next(sg)) { + unsigned len = min(nbytes, sg->length); struct buffer_desc *next_buf; u32 next_buf_phys; - unsigned len = min(nbytes, sg_dma_len(sg)); + void *ptr; - nents++; nbytes -= len; - if (!buf->phys_addr) { - buf->phys_addr = sg_dma_address(sg); - buf->buf_len = len; - buf->next = NULL; - buf->phys_next = 0; - goto next; - } - /* Two consecutive chunks on one page may be handled by the old - * buffer descriptor, increased by the length of the new one - */ - if (sg_dma_address(sg) == buf->phys_addr + buf->buf_len) { - buf->buf_len += len; - goto next; - } + ptr = page_address(sg_page(sg)) + sg->offset; next_buf = dma_pool_alloc(buffer_pool, flags, &next_buf_phys); - if (!next_buf) - return NULL; + if (!next_buf) { + buf = NULL; + break; + } + sg_dma_address(sg) = dma_map_single(dev, ptr, len, dir); buf->next = next_buf; buf->phys_next = next_buf_phys; - buf = next_buf; - buf->next = NULL; - buf->phys_next = 0; + buf->phys_addr = sg_dma_address(sg); buf->buf_len = len; -next: - if (nbytes > 0) { - sg = sg_next(sg); - } + buf->dir = dir; } + buf->next = NULL; + buf->phys_next = 0; return buf; } @@ -860,12 +826,12 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt) struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct ixp_ctx *ctx = crypto_ablkcipher_ctx(tfm); unsigned ivsize = crypto_ablkcipher_ivsize(tfm); - int ret = -ENOMEM; struct ix_sa_dir *dir; struct crypt_ctl *crypt; - unsigned int nbytes = req->nbytes, nents; + unsigned int nbytes = req->nbytes; enum dma_data_direction src_direction = DMA_BIDIRECTIONAL; struct ablk_ctx *req_ctx = ablkcipher_request_ctx(req); + struct buffer_desc src_hook; gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; @@ -878,7 +844,7 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt) crypt = get_crypt_desc(); if (!crypt) - return ret; + return -ENOMEM; crypt->data.ablk_req = req; crypt->crypto_ctx = dir->npe_ctx_phys; @@ -891,53 +857,41 @@ static int ablk_perform(struct ablkcipher_request *req, int encrypt) BUG_ON(ivsize && !req->info); memcpy(crypt->iv, req->info, ivsize); if (req->src != req->dst) { + struct buffer_desc dst_hook; crypt->mode |= NPE_OP_NOT_IN_PLACE; - nents = count_sg(req->dst, nbytes); /* This was never tested by Intel * for more than one dst buffer, I think. */ - BUG_ON(nents != 1); - req_ctx->dst_nents = nents; - dma_map_sg(dev, req->dst, nents, DMA_FROM_DEVICE); - req_ctx->dst = dma_pool_alloc(buffer_pool, flags,&crypt->dst_buf); - if (!req_ctx->dst) - goto unmap_sg_dest; - req_ctx->dst->phys_addr = 0; - if (!chainup_buffers(req->dst, nbytes, req_ctx->dst, flags)) + BUG_ON(req->dst->length < nbytes); + req_ctx->dst = NULL; + if (!chainup_buffers(dev, req->dst, nbytes, &dst_hook, + flags, DMA_FROM_DEVICE)) goto free_buf_dest; src_direction = DMA_TO_DEVICE; + req_ctx->dst = dst_hook.next; + crypt->dst_buf = dst_hook.phys_next; } else { req_ctx->dst = NULL; - req_ctx->dst_nents = 0; } - nents = count_sg(req->src, nbytes); - req_ctx->src_nents = nents; - dma_map_sg(dev, req->src, nents, src_direction); - - req_ctx->src = dma_pool_alloc(buffer_pool, flags, &crypt->src_buf); - if (!req_ctx->src) - goto unmap_sg_src; - req_ctx->src->phys_addr = 0; - if (!chainup_buffers(req->src, nbytes, req_ctx->src, flags)) + req_ctx->src = NULL; + if (!chainup_buffers(dev, req->src, nbytes, &src_hook, + flags, src_direction)) goto free_buf_src; + req_ctx->src = src_hook.next; + crypt->src_buf = src_hook.phys_next; crypt->ctl_flags |= CTL_FLAG_PERFORM_ABLK; qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt)); BUG_ON(qmgr_stat_overflow(SEND_QID)); return -EINPROGRESS; free_buf_src: - free_buf_chain(req_ctx->src, crypt->src_buf); -unmap_sg_src: - dma_unmap_sg(dev, req->src, req_ctx->src_nents, src_direction); + free_buf_chain(dev, req_ctx->src, crypt->src_buf); free_buf_dest: if (req->src != req->dst) { - free_buf_chain(req_ctx->dst, crypt->dst_buf); -unmap_sg_dest: - dma_unmap_sg(dev, req->src, req_ctx->dst_nents, - DMA_FROM_DEVICE); + free_buf_chain(dev, req_ctx->dst, crypt->dst_buf); } crypt->ctl_flags = CTL_FLAG_UNUSED; - return ret; + return -ENOMEM; } static int ablk_encrypt(struct ablkcipher_request *req) @@ -985,7 +939,7 @@ static int hmac_inconsistent(struct scatterlist *sg, unsigned start, break; offset += sg->length; - sg = sg_next(sg); + sg = scatterwalk_sg_next(sg); } return (start + nbytes > offset + sg->length); } @@ -997,11 +951,10 @@ static int aead_perform(struct aead_request *req, int encrypt, struct ixp_ctx *ctx = crypto_aead_ctx(tfm); unsigned ivsize = crypto_aead_ivsize(tfm); unsigned authsize = crypto_aead_authsize(tfm); - int ret = -ENOMEM; struct ix_sa_dir *dir; struct crypt_ctl *crypt; - unsigned int cryptlen, nents; - struct buffer_desc *buf; + unsigned int cryptlen; + struct buffer_desc *buf, src_hook; struct aead_ctx *req_ctx = aead_request_ctx(req); gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; @@ -1022,7 +975,7 @@ static int aead_perform(struct aead_request *req, int encrypt, } crypt = get_crypt_desc(); if (!crypt) - return ret; + return -ENOMEM; crypt->data.aead_req = req; crypt->crypto_ctx = dir->npe_ctx_phys; @@ -1041,31 +994,27 @@ static int aead_perform(struct aead_request *req, int encrypt, BUG(); /* -ENOTSUP because of my lazyness */ } - req_ctx->buffer = dma_pool_alloc(buffer_pool, flags, &crypt->src_buf); - if (!req_ctx->buffer) - goto out; - req_ctx->buffer->phys_addr = 0; /* ASSOC data */ - nents = count_sg(req->assoc, req->assoclen); - req_ctx->assoc_nents = nents; - dma_map_sg(dev, req->assoc, nents, DMA_TO_DEVICE); - buf = chainup_buffers(req->assoc, req->assoclen, req_ctx->buffer,flags); + buf = chainup_buffers(dev, req->assoc, req->assoclen, &src_hook, + flags, DMA_TO_DEVICE); + req_ctx->buffer = src_hook.next; + crypt->src_buf = src_hook.phys_next; if (!buf) - goto unmap_sg_assoc; + goto out; /* IV */ sg_init_table(&req_ctx->ivlist, 1); sg_set_buf(&req_ctx->ivlist, iv, ivsize); - dma_map_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL); - buf = chainup_buffers(&req_ctx->ivlist, ivsize, buf, flags); + buf = chainup_buffers(dev, &req_ctx->ivlist, ivsize, buf, flags, + DMA_BIDIRECTIONAL); if (!buf) - goto unmap_sg_iv; + goto free_chain; if (unlikely(hmac_inconsistent(req->src, cryptlen, authsize))) { /* The 12 hmac bytes are scattered, * we need to copy them into a safe buffer */ req_ctx->hmac_virt = dma_pool_alloc(buffer_pool, flags, &crypt->icv_rev_aes); if (unlikely(!req_ctx->hmac_virt)) - goto unmap_sg_iv; + goto free_chain; if (!encrypt) { scatterwalk_map_and_copy(req_ctx->hmac_virt, req->src, cryptlen, authsize, 0); @@ -1075,33 +1024,28 @@ static int aead_perform(struct aead_request *req, int encrypt, req_ctx->hmac_virt = NULL; } /* Crypt */ - nents = count_sg(req->src, cryptlen + authsize); - req_ctx->src_nents = nents; - dma_map_sg(dev, req->src, nents, DMA_BIDIRECTIONAL); - buf = chainup_buffers(req->src, cryptlen + authsize, buf, flags); + buf = chainup_buffers(dev, req->src, cryptlen + authsize, buf, flags, + DMA_BIDIRECTIONAL); if (!buf) - goto unmap_sg_src; + goto free_hmac_virt; if (!req_ctx->hmac_virt) { crypt->icv_rev_aes = buf->phys_addr + buf->buf_len - authsize; } + crypt->ctl_flags |= CTL_FLAG_PERFORM_AEAD; qmgr_put_entry(SEND_QID, crypt_virt2phys(crypt)); BUG_ON(qmgr_stat_overflow(SEND_QID)); return -EINPROGRESS; -unmap_sg_src: - dma_unmap_sg(dev, req->src, req_ctx->src_nents, DMA_BIDIRECTIONAL); +free_hmac_virt: if (req_ctx->hmac_virt) { dma_pool_free(buffer_pool, req_ctx->hmac_virt, crypt->icv_rev_aes); } -unmap_sg_iv: - dma_unmap_sg(dev, &req_ctx->ivlist, 1, DMA_BIDIRECTIONAL); -unmap_sg_assoc: - dma_unmap_sg(dev, req->assoc, req_ctx->assoc_nents, DMA_TO_DEVICE); - free_buf_chain(req_ctx->buffer, crypt->src_buf); +free_chain: + free_buf_chain(dev, req_ctx->buffer, crypt->src_buf); out: crypt->ctl_flags = CTL_FLAG_UNUSED; - return ret; + return -ENOMEM; } static int aead_setup(struct crypto_aead *tfm, unsigned int authsize) diff --git a/trunk/drivers/edac/Kconfig b/trunk/drivers/edac/Kconfig index eee47fd16d79..e5f5c5a8ba6c 100644 --- a/trunk/drivers/edac/Kconfig +++ b/trunk/drivers/edac/Kconfig @@ -1,13 +1,12 @@ # # EDAC Kconfig -# Copyright (c) 2003 Linux Networx +# Copyright (c) 2008 Doug Thompson www.softwarebitmaker.com # Licensed and distributed under the GPL # menuconfig EDAC - bool "EDAC - error detection and reporting (EXPERIMENTAL)" + bool "EDAC - error detection and reporting" depends on HAS_IOMEM - depends on EXPERIMENTAL depends on X86 || PPC help EDAC is designed to report errors in the core system. @@ -40,6 +39,14 @@ config EDAC_DEBUG there're four debug levels (x=0,1,2,3 from low to high). Usually you should select 'N'. +config EDAC_DEBUG_VERBOSE + bool "More verbose debugging" + depends on EDAC_DEBUG + help + This option makes debugging information more verbose. + Source file name and line number where debugging message + printed will be added to debugging message. + config EDAC_MM_EDAC tristate "Main Memory EDAC (Error Detection And Correction) reporting" default y @@ -174,4 +181,27 @@ config EDAC_CELL Cell Broadband Engine internal memory controller on platform without a hypervisor +config EDAC_PPC4XX + tristate "PPC4xx IBM DDR2 Memory Controller" + depends on EDAC_MM_EDAC && 4xx + help + This enables support for EDAC on the ECC memory used + with the IBM DDR2 memory controller found in various + PowerPC 4xx embedded processors such as the 405EX[r], + 440SP, 440SPe, 460EX, 460GT and 460SX. + +config EDAC_AMD8131 + tristate "AMD8131 HyperTransport PCI-X Tunnel" + depends on EDAC_MM_EDAC && PCI + help + Support for error detection and correction on the + AMD8131 HyperTransport PCI-X Tunnel chip. + +config EDAC_AMD8111 + tristate "AMD8111 HyperTransport I/O Hub" + depends on EDAC_MM_EDAC && PCI + help + Support for error detection and correction on the + AMD8111 HyperTransport I/O Hub chip. + endif # EDAC diff --git a/trunk/drivers/edac/Makefile b/trunk/drivers/edac/Makefile index b75196927de3..a5fdcf02f591 100644 --- a/trunk/drivers/edac/Makefile +++ b/trunk/drivers/edac/Makefile @@ -34,4 +34,4 @@ obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o obj-$(CONFIG_EDAC_MPC85XX) += mpc85xx_edac.o obj-$(CONFIG_EDAC_MV64X60) += mv64x60_edac.o obj-$(CONFIG_EDAC_CELL) += cell_edac.o - +obj-$(CONFIG_EDAC_PPC4XX) += ppc4xx_edac.o diff --git a/trunk/drivers/edac/amd8111_edac.c b/trunk/drivers/edac/amd8111_edac.c new file mode 100644 index 000000000000..614692181120 --- /dev/null +++ b/trunk/drivers/edac/amd8111_edac.c @@ -0,0 +1,595 @@ +/* + * amd8111_edac.c, AMD8111 Hyper Transport chip EDAC kernel module + * + * Copyright (c) 2008 Wind River Systems, Inc. + * + * Authors: Cao Qingtao + * Benjamin Walsh + * Hu Yongqi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "edac_core.h" +#include "edac_module.h" +#include "amd8111_edac.h" + +#define AMD8111_EDAC_REVISION " Ver: 1.0.0 " __DATE__ +#define AMD8111_EDAC_MOD_STR "amd8111_edac" + +#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460 +static int edac_dev_idx; + +enum amd8111_edac_devs { + LPC_BRIDGE = 0, +}; + +enum amd8111_edac_pcis { + PCI_BRIDGE = 0, +}; + +/* Wrapper functions for accessing PCI configuration space */ +static int edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32) +{ + int ret; + + ret = pci_read_config_dword(dev, reg, val32); + if (ret != 0) + printk(KERN_ERR AMD8111_EDAC_MOD_STR + " PCI Access Read Error at 0x%x\n", reg); + + return ret; +} + +static void edac_pci_read_byte(struct pci_dev *dev, int reg, u8 *val8) +{ + int ret; + + ret = pci_read_config_byte(dev, reg, val8); + if (ret != 0) + printk(KERN_ERR AMD8111_EDAC_MOD_STR + " PCI Access Read Error at 0x%x\n", reg); +} + +static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32) +{ + int ret; + + ret = pci_write_config_dword(dev, reg, val32); + if (ret != 0) + printk(KERN_ERR AMD8111_EDAC_MOD_STR + " PCI Access Write Error at 0x%x\n", reg); +} + +static void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8) +{ + int ret; + + ret = pci_write_config_byte(dev, reg, val8); + if (ret != 0) + printk(KERN_ERR AMD8111_EDAC_MOD_STR + " PCI Access Write Error at 0x%x\n", reg); +} + +/* + * device-specific methods for amd8111 PCI Bridge Controller + * + * Error Reporting and Handling for amd8111 chipset could be found + * in its datasheet 3.1.2 section, P37 + */ +static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info) +{ + u32 val32; + struct pci_dev *dev = pci_info->dev; + + /* First clear error detection flags on the host interface */ + + /* Clear SSE/SMA/STA flags in the global status register*/ + edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); + if (val32 & PCI_STSCMD_CLEAR_MASK) + edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); + + /* Clear CRC and Link Fail flags in HT Link Control reg */ + edac_pci_read_dword(dev, REG_HT_LINK, &val32); + if (val32 & HT_LINK_CLEAR_MASK) + edac_pci_write_dword(dev, REG_HT_LINK, val32); + + /* Second clear all fault on the secondary interface */ + + /* Clear error flags in the memory-base limit reg. */ + edac_pci_read_dword(dev, REG_MEM_LIM, &val32); + if (val32 & MEM_LIMIT_CLEAR_MASK) + edac_pci_write_dword(dev, REG_MEM_LIM, val32); + + /* Clear Discard Timer Expired flag in Interrupt/Bridge Control reg */ + edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); + if (val32 & PCI_INTBRG_CTRL_CLEAR_MASK) + edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); + + /* Last enable error detections */ + if (edac_op_state == EDAC_OPSTATE_POLL) { + /* Enable System Error reporting in global status register */ + edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); + val32 |= PCI_STSCMD_SERREN; + edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); + + /* Enable CRC Sync flood packets to HyperTransport Link */ + edac_pci_read_dword(dev, REG_HT_LINK, &val32); + val32 |= HT_LINK_CRCFEN; + edac_pci_write_dword(dev, REG_HT_LINK, val32); + + /* Enable SSE reporting etc in Interrupt control reg */ + edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); + val32 |= PCI_INTBRG_CTRL_POLL_MASK; + edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); + } +} + +static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info) +{ + u32 val32; + struct pci_dev *dev = pci_info->dev; + + if (edac_op_state == EDAC_OPSTATE_POLL) { + /* Disable System Error reporting */ + edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); + val32 &= ~PCI_STSCMD_SERREN; + edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); + + /* Disable CRC flood packets */ + edac_pci_read_dword(dev, REG_HT_LINK, &val32); + val32 &= ~HT_LINK_CRCFEN; + edac_pci_write_dword(dev, REG_HT_LINK, val32); + + /* Disable DTSERREN/MARSP/SERREN in Interrupt Control reg */ + edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); + val32 &= ~PCI_INTBRG_CTRL_POLL_MASK; + edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); + } +} + +static void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev) +{ + struct amd8111_pci_info *pci_info = edac_dev->pvt_info; + struct pci_dev *dev = pci_info->dev; + u32 val32; + + /* Check out PCI Bridge Status and Command Register */ + edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32); + if (val32 & PCI_STSCMD_CLEAR_MASK) { + printk(KERN_INFO "Error(s) in PCI bridge status and command" + "register on device %s\n", pci_info->ctl_name); + printk(KERN_INFO "SSE: %d, RMA: %d, RTA: %d\n", + (val32 & PCI_STSCMD_SSE) != 0, + (val32 & PCI_STSCMD_RMA) != 0, + (val32 & PCI_STSCMD_RTA) != 0); + + val32 |= PCI_STSCMD_CLEAR_MASK; + edac_pci_write_dword(dev, REG_PCI_STSCMD, val32); + + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); + } + + /* Check out HyperTransport Link Control Register */ + edac_pci_read_dword(dev, REG_HT_LINK, &val32); + if (val32 & HT_LINK_LKFAIL) { + printk(KERN_INFO "Error(s) in hypertransport link control" + "register on device %s\n", pci_info->ctl_name); + printk(KERN_INFO "LKFAIL: %d\n", + (val32 & HT_LINK_LKFAIL) != 0); + + val32 |= HT_LINK_LKFAIL; + edac_pci_write_dword(dev, REG_HT_LINK, val32); + + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); + } + + /* Check out PCI Interrupt and Bridge Control Register */ + edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32); + if (val32 & PCI_INTBRG_CTRL_DTSTAT) { + printk(KERN_INFO "Error(s) in PCI interrupt and bridge control" + "register on device %s\n", pci_info->ctl_name); + printk(KERN_INFO "DTSTAT: %d\n", + (val32 & PCI_INTBRG_CTRL_DTSTAT) != 0); + + val32 |= PCI_INTBRG_CTRL_DTSTAT; + edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32); + + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); + } + + /* Check out PCI Bridge Memory Base-Limit Register */ + edac_pci_read_dword(dev, REG_MEM_LIM, &val32); + if (val32 & MEM_LIMIT_CLEAR_MASK) { + printk(KERN_INFO + "Error(s) in mem limit register on %s device\n", + pci_info->ctl_name); + printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n" + "RTA: %d, STA: %d, MDPE: %d\n", + (val32 & MEM_LIMIT_DPE) != 0, + (val32 & MEM_LIMIT_RSE) != 0, + (val32 & MEM_LIMIT_RMA) != 0, + (val32 & MEM_LIMIT_RTA) != 0, + (val32 & MEM_LIMIT_STA) != 0, + (val32 & MEM_LIMIT_MDPE) != 0); + + val32 |= MEM_LIMIT_CLEAR_MASK; + edac_pci_write_dword(dev, REG_MEM_LIM, val32); + + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); + } +} + +static struct resource *legacy_io_res; +static int at_compat_reg_broken; +#define LEGACY_NR_PORTS 1 + +/* device-specific methods for amd8111 LPC Bridge device */ +static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info) +{ + u8 val8; + struct pci_dev *dev = dev_info->dev; + + /* First clear REG_AT_COMPAT[SERR, IOCHK] if necessary */ + legacy_io_res = request_region(REG_AT_COMPAT, LEGACY_NR_PORTS, + AMD8111_EDAC_MOD_STR); + if (!legacy_io_res) + printk(KERN_INFO "%s: failed to request legacy I/O region " + "start %d, len %d\n", __func__, + REG_AT_COMPAT, LEGACY_NR_PORTS); + else { + val8 = __do_inb(REG_AT_COMPAT); + if (val8 == 0xff) { /* buggy port */ + printk(KERN_INFO "%s: port %d is buggy, not supported" + " by hardware?\n", __func__, REG_AT_COMPAT); + at_compat_reg_broken = 1; + release_region(REG_AT_COMPAT, LEGACY_NR_PORTS); + legacy_io_res = NULL; + } else { + u8 out8 = 0; + if (val8 & AT_COMPAT_SERR) + out8 = AT_COMPAT_CLRSERR; + if (val8 & AT_COMPAT_IOCHK) + out8 |= AT_COMPAT_CLRIOCHK; + if (out8 > 0) + __do_outb(out8, REG_AT_COMPAT); + } + } + + /* Second clear error flags on LPC bridge */ + edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8); + if (val8 & IO_CTRL_1_CLEAR_MASK) + edac_pci_write_byte(dev, REG_IO_CTRL_1, val8); +} + +static void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info) +{ + if (legacy_io_res) + release_region(REG_AT_COMPAT, LEGACY_NR_PORTS); +} + +static void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev) +{ + struct amd8111_dev_info *dev_info = edac_dev->pvt_info; + struct pci_dev *dev = dev_info->dev; + u8 val8; + + edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8); + if (val8 & IO_CTRL_1_CLEAR_MASK) { + printk(KERN_INFO + "Error(s) in IO control register on %s device\n", + dev_info->ctl_name); + printk(KERN_INFO "LPC ERR: %d, PW2LPC: %d\n", + (val8 & IO_CTRL_1_LPC_ERR) != 0, + (val8 & IO_CTRL_1_PW2LPC) != 0); + + val8 |= IO_CTRL_1_CLEAR_MASK; + edac_pci_write_byte(dev, REG_IO_CTRL_1, val8); + + edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); + } + + if (at_compat_reg_broken == 0) { + u8 out8 = 0; + val8 = __do_inb(REG_AT_COMPAT); + if (val8 & AT_COMPAT_SERR) + out8 = AT_COMPAT_CLRSERR; + if (val8 & AT_COMPAT_IOCHK) + out8 |= AT_COMPAT_CLRIOCHK; + if (out8 > 0) { + __do_outb(out8, REG_AT_COMPAT); + edac_device_handle_ue(edac_dev, 0, 0, + edac_dev->ctl_name); + } + } +} + +/* General devices represented by edac_device_ctl_info */ +static struct amd8111_dev_info amd8111_devices[] = { + [LPC_BRIDGE] = { + .err_dev = PCI_DEVICE_ID_AMD_8111_LPC, + .ctl_name = "lpc", + .init = amd8111_lpc_bridge_init, + .exit = amd8111_lpc_bridge_exit, + .check = amd8111_lpc_bridge_check, + }, + {0}, +}; + +/* PCI controllers represented by edac_pci_ctl_info */ +static struct amd8111_pci_info amd8111_pcis[] = { + [PCI_BRIDGE] = { + .err_dev = PCI_DEVICE_ID_AMD_8111_PCI, + .ctl_name = "AMD8111_PCI_Controller", + .init = amd8111_pci_bridge_init, + .exit = amd8111_pci_bridge_exit, + .check = amd8111_pci_bridge_check, + }, + {0}, +}; + +static int amd8111_dev_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data]; + + dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD, + dev_info->err_dev, NULL); + + if (!dev_info->dev) { + printk(KERN_ERR "EDAC device not found:" + "vendor %x, device %x, name %s\n", + PCI_VENDOR_ID_AMD, dev_info->err_dev, + dev_info->ctl_name); + return -ENODEV; + } + + if (pci_enable_device(dev_info->dev)) { + pci_dev_put(dev_info->dev); + printk(KERN_ERR "failed to enable:" + "vendor %x, device %x, name %s\n", + PCI_VENDOR_ID_AMD, dev_info->err_dev, + dev_info->ctl_name); + return -ENODEV; + } + + /* + * we do not allocate extra private structure for + * edac_device_ctl_info, but make use of existing + * one instead. + */ + dev_info->edac_idx = edac_dev_idx++; + dev_info->edac_dev = + edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1, + NULL, 0, 0, + NULL, 0, dev_info->edac_idx); + if (!dev_info->edac_dev) + return -ENOMEM; + + dev_info->edac_dev->pvt_info = dev_info; + dev_info->edac_dev->dev = &dev_info->dev->dev; + dev_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR; + dev_info->edac_dev->ctl_name = dev_info->ctl_name; + dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id; + + if (edac_op_state == EDAC_OPSTATE_POLL) + dev_info->edac_dev->edac_check = dev_info->check; + + if (dev_info->init) + dev_info->init(dev_info); + + if (edac_device_add_device(dev_info->edac_dev) > 0) { + printk(KERN_ERR "failed to add edac_dev for %s\n", + dev_info->ctl_name); + edac_device_free_ctl_info(dev_info->edac_dev); + return -ENODEV; + } + + printk(KERN_INFO "added one edac_dev on AMD8111 " + "vendor %x, device %x, name %s\n", + PCI_VENDOR_ID_AMD, dev_info->err_dev, + dev_info->ctl_name); + + return 0; +} + +static void amd8111_dev_remove(struct pci_dev *dev) +{ + struct amd8111_dev_info *dev_info; + + for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++) + if (dev_info->dev->device == dev->device) + break; + + if (!dev_info->err_dev) /* should never happen */ + return; + + if (dev_info->edac_dev) { + edac_device_del_device(dev_info->edac_dev->dev); + edac_device_free_ctl_info(dev_info->edac_dev); + } + + if (dev_info->exit) + dev_info->exit(dev_info); + + pci_dev_put(dev_info->dev); +} + +static int amd8111_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data]; + + pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD, + pci_info->err_dev, NULL); + + if (!pci_info->dev) { + printk(KERN_ERR "EDAC device not found:" + "vendor %x, device %x, name %s\n", + PCI_VENDOR_ID_AMD, pci_info->err_dev, + pci_info->ctl_name); + return -ENODEV; + } + + if (pci_enable_device(pci_info->dev)) { + pci_dev_put(pci_info->dev); + printk(KERN_ERR "failed to enable:" + "vendor %x, device %x, name %s\n", + PCI_VENDOR_ID_AMD, pci_info->err_dev, + pci_info->ctl_name); + return -ENODEV; + } + + /* + * we do not allocate extra private structure for + * edac_pci_ctl_info, but make use of existing + * one instead. + */ + pci_info->edac_idx = edac_pci_alloc_index(); + pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name); + if (!pci_info->edac_dev) + return -ENOMEM; + + pci_info->edac_dev->pvt_info = pci_info; + pci_info->edac_dev->dev = &pci_info->dev->dev; + pci_info->edac_dev->mod_name = AMD8111_EDAC_MOD_STR; + pci_info->edac_dev->ctl_name = pci_info->ctl_name; + pci_info->edac_dev->dev_name = pci_info->dev->dev.bus_id; + + if (edac_op_state == EDAC_OPSTATE_POLL) + pci_info->edac_dev->edac_check = pci_info->check; + + if (pci_info->init) + pci_info->init(pci_info); + + if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) { + printk(KERN_ERR "failed to add edac_pci for %s\n", + pci_info->ctl_name); + edac_pci_free_ctl_info(pci_info->edac_dev); + return -ENODEV; + } + + printk(KERN_INFO "added one edac_pci on AMD8111 " + "vendor %x, device %x, name %s\n", + PCI_VENDOR_ID_AMD, pci_info->err_dev, + pci_info->ctl_name); + + return 0; +} + +static void amd8111_pci_remove(struct pci_dev *dev) +{ + struct amd8111_pci_info *pci_info; + + for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++) + if (pci_info->dev->device == dev->device) + break; + + if (!pci_info->err_dev) /* should never happen */ + return; + + if (pci_info->edac_dev) { + edac_pci_del_device(pci_info->edac_dev->dev); + edac_pci_free_ctl_info(pci_info->edac_dev); + } + + if (pci_info->exit) + pci_info->exit(pci_info); + + pci_dev_put(pci_info->dev); +} + +/* PCI Device ID talbe for general EDAC device */ +static const struct pci_device_id amd8111_edac_dev_tbl[] = { + { + PCI_VEND_DEV(AMD, 8111_LPC), + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = LPC_BRIDGE, + }, + { + 0, + } /* table is NULL-terminated */ +}; +MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl); + +static struct pci_driver amd8111_edac_dev_driver = { + .name = "AMD8111_EDAC_DEV", + .probe = amd8111_dev_probe, + .remove = amd8111_dev_remove, + .id_table = amd8111_edac_dev_tbl, +}; + +/* PCI Device ID table for EDAC PCI controller */ +static const struct pci_device_id amd8111_edac_pci_tbl[] = { + { + PCI_VEND_DEV(AMD, 8111_PCI), + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = PCI_BRIDGE, + }, + { + 0, + } /* table is NULL-terminated */ +}; +MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl); + +static struct pci_driver amd8111_edac_pci_driver = { + .name = "AMD8111_EDAC_PCI", + .probe = amd8111_pci_probe, + .remove = amd8111_pci_remove, + .id_table = amd8111_edac_pci_tbl, +}; + +static int __init amd8111_edac_init(void) +{ + int val; + + printk(KERN_INFO "AMD8111 EDAC driver " AMD8111_EDAC_REVISION "\n"); + printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n"); + + /* Only POLL mode supported so far */ + edac_op_state = EDAC_OPSTATE_POLL; + + val = pci_register_driver(&amd8111_edac_dev_driver); + val |= pci_register_driver(&amd8111_edac_pci_driver); + + return val; +} + +static void __exit amd8111_edac_exit(void) +{ + pci_unregister_driver(&amd8111_edac_pci_driver); + pci_unregister_driver(&amd8111_edac_dev_driver); +} + + +module_init(amd8111_edac_init); +module_exit(amd8111_edac_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cao Qingtao \n"); +MODULE_DESCRIPTION("AMD8111 HyperTransport I/O Hub EDAC kernel module"); diff --git a/trunk/drivers/edac/amd8111_edac.h b/trunk/drivers/edac/amd8111_edac.h new file mode 100644 index 000000000000..35794331debc --- /dev/null +++ b/trunk/drivers/edac/amd8111_edac.h @@ -0,0 +1,130 @@ +/* + * amd8111_edac.h, EDAC defs for AMD8111 hypertransport chip + * + * Copyright (c) 2008 Wind River Systems, Inc. + * + * Authors: Cao Qingtao + * Benjamin Walsh + * Hu Yongqi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This 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 + */ + +#ifndef _AMD8111_EDAC_H_ +#define _AMD8111_EDAC_H_ + +/************************************************************ + * PCI Bridge Status and Command Register, DevA:0x04 + ************************************************************/ +#define REG_PCI_STSCMD 0x04 +enum pci_stscmd_bits { + PCI_STSCMD_SSE = BIT(30), + PCI_STSCMD_RMA = BIT(29), + PCI_STSCMD_RTA = BIT(28), + PCI_STSCMD_SERREN = BIT(8), + PCI_STSCMD_CLEAR_MASK = (PCI_STSCMD_SSE | + PCI_STSCMD_RMA | + PCI_STSCMD_RTA) +}; + +/************************************************************ + * PCI Bridge Memory Base-Limit Register, DevA:0x1c + ************************************************************/ +#define REG_MEM_LIM 0x1c +enum mem_limit_bits { + MEM_LIMIT_DPE = BIT(31), + MEM_LIMIT_RSE = BIT(30), + MEM_LIMIT_RMA = BIT(29), + MEM_LIMIT_RTA = BIT(28), + MEM_LIMIT_STA = BIT(27), + MEM_LIMIT_MDPE = BIT(24), + MEM_LIMIT_CLEAR_MASK = (MEM_LIMIT_DPE | + MEM_LIMIT_RSE | + MEM_LIMIT_RMA | + MEM_LIMIT_RTA | + MEM_LIMIT_STA | + MEM_LIMIT_MDPE) +}; + +/************************************************************ + * HyperTransport Link Control Register, DevA:0xc4 + ************************************************************/ +#define REG_HT_LINK 0xc4 +enum ht_link_bits { + HT_LINK_LKFAIL = BIT(4), + HT_LINK_CRCFEN = BIT(1), + HT_LINK_CLEAR_MASK = (HT_LINK_LKFAIL) +}; + +/************************************************************ + * PCI Bridge Interrupt and Bridge Control, DevA:0x3c + ************************************************************/ +#define REG_PCI_INTBRG_CTRL 0x3c +enum pci_intbrg_ctrl_bits { + PCI_INTBRG_CTRL_DTSERREN = BIT(27), + PCI_INTBRG_CTRL_DTSTAT = BIT(26), + PCI_INTBRG_CTRL_MARSP = BIT(21), + PCI_INTBRG_CTRL_SERREN = BIT(17), + PCI_INTBRG_CTRL_PEREN = BIT(16), + PCI_INTBRG_CTRL_CLEAR_MASK = (PCI_INTBRG_CTRL_DTSTAT), + PCI_INTBRG_CTRL_POLL_MASK = (PCI_INTBRG_CTRL_DTSERREN | + PCI_INTBRG_CTRL_MARSP | + PCI_INTBRG_CTRL_SERREN) +}; + +/************************************************************ + * I/O Control 1 Register, DevB:0x40 + ************************************************************/ +#define REG_IO_CTRL_1 0x40 +enum io_ctrl_1_bits { + IO_CTRL_1_NMIONERR = BIT(7), + IO_CTRL_1_LPC_ERR = BIT(6), + IO_CTRL_1_PW2LPC = BIT(1), + IO_CTRL_1_CLEAR_MASK = (IO_CTRL_1_LPC_ERR | IO_CTRL_1_PW2LPC) +}; + +/************************************************************ + * Legacy I/O Space Registers + ************************************************************/ +#define REG_AT_COMPAT 0x61 +enum at_compat_bits { + AT_COMPAT_SERR = BIT(7), + AT_COMPAT_IOCHK = BIT(6), + AT_COMPAT_CLRIOCHK = BIT(3), + AT_COMPAT_CLRSERR = BIT(2), +}; + +struct amd8111_dev_info { + u16 err_dev; /* PCI Device ID */ + struct pci_dev *dev; + int edac_idx; /* device index */ + char *ctl_name; + struct edac_device_ctl_info *edac_dev; + void (*init)(struct amd8111_dev_info *dev_info); + void (*exit)(struct amd8111_dev_info *dev_info); + void (*check)(struct edac_device_ctl_info *edac_dev); +}; + +struct amd8111_pci_info { + u16 err_dev; /* PCI Device ID */ + struct pci_dev *dev; + int edac_idx; /* pci index */ + const char *ctl_name; + struct edac_pci_ctl_info *edac_dev; + void (*init)(struct amd8111_pci_info *dev_info); + void (*exit)(struct amd8111_pci_info *dev_info); + void (*check)(struct edac_pci_ctl_info *edac_dev); +}; + +#endif /* _AMD8111_EDAC_H_ */ diff --git a/trunk/drivers/edac/amd8131_edac.c b/trunk/drivers/edac/amd8131_edac.c new file mode 100644 index 000000000000..c083b31cac5a --- /dev/null +++ b/trunk/drivers/edac/amd8131_edac.c @@ -0,0 +1,379 @@ +/* + * amd8131_edac.c, AMD8131 hypertransport chip EDAC kernel module + * + * Copyright (c) 2008 Wind River Systems, Inc. + * + * Authors: Cao Qingtao + * Benjamin Walsh + * Hu Yongqi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "edac_core.h" +#include "edac_module.h" +#include "amd8131_edac.h" + +#define AMD8131_EDAC_REVISION " Ver: 1.0.0 " __DATE__ +#define AMD8131_EDAC_MOD_STR "amd8131_edac" + +/* Wrapper functions for accessing PCI configuration space */ +static void edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32) +{ + int ret; + + ret = pci_read_config_dword(dev, reg, val32); + if (ret != 0) + printk(KERN_ERR AMD8131_EDAC_MOD_STR + " PCI Access Read Error at 0x%x\n", reg); +} + +static void edac_pci_write_dword(struct pci_dev *dev, int reg, u32 val32) +{ + int ret; + + ret = pci_write_config_dword(dev, reg, val32); + if (ret != 0) + printk(KERN_ERR AMD8131_EDAC_MOD_STR + " PCI Access Write Error at 0x%x\n", reg); +} + +static char * const bridge_str[] = { + [NORTH_A] = "NORTH A", + [NORTH_B] = "NORTH B", + [SOUTH_A] = "SOUTH A", + [SOUTH_B] = "SOUTH B", + [NO_BRIDGE] = "NO BRIDGE", +}; + +/* Support up to two AMD8131 chipsets on a platform */ +static struct amd8131_dev_info amd8131_devices[] = { + { + .inst = NORTH_A, + .devfn = DEVFN_PCIX_BRIDGE_NORTH_A, + .ctl_name = "AMD8131_PCIX_NORTH_A", + }, + { + .inst = NORTH_B, + .devfn = DEVFN_PCIX_BRIDGE_NORTH_B, + .ctl_name = "AMD8131_PCIX_NORTH_B", + }, + { + .inst = SOUTH_A, + .devfn = DEVFN_PCIX_BRIDGE_SOUTH_A, + .ctl_name = "AMD8131_PCIX_SOUTH_A", + }, + { + .inst = SOUTH_B, + .devfn = DEVFN_PCIX_BRIDGE_SOUTH_B, + .ctl_name = "AMD8131_PCIX_SOUTH_B", + }, + {.inst = NO_BRIDGE,}, +}; + +static void amd8131_pcix_init(struct amd8131_dev_info *dev_info) +{ + u32 val32; + struct pci_dev *dev = dev_info->dev; + + /* First clear error detection flags */ + edac_pci_read_dword(dev, REG_MEM_LIM, &val32); + if (val32 & MEM_LIMIT_MASK) + edac_pci_write_dword(dev, REG_MEM_LIM, val32); + + /* Clear Discard Timer Timedout flag */ + edac_pci_read_dword(dev, REG_INT_CTLR, &val32); + if (val32 & INT_CTLR_DTS) + edac_pci_write_dword(dev, REG_INT_CTLR, val32); + + /* Clear CRC Error flag on link side A */ + edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); + if (val32 & LNK_CTRL_CRCERR_A) + edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); + + /* Clear CRC Error flag on link side B */ + edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); + if (val32 & LNK_CTRL_CRCERR_B) + edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); + + /* + * Then enable all error detections. + * + * Setup Discard Timer Sync Flood Enable, + * System Error Enable and Parity Error Enable. + */ + edac_pci_read_dword(dev, REG_INT_CTLR, &val32); + val32 |= INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE; + edac_pci_write_dword(dev, REG_INT_CTLR, val32); + + /* Enable overall SERR Error detection */ + edac_pci_read_dword(dev, REG_STS_CMD, &val32); + val32 |= STS_CMD_SERREN; + edac_pci_write_dword(dev, REG_STS_CMD, val32); + + /* Setup CRC Flood Enable for link side A */ + edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); + val32 |= LNK_CTRL_CRCFEN; + edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); + + /* Setup CRC Flood Enable for link side B */ + edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); + val32 |= LNK_CTRL_CRCFEN; + edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); +} + +static void amd8131_pcix_exit(struct amd8131_dev_info *dev_info) +{ + u32 val32; + struct pci_dev *dev = dev_info->dev; + + /* Disable SERR, PERR and DTSE Error detection */ + edac_pci_read_dword(dev, REG_INT_CTLR, &val32); + val32 &= ~(INT_CTLR_PERR | INT_CTLR_SERR | INT_CTLR_DTSE); + edac_pci_write_dword(dev, REG_INT_CTLR, val32); + + /* Disable overall System Error detection */ + edac_pci_read_dword(dev, REG_STS_CMD, &val32); + val32 &= ~STS_CMD_SERREN; + edac_pci_write_dword(dev, REG_STS_CMD, val32); + + /* Disable CRC Sync Flood on link side A */ + edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); + val32 &= ~LNK_CTRL_CRCFEN; + edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); + + /* Disable CRC Sync Flood on link side B */ + edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); + val32 &= ~LNK_CTRL_CRCFEN; + edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); +} + +static void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev) +{ + struct amd8131_dev_info *dev_info = edac_dev->pvt_info; + struct pci_dev *dev = dev_info->dev; + u32 val32; + + /* Check PCI-X Bridge Memory Base-Limit Register for errors */ + edac_pci_read_dword(dev, REG_MEM_LIM, &val32); + if (val32 & MEM_LIMIT_MASK) { + printk(KERN_INFO "Error(s) in mem limit register " + "on %s bridge\n", dev_info->ctl_name); + printk(KERN_INFO "DPE: %d, RSE: %d, RMA: %d\n" + "RTA: %d, STA: %d, MDPE: %d\n", + val32 & MEM_LIMIT_DPE, + val32 & MEM_LIMIT_RSE, + val32 & MEM_LIMIT_RMA, + val32 & MEM_LIMIT_RTA, + val32 & MEM_LIMIT_STA, + val32 & MEM_LIMIT_MDPE); + + val32 |= MEM_LIMIT_MASK; + edac_pci_write_dword(dev, REG_MEM_LIM, val32); + + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); + } + + /* Check if Discard Timer timed out */ + edac_pci_read_dword(dev, REG_INT_CTLR, &val32); + if (val32 & INT_CTLR_DTS) { + printk(KERN_INFO "Error(s) in interrupt and control register " + "on %s bridge\n", dev_info->ctl_name); + printk(KERN_INFO "DTS: %d\n", val32 & INT_CTLR_DTS); + + val32 |= INT_CTLR_DTS; + edac_pci_write_dword(dev, REG_INT_CTLR, val32); + + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); + } + + /* Check if CRC error happens on link side A */ + edac_pci_read_dword(dev, REG_LNK_CTRL_A, &val32); + if (val32 & LNK_CTRL_CRCERR_A) { + printk(KERN_INFO "Error(s) in link conf and control register " + "on %s bridge\n", dev_info->ctl_name); + printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_A); + + val32 |= LNK_CTRL_CRCERR_A; + edac_pci_write_dword(dev, REG_LNK_CTRL_A, val32); + + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); + } + + /* Check if CRC error happens on link side B */ + edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32); + if (val32 & LNK_CTRL_CRCERR_B) { + printk(KERN_INFO "Error(s) in link conf and control register " + "on %s bridge\n", dev_info->ctl_name); + printk(KERN_INFO "CRCERR: %d\n", val32 & LNK_CTRL_CRCERR_B); + + val32 |= LNK_CTRL_CRCERR_B; + edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32); + + edac_pci_handle_npe(edac_dev, edac_dev->ctl_name); + } +} + +static struct amd8131_info amd8131_chipset = { + .err_dev = PCI_DEVICE_ID_AMD_8131_APIC, + .devices = amd8131_devices, + .init = amd8131_pcix_init, + .exit = amd8131_pcix_exit, + .check = amd8131_pcix_check, +}; + +/* + * There are 4 PCIX Bridges on ATCA-6101 that share the same PCI Device ID, + * so amd8131_probe() would be called by kernel 4 times, with different + * address of pci_dev for each of them each time. + */ +static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct amd8131_dev_info *dev_info; + + for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE; + dev_info++) + if (dev_info->devfn == dev->devfn) + break; + + if (dev_info->inst == NO_BRIDGE) /* should never happen */ + return -ENODEV; + + /* + * We can't call pci_get_device() as we are used to do because + * there are 4 of them but pci_dev_get() instead. + */ + dev_info->dev = pci_dev_get(dev); + + if (pci_enable_device(dev_info->dev)) { + pci_dev_put(dev_info->dev); + printk(KERN_ERR "failed to enable:" + "vendor %x, device %x, devfn %x, name %s\n", + PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev, + dev_info->devfn, dev_info->ctl_name); + return -ENODEV; + } + + /* + * we do not allocate extra private structure for + * edac_pci_ctl_info, but make use of existing + * one instead. + */ + dev_info->edac_idx = edac_pci_alloc_index(); + dev_info->edac_dev = edac_pci_alloc_ctl_info(0, dev_info->ctl_name); + if (!dev_info->edac_dev) + return -ENOMEM; + + dev_info->edac_dev->pvt_info = dev_info; + dev_info->edac_dev->dev = &dev_info->dev->dev; + dev_info->edac_dev->mod_name = AMD8131_EDAC_MOD_STR; + dev_info->edac_dev->ctl_name = dev_info->ctl_name; + dev_info->edac_dev->dev_name = dev_info->dev->dev.bus_id; + + if (edac_op_state == EDAC_OPSTATE_POLL) + dev_info->edac_dev->edac_check = amd8131_chipset.check; + + if (amd8131_chipset.init) + amd8131_chipset.init(dev_info); + + if (edac_pci_add_device(dev_info->edac_dev, dev_info->edac_idx) > 0) { + printk(KERN_ERR "failed edac_pci_add_device() for %s\n", + dev_info->ctl_name); + edac_pci_free_ctl_info(dev_info->edac_dev); + return -ENODEV; + } + + printk(KERN_INFO "added one device on AMD8131 " + "vendor %x, device %x, devfn %x, name %s\n", + PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev, + dev_info->devfn, dev_info->ctl_name); + + return 0; +} + +static void amd8131_remove(struct pci_dev *dev) +{ + struct amd8131_dev_info *dev_info; + + for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE; + dev_info++) + if (dev_info->devfn == dev->devfn) + break; + + if (dev_info->inst == NO_BRIDGE) /* should never happen */ + return; + + if (dev_info->edac_dev) { + edac_pci_del_device(dev_info->edac_dev->dev); + edac_pci_free_ctl_info(dev_info->edac_dev); + } + + if (amd8131_chipset.exit) + amd8131_chipset.exit(dev_info); + + pci_dev_put(dev_info->dev); +} + +static const struct pci_device_id amd8131_edac_pci_tbl[] = { + { + PCI_VEND_DEV(AMD, 8131_BRIDGE), + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = 0, + }, + { + 0, + } /* table is NULL-terminated */ +}; +MODULE_DEVICE_TABLE(pci, amd8131_edac_pci_tbl); + +static struct pci_driver amd8131_edac_driver = { + .name = AMD8131_EDAC_MOD_STR, + .probe = amd8131_probe, + .remove = amd8131_remove, + .id_table = amd8131_edac_pci_tbl, +}; + +static int __init amd8131_edac_init(void) +{ + printk(KERN_INFO "AMD8131 EDAC driver " AMD8131_EDAC_REVISION "\n"); + printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n"); + + /* Only POLL mode supported so far */ + edac_op_state = EDAC_OPSTATE_POLL; + + return pci_register_driver(&amd8131_edac_driver); +} + +static void __exit amd8131_edac_exit(void) +{ + pci_unregister_driver(&amd8131_edac_driver); +} + +module_init(amd8131_edac_init); +module_exit(amd8131_edac_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cao Qingtao \n"); +MODULE_DESCRIPTION("AMD8131 HyperTransport PCI-X Tunnel EDAC kernel module"); diff --git a/trunk/drivers/edac/amd8131_edac.h b/trunk/drivers/edac/amd8131_edac.h new file mode 100644 index 000000000000..60e0d1c72dee --- /dev/null +++ b/trunk/drivers/edac/amd8131_edac.h @@ -0,0 +1,119 @@ +/* + * amd8131_edac.h, EDAC defs for AMD8131 hypertransport chip + * + * Copyright (c) 2008 Wind River Systems, Inc. + * + * Authors: Cao Qingtao + * Benjamin Walsh + * Hu Yongqi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This 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 + */ + +#ifndef _AMD8131_EDAC_H_ +#define _AMD8131_EDAC_H_ + +#define DEVFN_PCIX_BRIDGE_NORTH_A 8 +#define DEVFN_PCIX_BRIDGE_NORTH_B 16 +#define DEVFN_PCIX_BRIDGE_SOUTH_A 24 +#define DEVFN_PCIX_BRIDGE_SOUTH_B 32 + +/************************************************************ + * PCI-X Bridge Status and Command Register, DevA:0x04 + ************************************************************/ +#define REG_STS_CMD 0x04 +enum sts_cmd_bits { + STS_CMD_SSE = BIT(30), + STS_CMD_SERREN = BIT(8) +}; + +/************************************************************ + * PCI-X Bridge Interrupt and Bridge Control Register, + ************************************************************/ +#define REG_INT_CTLR 0x3c +enum int_ctlr_bits { + INT_CTLR_DTSE = BIT(27), + INT_CTLR_DTS = BIT(26), + INT_CTLR_SERR = BIT(17), + INT_CTLR_PERR = BIT(16) +}; + +/************************************************************ + * PCI-X Bridge Memory Base-Limit Register, DevA:0x1C + ************************************************************/ +#define REG_MEM_LIM 0x1c +enum mem_limit_bits { + MEM_LIMIT_DPE = BIT(31), + MEM_LIMIT_RSE = BIT(30), + MEM_LIMIT_RMA = BIT(29), + MEM_LIMIT_RTA = BIT(28), + MEM_LIMIT_STA = BIT(27), + MEM_LIMIT_MDPE = BIT(24), + MEM_LIMIT_MASK = MEM_LIMIT_DPE|MEM_LIMIT_RSE|MEM_LIMIT_RMA| + MEM_LIMIT_RTA|MEM_LIMIT_STA|MEM_LIMIT_MDPE +}; + +/************************************************************ + * Link Configuration And Control Register, side A + ************************************************************/ +#define REG_LNK_CTRL_A 0xc4 + +/************************************************************ + * Link Configuration And Control Register, side B + ************************************************************/ +#define REG_LNK_CTRL_B 0xc8 + +enum lnk_ctrl_bits { + LNK_CTRL_CRCERR_A = BIT(9), + LNK_CTRL_CRCERR_B = BIT(8), + LNK_CTRL_CRCFEN = BIT(1) +}; + +enum pcix_bridge_inst { + NORTH_A = 0, + NORTH_B = 1, + SOUTH_A = 2, + SOUTH_B = 3, + NO_BRIDGE = 4 +}; + +struct amd8131_dev_info { + int devfn; + enum pcix_bridge_inst inst; + struct pci_dev *dev; + int edac_idx; /* pci device index */ + char *ctl_name; + struct edac_pci_ctl_info *edac_dev; +}; + +/* + * AMD8131 chipset has two pairs of PCIX Bridge and related IOAPIC + * Controler, and ATCA-6101 has two AMD8131 chipsets, so there are + * four PCIX Bridges on ATCA-6101 altogether. + * + * These PCIX Bridges share the same PCI Device ID and are all of + * Function Zero, they could be discrimated by their pci_dev->devfn. + * They share the same set of init/check/exit methods, and their + * private structures are collected in the devices[] array. + */ +struct amd8131_info { + u16 err_dev; /* PCI Device ID for AMD8131 APIC*/ + struct amd8131_dev_info *devices; + void (*init)(struct amd8131_dev_info *dev_info); + void (*exit)(struct amd8131_dev_info *dev_info); + void (*check)(struct edac_pci_ctl_info *edac_dev); +}; + +#endif /* _AMD8131_EDAC_H_ */ + diff --git a/trunk/drivers/edac/edac_core.h b/trunk/drivers/edac/edac_core.h index 4b55ec607a88..28f2c3f959b5 100644 --- a/trunk/drivers/edac/edac_core.h +++ b/trunk/drivers/edac/edac_core.h @@ -49,6 +49,10 @@ #define edac_printk(level, prefix, fmt, arg...) \ printk(level "EDAC " prefix ": " fmt, ##arg) +#define edac_printk_verbose(level, prefix, fmt, arg...) \ + printk(level "EDAC " prefix ": " "in %s, line at %d: " fmt, \ + __FILE__, __LINE__, ##arg) + #define edac_mc_printk(mci, level, fmt, arg...) \ printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg) @@ -71,11 +75,20 @@ #ifdef CONFIG_EDAC_DEBUG extern int edac_debug_level; +#ifndef CONFIG_EDAC_DEBUG_VERBOSE #define edac_debug_printk(level, fmt, arg...) \ do { \ if (level <= edac_debug_level) \ edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \ - } while(0) + } while (0) +#else /* CONFIG_EDAC_DEBUG_VERBOSE */ +#define edac_debug_printk(level, fmt, arg...) \ + do { \ + if (level <= edac_debug_level) \ + edac_printk_verbose(KERN_DEBUG, EDAC_DEBUG, fmt, \ + ##arg); \ + } while (0) +#endif #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) #define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ ) @@ -831,6 +844,7 @@ extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci); extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, unsigned long value); +extern int edac_pci_alloc_index(void); extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx); extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev); diff --git a/trunk/drivers/edac/edac_pci.c b/trunk/drivers/edac/edac_pci.c index 5d3c8083a40e..5b150aea703a 100644 --- a/trunk/drivers/edac/edac_pci.c +++ b/trunk/drivers/edac/edac_pci.c @@ -30,6 +30,7 @@ static DEFINE_MUTEX(edac_pci_ctls_mutex); static LIST_HEAD(edac_pci_list); +static atomic_t pci_indexes = ATOMIC_INIT(0); /* * edac_pci_alloc_ctl_info @@ -317,6 +318,19 @@ void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, } EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period); +/* + * edac_pci_alloc_index: Allocate a unique PCI index number + * + * Return: + * allocated index number + * + */ +int edac_pci_alloc_index(void) +{ + return atomic_inc_return(&pci_indexes) - 1; +} +EXPORT_SYMBOL_GPL(edac_pci_alloc_index); + /* * edac_pci_add_device: Insert the 'edac_dev' structure into the * edac_pci global list and create sysfs entries associated with diff --git a/trunk/drivers/edac/ppc4xx_edac.c b/trunk/drivers/edac/ppc4xx_edac.c new file mode 100644 index 000000000000..11f2172aa1e6 --- /dev/null +++ b/trunk/drivers/edac/ppc4xx_edac.c @@ -0,0 +1,1448 @@ +/* + * Copyright (c) 2008 Nuovation System Designs, LLC + * Grant Erickson + * + * 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 of the + * License. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "edac_core.h" +#include "ppc4xx_edac.h" + +/* + * This file implements a driver for monitoring and handling events + * associated with the IMB DDR2 ECC controller found in the AMCC/IBM + * 405EX[r], 440SP, 440SPe, 460EX, 460GT and 460SX. + * + * As realized in the 405EX[r], this controller features: + * + * - Support for registered- and non-registered DDR1 and DDR2 memory. + * - 32-bit or 16-bit memory interface with optional ECC. + * + * o ECC support includes: + * + * - 4-bit SEC/DED + * - Aligned-nibble error detect + * - Bypass mode + * + * - Two (2) memory banks/ranks. + * - Up to 1 GiB per bank/rank in 32-bit mode and up to 512 MiB per + * bank/rank in 16-bit mode. + * + * As realized in the 440SP and 440SPe, this controller changes/adds: + * + * - 64-bit or 32-bit memory interface with optional ECC. + * + * o ECC support includes: + * + * - 8-bit SEC/DED + * - Aligned-nibble error detect + * - Bypass mode + * + * - Up to 4 GiB per bank/rank in 64-bit mode and up to 2 GiB + * per bank/rank in 32-bit mode. + * + * As realized in the 460EX and 460GT, this controller changes/adds: + * + * - 64-bit or 32-bit memory interface with optional ECC. + * + * o ECC support includes: + * + * - 8-bit SEC/DED + * - Aligned-nibble error detect + * - Bypass mode + * + * - Four (4) memory banks/ranks. + * - Up to 16 GiB per bank/rank in 64-bit mode and up to 8 GiB + * per bank/rank in 32-bit mode. + * + * At present, this driver has ONLY been tested against the controller + * realization in the 405EX[r] on the AMCC Kilauea and Haleakala + * boards (256 MiB w/o ECC memory soldered onto the board) and a + * proprietary board based on those designs (128 MiB ECC memory, also + * soldered onto the board). + * + * Dynamic feature detection and handling needs to be added for the + * other realizations of this controller listed above. + * + * Eventually, this driver will likely be adapted to the above variant + * realizations of this controller as well as broken apart to handle + * the other known ECC-capable controllers prevalent in other 4xx + * processors: + * + * - IBM SDRAM (405GP, 405CR and 405EP) "ibm,sdram-4xx" + * - IBM DDR1 (440GP, 440GX, 440EP and 440GR) "ibm,sdram-4xx-ddr" + * - Denali DDR1/DDR2 (440EPX and 440GRX) "denali,sdram-4xx-ddr2" + * + * For this controller, unfortunately, correctable errors report + * nothing more than the beat/cycle and byte/lane the correction + * occurred on and the check bit group that covered the error. + * + * In contrast, uncorrectable errors also report the failing address, + * the bus master and the transaction direction (i.e. read or write) + * + * Regardless of whether the error is a CE or a UE, we report the + * following pieces of information in the driver-unique message to the + * EDAC subsystem: + * + * - Device tree path + * - Bank(s) + * - Check bit error group + * - Beat(s)/lane(s) + */ + +/* Preprocessor Definitions */ + +#define EDAC_OPSTATE_INT_STR "interrupt" +#define EDAC_OPSTATE_POLL_STR "polled" +#define EDAC_OPSTATE_UNKNOWN_STR "unknown" + +#define PPC4XX_EDAC_MODULE_NAME "ppc4xx_edac" +#define PPC4XX_EDAC_MODULE_REVISION "v1.0.0 " __DATE__ + +#define PPC4XX_EDAC_MESSAGE_SIZE 256 + +/* + * Kernel logging without an EDAC instance + */ +#define ppc4xx_edac_printk(level, fmt, arg...) \ + edac_printk(level, "PPC4xx MC", fmt, ##arg) + +/* + * Kernel logging with an EDAC instance + */ +#define ppc4xx_edac_mc_printk(level, mci, fmt, arg...) \ + edac_mc_chipset_printk(mci, level, "PPC4xx", fmt, ##arg) + +/* + * Macros to convert bank configuration size enumerations into MiB and + * page values. + */ +#define SDRAM_MBCF_SZ_MiB_MIN 4 +#define SDRAM_MBCF_SZ_TO_MiB(n) (SDRAM_MBCF_SZ_MiB_MIN \ + << (SDRAM_MBCF_SZ_DECODE(n))) +#define SDRAM_MBCF_SZ_TO_PAGES(n) (SDRAM_MBCF_SZ_MiB_MIN \ + << (20 - PAGE_SHIFT + \ + SDRAM_MBCF_SZ_DECODE(n))) + +/* + * The ibm,sdram-4xx-ddr2 Device Control Registers (DCRs) are + * indirectly acccessed and have a base and length defined by the + * device tree. The base can be anything; however, we expect the + * length to be precisely two registers, the first for the address + * window and the second for the data window. + */ +#define SDRAM_DCR_RESOURCE_LEN 2 +#define SDRAM_DCR_ADDR_OFFSET 0 +#define SDRAM_DCR_DATA_OFFSET 1 + +/* + * Device tree interrupt indices + */ +#define INTMAP_ECCDED_INDEX 0 /* Double-bit Error Detect */ +#define INTMAP_ECCSEC_INDEX 1 /* Single-bit Error Correct */ + +/* Type Definitions */ + +/* + * PPC4xx SDRAM memory controller private instance data + */ +struct ppc4xx_edac_pdata { + dcr_host_t dcr_host; /* Indirect DCR address/data window mapping */ + struct { + int sec; /* Single-bit correctable error IRQ assigned */ + int ded; /* Double-bit detectable error IRQ assigned */ + } irqs; +}; + +/* + * Various status data gathered and manipulated when checking and + * reporting ECC status. + */ +struct ppc4xx_ecc_status { + u32 ecces; + u32 besr; + u32 bearh; + u32 bearl; + u32 wmirq; +}; + +/* Function Prototypes */ + +static int ppc4xx_edac_probe(struct of_device *device, + const struct of_device_id *device_id); +static int ppc4xx_edac_remove(struct of_device *device); + +/* Global Variables */ + +/* + * Device tree node type and compatible tuples this driver can match + * on. + */ +static struct of_device_id ppc4xx_edac_match[] = { + { + .compatible = "ibm,sdram-4xx-ddr2" + }, + { } +}; + +static struct of_platform_driver ppc4xx_edac_driver = { + .match_table = ppc4xx_edac_match, + .probe = ppc4xx_edac_probe, + .remove = ppc4xx_edac_remove, + .driver = { + .owner = THIS_MODULE, + .name = PPC4XX_EDAC_MODULE_NAME + } +}; + +/* + * TODO: The row and channel parameters likely need to be dynamically + * set based on the aforementioned variant controller realizations. + */ +static const unsigned ppc4xx_edac_nr_csrows = 2; +static const unsigned ppc4xx_edac_nr_chans = 1; + +/* + * Strings associated with PLB master IDs capable of being posted in + * SDRAM_BESR or SDRAM_WMIRQ on uncorrectable ECC errors. + */ +static const char * const ppc4xx_plb_masters[9] = { + [SDRAM_PLB_M0ID_ICU] = "ICU", + [SDRAM_PLB_M0ID_PCIE0] = "PCI-E 0", + [SDRAM_PLB_M0ID_PCIE1] = "PCI-E 1", + [SDRAM_PLB_M0ID_DMA] = "DMA", + [SDRAM_PLB_M0ID_DCU] = "DCU", + [SDRAM_PLB_M0ID_OPB] = "OPB", + [SDRAM_PLB_M0ID_MAL] = "MAL", + [SDRAM_PLB_M0ID_SEC] = "SEC", + [SDRAM_PLB_M0ID_AHB] = "AHB" +}; + +/** + * mfsdram - read and return controller register data + * @dcr_host: A pointer to the DCR mapping. + * @idcr_n: The indirect DCR register to read. + * + * This routine reads and returns the data associated with the + * controller's specified indirect DCR register. + * + * Returns the read data. + */ +static inline u32 +mfsdram(const dcr_host_t *dcr_host, unsigned int idcr_n) +{ + return __mfdcri(dcr_host->base + SDRAM_DCR_ADDR_OFFSET, + dcr_host->base + SDRAM_DCR_DATA_OFFSET, + idcr_n); +} + +/** + * mtsdram - write controller register data + * @dcr_host: A pointer to the DCR mapping. + * @idcr_n: The indirect DCR register to write. + * @value: The data to write. + * + * This routine writes the provided data to the controller's specified + * indirect DCR register. + */ +static inline void +mtsdram(const dcr_host_t *dcr_host, unsigned int idcr_n, u32 value) +{ + return __mtdcri(dcr_host->base + SDRAM_DCR_ADDR_OFFSET, + dcr_host->base + SDRAM_DCR_DATA_OFFSET, + idcr_n, + value); +} + +/** + * ppc4xx_edac_check_bank_error - check a bank for an ECC bank error + * @status: A pointer to the ECC status structure to check for an + * ECC bank error. + * @bank: The bank to check for an ECC error. + * + * This routine determines whether the specified bank has an ECC + * error. + * + * Returns true if the specified bank has an ECC error; otherwise, + * false. + */ +static bool +ppc4xx_edac_check_bank_error(const struct ppc4xx_ecc_status *status, + unsigned int bank) +{ + switch (bank) { + case 0: + return status->ecces & SDRAM_ECCES_BK0ER; + case 1: + return status->ecces & SDRAM_ECCES_BK1ER; + default: + return false; + } +} + +/** + * ppc4xx_edac_generate_bank_message - generate interpretted bank status message + * @mci: A pointer to the EDAC memory controller instance associated + * with the bank message being generated. + * @status: A pointer to the ECC status structure to generate the + * message from. + * @buffer: A pointer to the buffer in which to generate the + * message. + * @size: The size, in bytes, of space available in buffer. + * + * This routine generates to the provided buffer the portion of the + * driver-unique report message associated with the ECCESS[BKNER] + * field of the specified ECC status. + * + * Returns the number of characters generated on success; otherwise, < + * 0 on error. + */ +static int +ppc4xx_edac_generate_bank_message(const struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status, + char *buffer, + size_t size) +{ + int n, total = 0; + unsigned int row, rows; + + n = snprintf(buffer, size, "%s: Banks: ", mci->dev_name); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + + for (rows = 0, row = 0; row < mci->nr_csrows; row++) { + if (ppc4xx_edac_check_bank_error(status, row)) { + n = snprintf(buffer, size, "%s%u", + (rows++ ? ", " : ""), row); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + } + } + + n = snprintf(buffer, size, "%s; ", rows ? "" : "None"); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + + fail: + return total; +} + +/** + * ppc4xx_edac_generate_checkbit_message - generate interpretted checkbit message + * @mci: A pointer to the EDAC memory controller instance associated + * with the checkbit message being generated. + * @status: A pointer to the ECC status structure to generate the + * message from. + * @buffer: A pointer to the buffer in which to generate the + * message. + * @size: The size, in bytes, of space available in buffer. + * + * This routine generates to the provided buffer the portion of the + * driver-unique report message associated with the ECCESS[CKBER] + * field of the specified ECC status. + * + * Returns the number of characters generated on success; otherwise, < + * 0 on error. + */ +static int +ppc4xx_edac_generate_checkbit_message(const struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status, + char *buffer, + size_t size) +{ + const struct ppc4xx_edac_pdata *pdata = mci->pvt_info; + const char *ckber = NULL; + + switch (status->ecces & SDRAM_ECCES_CKBER_MASK) { + case SDRAM_ECCES_CKBER_NONE: + ckber = "None"; + break; + case SDRAM_ECCES_CKBER_32_ECC_0_3: + ckber = "ECC0:3"; + break; + case SDRAM_ECCES_CKBER_32_ECC_4_8: + switch (mfsdram(&pdata->dcr_host, SDRAM_MCOPT1) & + SDRAM_MCOPT1_WDTH_MASK) { + case SDRAM_MCOPT1_WDTH_16: + ckber = "ECC0:3"; + break; + case SDRAM_MCOPT1_WDTH_32: + ckber = "ECC4:8"; + break; + default: + ckber = "Unknown"; + break; + } + break; + case SDRAM_ECCES_CKBER_32_ECC_0_8: + ckber = "ECC0:8"; + break; + default: + ckber = "Unknown"; + break; + } + + return snprintf(buffer, size, "Checkbit Error: %s", ckber); +} + +/** + * ppc4xx_edac_generate_lane_message - generate interpretted byte lane message + * @mci: A pointer to the EDAC memory controller instance associated + * with the byte lane message being generated. + * @status: A pointer to the ECC status structure to generate the + * message from. + * @buffer: A pointer to the buffer in which to generate the + * message. + * @size: The size, in bytes, of space available in buffer. + * + * This routine generates to the provided buffer the portion of the + * driver-unique report message associated with the ECCESS[BNCE] + * field of the specified ECC status. + * + * Returns the number of characters generated on success; otherwise, < + * 0 on error. + */ +static int +ppc4xx_edac_generate_lane_message(const struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status, + char *buffer, + size_t size) +{ + int n, total = 0; + unsigned int lane, lanes; + const unsigned int first_lane = 0; + const unsigned int lane_count = 16; + + n = snprintf(buffer, size, "; Byte Lane Errors: "); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + + for (lanes = 0, lane = first_lane; lane < lane_count; lane++) { + if ((status->ecces & SDRAM_ECCES_BNCE_ENCODE(lane)) != 0) { + n = snprintf(buffer, size, + "%s%u", + (lanes++ ? ", " : ""), lane); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + } + } + + n = snprintf(buffer, size, "%s; ", lanes ? "" : "None"); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + + fail: + return total; +} + +/** + * ppc4xx_edac_generate_ecc_message - generate interpretted ECC status message + * @mci: A pointer to the EDAC memory controller instance associated + * with the ECCES message being generated. + * @status: A pointer to the ECC status structure to generate the + * message from. + * @buffer: A pointer to the buffer in which to generate the + * message. + * @size: The size, in bytes, of space available in buffer. + * + * This routine generates to the provided buffer the portion of the + * driver-unique report message associated with the ECCESS register of + * the specified ECC status. + * + * Returns the number of characters generated on success; otherwise, < + * 0 on error. + */ +static int +ppc4xx_edac_generate_ecc_message(const struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status, + char *buffer, + size_t size) +{ + int n, total = 0; + + n = ppc4xx_edac_generate_bank_message(mci, status, buffer, size); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + + n = ppc4xx_edac_generate_checkbit_message(mci, status, buffer, size); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + + n = ppc4xx_edac_generate_lane_message(mci, status, buffer, size); + + if (n < 0 || n >= size) + goto fail; + + buffer += n; + size -= n; + total += n; + + fail: + return total; +} + +/** + * ppc4xx_edac_generate_plb_message - generate interpretted PLB status message + * @mci: A pointer to the EDAC memory controller instance associated + * with the PLB message being generated. + * @status: A pointer to the ECC status structure to generate the + * message from. + * @buffer: A pointer to the buffer in which to generate the + * message. + * @size: The size, in bytes, of space available in buffer. + * + * This routine generates to the provided buffer the portion of the + * driver-unique report message associated with the PLB-related BESR + * and/or WMIRQ registers of the specified ECC status. + * + * Returns the number of characters generated on success; otherwise, < + * 0 on error. + */ +static int +ppc4xx_edac_generate_plb_message(const struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status, + char *buffer, + size_t size) +{ + unsigned int master; + bool read; + + if ((status->besr & SDRAM_BESR_MASK) == 0) + return 0; + + if ((status->besr & SDRAM_BESR_M0ET_MASK) == SDRAM_BESR_M0ET_NONE) + return 0; + + read = ((status->besr & SDRAM_BESR_M0RW_MASK) == SDRAM_BESR_M0RW_READ); + + master = SDRAM_BESR_M0ID_DECODE(status->besr); + + return snprintf(buffer, size, + "%s error w/ PLB master %u \"%s\"; ", + (read ? "Read" : "Write"), + master, + (((master >= SDRAM_PLB_M0ID_FIRST) && + (master <= SDRAM_PLB_M0ID_LAST)) ? + ppc4xx_plb_masters[master] : "UNKNOWN")); +} + +/** + * ppc4xx_edac_generate_message - generate interpretted status message + * @mci: A pointer to the EDAC memory controller instance associated + * with the driver-unique message being generated. + * @status: A pointer to the ECC status structure to generate the + * message from. + * @buffer: A pointer to the buffer in which to generate the + * message. + * @size: The size, in bytes, of space available in buffer. + * + * This routine generates to the provided buffer the driver-unique + * EDAC report message from the specified ECC status. + */ +static void +ppc4xx_edac_generate_message(const struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status, + char *buffer, + size_t size) +{ + int n; + + if (buffer == NULL || size == 0) + return; + + n = ppc4xx_edac_generate_ecc_message(mci, status, buffer, size); + + if (n < 0 || n >= size) + return; + + buffer += n; + size -= n; + + ppc4xx_edac_generate_plb_message(mci, status, buffer, size); +} + +#ifdef DEBUG +/** + * ppc4xx_ecc_dump_status - dump controller ECC status registers + * @mci: A pointer to the EDAC memory controller instance + * associated with the status being dumped. + * @status: A pointer to the ECC status structure to generate the + * dump from. + * + * This routine dumps to the kernel log buffer the raw and + * interpretted specified ECC status. + */ +static void +ppc4xx_ecc_dump_status(const struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status) +{ + char message[PPC4XX_EDAC_MESSAGE_SIZE]; + + ppc4xx_edac_generate_message(mci, status, message, sizeof(message)); + + ppc4xx_edac_mc_printk(KERN_INFO, mci, + "\n" + "\tECCES: 0x%08x\n" + "\tWMIRQ: 0x%08x\n" + "\tBESR: 0x%08x\n" + "\tBEAR: 0x%08x%08x\n" + "\t%s\n", + status->ecces, + status->wmirq, + status->besr, + status->bearh, + status->bearl, + message); +} +#endif /* DEBUG */ + +/** + * ppc4xx_ecc_get_status - get controller ECC status + * @mci: A pointer to the EDAC memory controller instance + * associated with the status being retrieved. + * @status: A pointer to the ECC status structure to populate the + * ECC status with. + * + * This routine reads and masks, as appropriate, all the relevant + * status registers that deal with ibm,sdram-4xx-ddr2 ECC errors. + * While we read all of them, for correctable errors, we only expect + * to deal with ECCES. For uncorrectable errors, we expect to deal + * with all of them. + */ +static void +ppc4xx_ecc_get_status(const struct mem_ctl_info *mci, + struct ppc4xx_ecc_status *status) +{ + const struct ppc4xx_edac_pdata *pdata = mci->pvt_info; + const dcr_host_t *dcr_host = &pdata->dcr_host; + + status->ecces = mfsdram(dcr_host, SDRAM_ECCES) & SDRAM_ECCES_MASK; + status->wmirq = mfsdram(dcr_host, SDRAM_WMIRQ) & SDRAM_WMIRQ_MASK; + status->besr = mfsdram(dcr_host, SDRAM_BESR) & SDRAM_BESR_MASK; + status->bearl = mfsdram(dcr_host, SDRAM_BEARL); + status->bearh = mfsdram(dcr_host, SDRAM_BEARH); +} + +/** + * ppc4xx_ecc_clear_status - clear controller ECC status + * @mci: A pointer to the EDAC memory controller instance + * associated with the status being cleared. + * @status: A pointer to the ECC status structure containing the + * values to write to clear the ECC status. + * + * This routine clears--by writing the masked (as appropriate) status + * values back to--the status registers that deal with + * ibm,sdram-4xx-ddr2 ECC errors. + */ +static void +ppc4xx_ecc_clear_status(const struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status) +{ + const struct ppc4xx_edac_pdata *pdata = mci->pvt_info; + const dcr_host_t *dcr_host = &pdata->dcr_host; + + mtsdram(dcr_host, SDRAM_ECCES, status->ecces & SDRAM_ECCES_MASK); + mtsdram(dcr_host, SDRAM_WMIRQ, status->wmirq & SDRAM_WMIRQ_MASK); + mtsdram(dcr_host, SDRAM_BESR, status->besr & SDRAM_BESR_MASK); + mtsdram(dcr_host, SDRAM_BEARL, 0); + mtsdram(dcr_host, SDRAM_BEARH, 0); +} + +/** + * ppc4xx_edac_handle_ce - handle controller correctable ECC error (CE) + * @mci: A pointer to the EDAC memory controller instance + * associated with the correctable error being handled and reported. + * @status: A pointer to the ECC status structure associated with + * the correctable error being handled and reported. + * + * This routine handles an ibm,sdram-4xx-ddr2 controller ECC + * correctable error. Per the aforementioned discussion, there's not + * enough status available to use the full EDAC correctable error + * interface, so we just pass driver-unique message to the "no info" + * interface. + */ +static void +ppc4xx_edac_handle_ce(struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status) +{ + int row; + char message[PPC4XX_EDAC_MESSAGE_SIZE]; + + ppc4xx_edac_generate_message(mci, status, message, sizeof(message)); + + for (row = 0; row < mci->nr_csrows; row++) + if (ppc4xx_edac_check_bank_error(status, row)) + edac_mc_handle_ce_no_info(mci, message); +} + +/** + * ppc4xx_edac_handle_ue - handle controller uncorrectable ECC error (UE) + * @mci: A pointer to the EDAC memory controller instance + * associated with the uncorrectable error being handled and + * reported. + * @status: A pointer to the ECC status structure associated with + * the uncorrectable error being handled and reported. + * + * This routine handles an ibm,sdram-4xx-ddr2 controller ECC + * uncorrectable error. + */ +static void +ppc4xx_edac_handle_ue(struct mem_ctl_info *mci, + const struct ppc4xx_ecc_status *status) +{ + const u64 bear = ((u64)status->bearh << 32 | status->bearl); + const unsigned long page = bear >> PAGE_SHIFT; + const unsigned long offset = bear & ~PAGE_MASK; + int row; + char message[PPC4XX_EDAC_MESSAGE_SIZE]; + + ppc4xx_edac_generate_message(mci, status, message, sizeof(message)); + + for (row = 0; row < mci->nr_csrows; row++) + if (ppc4xx_edac_check_bank_error(status, row)) + edac_mc_handle_ue(mci, page, offset, row, message); +} + +/** + * ppc4xx_edac_check - check controller for ECC errors + * @mci: A pointer to the EDAC memory controller instance + * associated with the ibm,sdram-4xx-ddr2 controller being + * checked. + * + * This routine is used to check and post ECC errors and is called by + * both the EDAC polling thread and this driver's CE and UE interrupt + * handler. + */ +static void +ppc4xx_edac_check(struct mem_ctl_info *mci) +{ +#ifdef DEBUG + static unsigned int count; +#endif + struct ppc4xx_ecc_status status; + + ppc4xx_ecc_get_status(mci, &status); + +#ifdef DEBUG + if (count++ % 30 == 0) + ppc4xx_ecc_dump_status(mci, &status); +#endif + + if (status.ecces & SDRAM_ECCES_UE) + ppc4xx_edac_handle_ue(mci, &status); + + if (status.ecces & SDRAM_ECCES_CE) + ppc4xx_edac_handle_ce(mci, &status); + + ppc4xx_ecc_clear_status(mci, &status); +} + +/** + * ppc4xx_edac_isr - SEC (CE) and DED (UE) interrupt service routine + * @irq: The virtual interrupt number being serviced. + * @dev_id: A pointer to the EDAC memory controller instance + * associated with the interrupt being handled. + * + * This routine implements the interrupt handler for both correctable + * (CE) and uncorrectable (UE) ECC errors for the ibm,sdram-4xx-ddr2 + * controller. It simply calls through to the same routine used during + * polling to check, report and clear the ECC status. + * + * Unconditionally returns IRQ_HANDLED. + */ +static irqreturn_t +ppc4xx_edac_isr(int irq, void *dev_id) +{ + struct mem_ctl_info *mci = dev_id; + + ppc4xx_edac_check(mci); + + return IRQ_HANDLED; +} + +/** + * ppc4xx_edac_get_dtype - return the controller memory width + * @mcopt1: The 32-bit Memory Controller Option 1 register value + * currently set for the controller, from which the width + * is derived. + * + * This routine returns the EDAC device type width appropriate for the + * current controller configuration. + * + * TODO: This needs to be conditioned dynamically through feature + * flags or some such when other controller variants are supported as + * the 405EX[r] is 16-/32-bit and the others are 32-/64-bit with the + * 16- and 64-bit field definition/value/enumeration (b1) overloaded + * among them. + * + * Returns a device type width enumeration. + */ +static enum dev_type __devinit +ppc4xx_edac_get_dtype(u32 mcopt1) +{ + switch (mcopt1 & SDRAM_MCOPT1_WDTH_MASK) { + case SDRAM_MCOPT1_WDTH_16: + return DEV_X2; + case SDRAM_MCOPT1_WDTH_32: + return DEV_X4; + default: + return DEV_UNKNOWN; + } +} + +/** + * ppc4xx_edac_get_mtype - return controller memory type + * @mcopt1: The 32-bit Memory Controller Option 1 register value + * currently set for the controller, from which the memory type + * is derived. + * + * This routine returns the EDAC memory type appropriate for the + * current controller configuration. + * + * Returns a memory type enumeration. + */ +static enum mem_type __devinit +ppc4xx_edac_get_mtype(u32 mcopt1) +{ + bool rden = ((mcopt1 & SDRAM_MCOPT1_RDEN_MASK) == SDRAM_MCOPT1_RDEN); + + switch (mcopt1 & SDRAM_MCOPT1_DDR_TYPE_MASK) { + case SDRAM_MCOPT1_DDR2_TYPE: + return rden ? MEM_RDDR2 : MEM_DDR2; + case SDRAM_MCOPT1_DDR1_TYPE: + return rden ? MEM_RDDR : MEM_DDR; + default: + return MEM_UNKNOWN; + } +} + +/** + * ppc4xx_edac_init_csrows - intialize driver instance rows + * @mci: A pointer to the EDAC memory controller instance + * associated with the ibm,sdram-4xx-ddr2 controller for which + * the csrows (i.e. banks/ranks) are being initialized. + * @mcopt1: The 32-bit Memory Controller Option 1 register value + * currently set for the controller, from which bank width + * and memory typ information is derived. + * + * This routine intializes the virtual "chip select rows" associated + * with the EDAC memory controller instance. An ibm,sdram-4xx-ddr2 + * controller bank/rank is mapped to a row. + * + * Returns 0 if OK; otherwise, -EINVAL if the memory bank size + * configuration cannot be determined. + */ +static int __devinit +ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1) +{ + const struct ppc4xx_edac_pdata *pdata = mci->pvt_info; + int status = 0; + enum mem_type mtype; + enum dev_type dtype; + enum edac_type edac_mode; + int row; + u32 mbxcf, size; + static u32 ppc4xx_last_page; + + /* Establish the memory type and width */ + + mtype = ppc4xx_edac_get_mtype(mcopt1); + dtype = ppc4xx_edac_get_dtype(mcopt1); + + /* Establish EDAC mode */ + + if (mci->edac_cap & EDAC_FLAG_SECDED) + edac_mode = EDAC_SECDED; + else if (mci->edac_cap & EDAC_FLAG_EC) + edac_mode = EDAC_EC; + else + edac_mode = EDAC_NONE; + + /* + * Initialize each chip select row structure which correspond + * 1:1 with a controller bank/rank. + */ + + for (row = 0; row < mci->nr_csrows; row++) { + struct csrow_info *csi = &mci->csrows[row]; + + /* + * Get the configuration settings for this + * row/bank/rank and skip disabled banks. + */ + + mbxcf = mfsdram(&pdata->dcr_host, SDRAM_MBXCF(row)); + + if ((mbxcf & SDRAM_MBCF_BE_MASK) != SDRAM_MBCF_BE_ENABLE) + continue; + + /* Map the bank configuration size setting to pages. */ + + size = mbxcf & SDRAM_MBCF_SZ_MASK; + + switch (size) { + case SDRAM_MBCF_SZ_4MB: + case SDRAM_MBCF_SZ_8MB: + case SDRAM_MBCF_SZ_16MB: + case SDRAM_MBCF_SZ_32MB: + case SDRAM_MBCF_SZ_64MB: + case SDRAM_MBCF_SZ_128MB: + case SDRAM_MBCF_SZ_256MB: + case SDRAM_MBCF_SZ_512MB: + case SDRAM_MBCF_SZ_1GB: + case SDRAM_MBCF_SZ_2GB: + case SDRAM_MBCF_SZ_4GB: + case SDRAM_MBCF_SZ_8GB: + csi->nr_pages = SDRAM_MBCF_SZ_TO_PAGES(size); + break; + default: + ppc4xx_edac_mc_printk(KERN_ERR, mci, + "Unrecognized memory bank %d " + "size 0x%08x\n", + row, SDRAM_MBCF_SZ_DECODE(size)); + status = -EINVAL; + goto done; + } + + csi->first_page = ppc4xx_last_page; + csi->last_page = csi->first_page + csi->nr_pages - 1; + csi->page_mask = 0; + + /* + * It's unclear exactly what grain should be set to + * here. The SDRAM_ECCES register allows resolution of + * an error down to a nibble which would potentially + * argue for a grain of '1' byte, even though we only + * know the associated address for uncorrectable + * errors. This value is not used at present for + * anything other than error reporting so getting it + * wrong should be of little consequence. Other + * possible values would be the PLB width (16), the + * page size (PAGE_SIZE) or the memory width (2 or 4). + */ + + csi->grain = 1; + + csi->mtype = mtype; + csi->dtype = dtype; + + csi->edac_mode = edac_mode; + + ppc4xx_last_page += csi->nr_pages; + } + + done: + return status; +} + +/** + * ppc4xx_edac_mc_init - intialize driver instance + * @mci: A pointer to the EDAC memory controller instance being + * initialized. + * @op: A pointer to the OpenFirmware device tree node associated + * with the controller this EDAC instance is bound to. + * @match: A pointer to the OpenFirmware device tree match + * information associated with the controller this EDAC instance + * is bound to. + * @dcr_host: A pointer to the DCR data containing the DCR mapping + * for this controller instance. + * @mcopt1: The 32-bit Memory Controller Option 1 register value + * currently set for the controller, from which ECC capabilities + * and scrub mode are derived. + * + * This routine performs initialization of the EDAC memory controller + * instance and related driver-private data associated with the + * ibm,sdram-4xx-ddr2 memory controller the instance is bound to. + * + * Returns 0 if OK; otherwise, < 0 on error. + */ +static int __devinit +ppc4xx_edac_mc_init(struct mem_ctl_info *mci, + struct of_device *op, + const struct of_device_id *match, + const dcr_host_t *dcr_host, + u32 mcopt1) +{ + int status = 0; + const u32 memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK); + struct ppc4xx_edac_pdata *pdata = NULL; + const struct device_node *np = op->node; + + if (match == NULL) + return -EINVAL; + + /* Initial driver pointers and private data */ + + mci->dev = &op->dev; + + dev_set_drvdata(mci->dev, mci); + + pdata = mci->pvt_info; + + pdata->dcr_host = *dcr_host; + pdata->irqs.sec = NO_IRQ; + pdata->irqs.ded = NO_IRQ; + + /* Initialize controller capabilities and configuration */ + + mci->mtype_cap = (MEM_FLAG_DDR | MEM_FLAG_RDDR | + MEM_FLAG_DDR2 | MEM_FLAG_RDDR2); + + mci->edac_ctl_cap = (EDAC_FLAG_NONE | + EDAC_FLAG_EC | + EDAC_FLAG_SECDED); + + mci->scrub_cap = SCRUB_NONE; + mci->scrub_mode = SCRUB_NONE; + + /* + * Update the actual capabilites based on the MCOPT1[MCHK] + * settings. Scrubbing is only useful if reporting is enabled. + */ + + switch (memcheck) { + case SDRAM_MCOPT1_MCHK_CHK: + mci->edac_cap = EDAC_FLAG_EC; + break; + case SDRAM_MCOPT1_MCHK_CHK_REP: + mci->edac_cap = (EDAC_FLAG_EC | EDAC_FLAG_SECDED); + mci->scrub_mode = SCRUB_SW_SRC; + break; + default: + mci->edac_cap = EDAC_FLAG_NONE; + break; + } + + /* Initialize strings */ + + mci->mod_name = PPC4XX_EDAC_MODULE_NAME; + mci->mod_ver = PPC4XX_EDAC_MODULE_REVISION; + mci->ctl_name = match->compatible, + mci->dev_name = np->full_name; + + /* Initialize callbacks */ + + mci->edac_check = ppc4xx_edac_check; + mci->ctl_page_to_phys = NULL; + + /* Initialize chip select rows */ + + status = ppc4xx_edac_init_csrows(mci, mcopt1); + + if (status) + ppc4xx_edac_mc_printk(KERN_ERR, mci, + "Failed to initialize rows!\n"); + + return status; +} + +/** + * ppc4xx_edac_register_irq - setup and register controller interrupts + * @op: A pointer to the OpenFirmware device tree node associated + * with the controller this EDAC instance is bound to. + * @mci: A pointer to the EDAC memory controller instance + * associated with the ibm,sdram-4xx-ddr2 controller for which + * interrupts are being registered. + * + * This routine parses the correctable (CE) and uncorrectable error (UE) + * interrupts from the device tree node and maps and assigns them to + * the associated EDAC memory controller instance. + * + * Returns 0 if OK; otherwise, -ENODEV if the interrupts could not be + * mapped and assigned. + */ +static int __devinit +ppc4xx_edac_register_irq(struct of_device *op, struct mem_ctl_info *mci) +{ + int status = 0; + int ded_irq, sec_irq; + struct ppc4xx_edac_pdata *pdata = mci->pvt_info; + struct device_node *np = op->node; + + ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX); + sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX); + + if (ded_irq == NO_IRQ || sec_irq == NO_IRQ) { + ppc4xx_edac_mc_printk(KERN_ERR, mci, + "Unable to map interrupts.\n"); + status = -ENODEV; + goto fail; + } + + status = request_irq(ded_irq, + ppc4xx_edac_isr, + IRQF_DISABLED, + "[EDAC] MC ECCDED", + mci); + + if (status < 0) { + ppc4xx_edac_mc_printk(KERN_ERR, mci, + "Unable to request irq %d for ECC DED", + ded_irq); + status = -ENODEV; + goto fail1; + } + + status = request_irq(sec_irq, + ppc4xx_edac_isr, + IRQF_DISABLED, + "[EDAC] MC ECCSEC", + mci); + + if (status < 0) { + ppc4xx_edac_mc_printk(KERN_ERR, mci, + "Unable to request irq %d for ECC SEC", + sec_irq); + status = -ENODEV; + goto fail2; + } + + ppc4xx_edac_mc_printk(KERN_INFO, mci, "ECCDED irq is %d\n", ded_irq); + ppc4xx_edac_mc_printk(KERN_INFO, mci, "ECCSEC irq is %d\n", sec_irq); + + pdata->irqs.ded = ded_irq; + pdata->irqs.sec = sec_irq; + + return 0; + + fail2: + free_irq(sec_irq, mci); + + fail1: + free_irq(ded_irq, mci); + + fail: + return status; +} + +/** + * ppc4xx_edac_map_dcrs - locate and map controller registers + * @np: A pointer to the device tree node containing the DCR + * resources to map. + * @dcr_host: A pointer to the DCR data to populate with the + * DCR mapping. + * + * This routine attempts to locate in the device tree and map the DCR + * register resources associated with the controller's indirect DCR + * address and data windows. + * + * Returns 0 if the DCRs were successfully mapped; otherwise, < 0 on + * error. + */ +static int __devinit +ppc4xx_edac_map_dcrs(const struct device_node *np, dcr_host_t *dcr_host) +{ + unsigned int dcr_base, dcr_len; + + if (np == NULL || dcr_host == NULL) + return -EINVAL; + + /* Get the DCR resource extent and sanity check the values. */ + + dcr_base = dcr_resource_start(np, 0); + dcr_len = dcr_resource_len(np, 0); + + if (dcr_base == 0 || dcr_len == 0) { + ppc4xx_edac_printk(KERN_ERR, + "Failed to obtain DCR property.\n"); + return -ENODEV; + } + + if (dcr_len != SDRAM_DCR_RESOURCE_LEN) { + ppc4xx_edac_printk(KERN_ERR, + "Unexpected DCR length %d, expected %d.\n", + dcr_len, SDRAM_DCR_RESOURCE_LEN); + return -ENODEV; + } + + /* Attempt to map the DCR extent. */ + + *dcr_host = dcr_map(np, dcr_base, dcr_len); + + if (!DCR_MAP_OK(*dcr_host)) { + ppc4xx_edac_printk(KERN_INFO, "Failed to map DCRs.\n"); + return -ENODEV; + } + + return 0; +} + +/** + * ppc4xx_edac_probe - check controller and bind driver + * @op: A pointer to the OpenFirmware device tree node associated + * with the controller being probed for driver binding. + * @match: A pointer to the OpenFirmware device tree match + * information associated with the controller being probed + * for driver binding. + * + * This routine probes a specific ibm,sdram-4xx-ddr2 controller + * instance for binding with the driver. + * + * Returns 0 if the controller instance was successfully bound to the + * driver; otherwise, < 0 on error. + */ +static int __devinit +ppc4xx_edac_probe(struct of_device *op, const struct of_device_id *match) +{ + int status = 0; + u32 mcopt1, memcheck; + dcr_host_t dcr_host; + const struct device_node *np = op->node; + struct mem_ctl_info *mci = NULL; + static int ppc4xx_edac_instance; + + /* + * At this point, we only support the controller realized on + * the AMCC PPC 405EX[r]. Reject anything else. + */ + + if (!of_device_is_compatible(np, "ibm,sdram-405ex") && + !of_device_is_compatible(np, "ibm,sdram-405exr")) { + ppc4xx_edac_printk(KERN_NOTICE, + "Only the PPC405EX[r] is supported.\n"); + return -ENODEV; + } + + /* + * Next, get the DCR property and attempt to map it so that we + * can probe the controller. + */ + + status = ppc4xx_edac_map_dcrs(np, &dcr_host); + + if (status) + return status; + + /* + * First determine whether ECC is enabled at all. If not, + * there is no useful checking or monitoring that can be done + * for this controller. + */ + + mcopt1 = mfsdram(&dcr_host, SDRAM_MCOPT1); + memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK); + + if (memcheck == SDRAM_MCOPT1_MCHK_NON) { + ppc4xx_edac_printk(KERN_INFO, "%s: No ECC memory detected or " + "ECC is disabled.\n", np->full_name); + status = -ENODEV; + goto done; + } + + /* + * At this point, we know ECC is enabled, allocate an EDAC + * controller instance and perform the appropriate + * initialization. + */ + + mci = edac_mc_alloc(sizeof(struct ppc4xx_edac_pdata), + ppc4xx_edac_nr_csrows, + ppc4xx_edac_nr_chans, + ppc4xx_edac_instance); + + if (mci == NULL) { + ppc4xx_edac_printk(KERN_ERR, "%s: " + "Failed to allocate EDAC MC instance!\n", + np->full_name); + status = -ENOMEM; + goto done; + } + + status = ppc4xx_edac_mc_init(mci, op, match, &dcr_host, mcopt1); + + if (status) { + ppc4xx_edac_mc_printk(KERN_ERR, mci, + "Failed to initialize instance!\n"); + goto fail; + } + + /* + * We have a valid, initialized EDAC instance bound to the + * controller. Attempt to register it with the EDAC subsystem + * and, if necessary, register interrupts. + */ + + if (edac_mc_add_mc(mci)) { + ppc4xx_edac_mc_printk(KERN_ERR, mci, + "Failed to add instance!\n"); + status = -ENODEV; + goto fail; + } + + if (edac_op_state == EDAC_OPSTATE_INT) { + status = ppc4xx_edac_register_irq(op, mci); + + if (status) + goto fail1; + } + + ppc4xx_edac_instance++; + + return 0; + + fail1: + edac_mc_del_mc(mci->dev); + + fail: + edac_mc_free(mci); + + done: + return status; +} + +/** + * ppc4xx_edac_remove - unbind driver from controller + * @op: A pointer to the OpenFirmware device tree node associated + * with the controller this EDAC instance is to be unbound/removed + * from. + * + * This routine unbinds the EDAC memory controller instance associated + * with the specified ibm,sdram-4xx-ddr2 controller described by the + * OpenFirmware device tree node passed as a parameter. + * + * Unconditionally returns 0. + */ +static int +ppc4xx_edac_remove(struct of_device *op) +{ + struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); + struct ppc4xx_edac_pdata *pdata = mci->pvt_info; + + if (edac_op_state == EDAC_OPSTATE_INT) { + free_irq(pdata->irqs.sec, mci); + free_irq(pdata->irqs.ded, mci); + } + + dcr_unmap(pdata->dcr_host, SDRAM_DCR_RESOURCE_LEN); + + edac_mc_del_mc(mci->dev); + edac_mc_free(mci); + + return 0; +} + +/** + * ppc4xx_edac_opstate_init - initialize EDAC reporting method + * + * This routine ensures that the EDAC memory controller reporting + * method is mapped to a sane value as the EDAC core defines the value + * to EDAC_OPSTATE_INVAL by default. We don't call the global + * opstate_init as that defaults to polling and we want interrupt as + * the default. + */ +static inline void __init +ppc4xx_edac_opstate_init(void) +{ + switch (edac_op_state) { + case EDAC_OPSTATE_POLL: + case EDAC_OPSTATE_INT: + break; + default: + edac_op_state = EDAC_OPSTATE_INT; + break; + } + + ppc4xx_edac_printk(KERN_INFO, "Reporting type: %s\n", + ((edac_op_state == EDAC_OPSTATE_POLL) ? + EDAC_OPSTATE_POLL_STR : + ((edac_op_state == EDAC_OPSTATE_INT) ? + EDAC_OPSTATE_INT_STR : + EDAC_OPSTATE_UNKNOWN_STR))); +} + +/** + * ppc4xx_edac_init - driver/module insertion entry point + * + * This routine is the driver/module insertion entry point. It + * initializes the EDAC memory controller reporting state and + * registers the driver as an OpenFirmware device tree platform + * driver. + */ +static int __init +ppc4xx_edac_init(void) +{ + ppc4xx_edac_printk(KERN_INFO, PPC4XX_EDAC_MODULE_REVISION "\n"); + + ppc4xx_edac_opstate_init(); + + return of_register_platform_driver(&ppc4xx_edac_driver); +} + +/** + * ppc4xx_edac_exit - driver/module removal entry point + * + * This routine is the driver/module removal entry point. It + * unregisters the driver as an OpenFirmware device tree platform + * driver. + */ +static void __exit +ppc4xx_edac_exit(void) +{ + of_unregister_platform_driver(&ppc4xx_edac_driver); +} + +module_init(ppc4xx_edac_init); +module_exit(ppc4xx_edac_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Grant Erickson "); +MODULE_DESCRIPTION("EDAC MC Driver for the PPC4xx IBM DDR2 Memory Controller"); +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting State: " + "0=" EDAC_OPSTATE_POLL_STR ", 2=" EDAC_OPSTATE_INT_STR); diff --git a/trunk/drivers/edac/ppc4xx_edac.h b/trunk/drivers/edac/ppc4xx_edac.h new file mode 100644 index 000000000000..d3154764c449 --- /dev/null +++ b/trunk/drivers/edac/ppc4xx_edac.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2008 Nuovation System Designs, LLC + * Grant Erickson + * + * This file defines processor mnemonics for accessing and managing + * the IBM DDR1/DDR2 ECC controller found in the 405EX[r], 440SP, + * 440SPe, 460EX, 460GT and 460SX. + * + * 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 of the + * License. + * + */ + +#ifndef __PPC4XX_EDAC_H +#define __PPC4XX_EDAC_H + +#include + +/* + * Macro for generating register field mnemonics + */ +#define PPC_REG_BITS 32 +#define PPC_REG_VAL(bit, val) ((val) << ((PPC_REG_BITS - 1) - (bit))) +#define PPC_REG_DECODE(bit, val) ((val) >> ((PPC_REG_BITS - 1) - (bit))) + +/* + * IBM 4xx DDR1/DDR2 SDRAM memory controller registers (at least those + * relevant to ECC) + */ +#define SDRAM_BESR 0x00 /* Error status (read/clear) */ +#define SDRAM_BESRT 0x01 /* Error statuss (test/set) */ +#define SDRAM_BEARL 0x02 /* Error address low */ +#define SDRAM_BEARH 0x03 /* Error address high */ +#define SDRAM_WMIRQ 0x06 /* Write master (read/clear) */ +#define SDRAM_WMIRQT 0x07 /* Write master (test/set) */ +#define SDRAM_MCOPT1 0x20 /* Controller options 1 */ +#define SDRAM_MBXCF_BASE 0x40 /* Bank n configuration base */ +#define SDRAM_MBXCF(n) (SDRAM_MBXCF_BASE + (4 * (n))) +#define SDRAM_MB0CF SDRAM_MBXCF(0) +#define SDRAM_MB1CF SDRAM_MBXCF(1) +#define SDRAM_MB2CF SDRAM_MBXCF(2) +#define SDRAM_MB3CF SDRAM_MBXCF(3) +#define SDRAM_ECCCR 0x98 /* ECC error status */ +#define SDRAM_ECCES SDRAM_ECCCR + +/* + * PLB Master IDs + */ +#define SDRAM_PLB_M0ID_FIRST 0 +#define SDRAM_PLB_M0ID_ICU SDRAM_PLB_M0ID_FIRST +#define SDRAM_PLB_M0ID_PCIE0 1 +#define SDRAM_PLB_M0ID_PCIE1 2 +#define SDRAM_PLB_M0ID_DMA 3 +#define SDRAM_PLB_M0ID_DCU 4 +#define SDRAM_PLB_M0ID_OPB 5 +#define SDRAM_PLB_M0ID_MAL 6 +#define SDRAM_PLB_M0ID_SEC 7 +#define SDRAM_PLB_M0ID_AHB 8 +#define SDRAM_PLB_M0ID_LAST SDRAM_PLB_M0ID_AHB +#define SDRAM_PLB_M0ID_COUNT (SDRAM_PLB_M0ID_LAST - \ + SDRAM_PLB_M0ID_FIRST + 1) + +/* + * Memory Controller Bus Error Status Register + */ +#define SDRAM_BESR_MASK PPC_REG_VAL(7, 0xFF) +#define SDRAM_BESR_M0ID_MASK PPC_REG_VAL(3, 0xF) +#define SDRAM_BESR_M0ID_DECODE(n) PPC_REG_DECODE(3, n) +#define SDRAM_BESR_M0ID_ICU PPC_REG_VAL(3, SDRAM_PLB_M0ID_ICU) +#define SDRAM_BESR_M0ID_PCIE0 PPC_REG_VAL(3, SDRAM_PLB_M0ID_PCIE0) +#define SDRAM_BESR_M0ID_PCIE1 PPC_REG_VAL(3, SDRAM_PLB_M0ID_PCIE1) +#define SDRAM_BESR_M0ID_DMA PPC_REG_VAL(3, SDRAM_PLB_M0ID_DMA) +#define SDRAM_BESR_M0ID_DCU PPC_REG_VAL(3, SDRAM_PLB_M0ID_DCU) +#define SDRAM_BESR_M0ID_OPB PPC_REG_VAL(3, SDRAM_PLB_M0ID_OPB) +#define SDRAM_BESR_M0ID_MAL PPC_REG_VAL(3, SDRAM_PLB_M0ID_MAL) +#define SDRAM_BESR_M0ID_SEC PPC_REG_VAL(3, SDRAM_PLB_M0ID_SEC) +#define SDRAM_BESR_M0ID_AHB PPC_REG_VAL(3, SDRAM_PLB_M0ID_AHB) +#define SDRAM_BESR_M0ET_MASK PPC_REG_VAL(6, 0x7) +#define SDRAM_BESR_M0ET_NONE PPC_REG_VAL(6, 0) +#define SDRAM_BESR_M0ET_ECC PPC_REG_VAL(6, 1) +#define SDRAM_BESR_M0RW_MASK PPC_REG_VAL(7, 1) +#define SDRAM_BESR_M0RW_WRITE PPC_REG_VAL(7, 0) +#define SDRAM_BESR_M0RW_READ PPC_REG_VAL(7, 1) + +/* + * Memory Controller PLB Write Master Interrupt Register + */ +#define SDRAM_WMIRQ_MASK PPC_REG_VAL(8, 0x1FF) +#define SDRAM_WMIRQ_ENCODE(id) PPC_REG_VAL((id % \ + SDRAM_PLB_M0ID_COUNT), 1) +#define SDRAM_WMIRQ_ICU PPC_REG_VAL(SDRAM_PLB_M0ID_ICU, 1) +#define SDRAM_WMIRQ_PCIE0 PPC_REG_VAL(SDRAM_PLB_M0ID_PCIE0, 1) +#define SDRAM_WMIRQ_PCIE1 PPC_REG_VAL(SDRAM_PLB_M0ID_PCIE1, 1) +#define SDRAM_WMIRQ_DMA PPC_REG_VAL(SDRAM_PLB_M0ID_DMA, 1) +#define SDRAM_WMIRQ_DCU PPC_REG_VAL(SDRAM_PLB_M0ID_DCU, 1) +#define SDRAM_WMIRQ_OPB PPC_REG_VAL(SDRAM_PLB_M0ID_OPB, 1) +#define SDRAM_WMIRQ_MAL PPC_REG_VAL(SDRAM_PLB_M0ID_MAL, 1) +#define SDRAM_WMIRQ_SEC PPC_REG_VAL(SDRAM_PLB_M0ID_SEC, 1) +#define SDRAM_WMIRQ_AHB PPC_REG_VAL(SDRAM_PLB_M0ID_AHB, 1) + +/* + * Memory Controller Options 1 Register + */ +#define SDRAM_MCOPT1_MCHK_MASK PPC_REG_VAL(3, 0x3) /* ECC mask */ +#define SDRAM_MCOPT1_MCHK_NON PPC_REG_VAL(3, 0x0) /* No ECC gen */ +#define SDRAM_MCOPT1_MCHK_GEN PPC_REG_VAL(3, 0x2) /* ECC gen */ +#define SDRAM_MCOPT1_MCHK_CHK PPC_REG_VAL(3, 0x1) /* ECC gen and chk */ +#define SDRAM_MCOPT1_MCHK_CHK_REP PPC_REG_VAL(3, 0x3) /* ECC gen/chk/rpt */ +#define SDRAM_MCOPT1_MCHK_DECODE(n) ((((u32)(n)) >> 28) & 0x3) +#define SDRAM_MCOPT1_RDEN_MASK PPC_REG_VAL(4, 0x1) /* Rgstrd DIMM mask */ +#define SDRAM_MCOPT1_RDEN PPC_REG_VAL(4, 0x1) /* Rgstrd DIMM enbl */ +#define SDRAM_MCOPT1_WDTH_MASK PPC_REG_VAL(7, 0x1) /* Width mask */ +#define SDRAM_MCOPT1_WDTH_32 PPC_REG_VAL(7, 0x0) /* 32 bits */ +#define SDRAM_MCOPT1_WDTH_16 PPC_REG_VAL(7, 0x1) /* 16 bits */ +#define SDRAM_MCOPT1_DDR_TYPE_MASK PPC_REG_VAL(11, 0x1) /* DDR type mask */ +#define SDRAM_MCOPT1_DDR1_TYPE PPC_REG_VAL(11, 0x0) /* DDR1 type */ +#define SDRAM_MCOPT1_DDR2_TYPE PPC_REG_VAL(11, 0x1) /* DDR2 type */ + +/* + * Memory Bank 0 - n Configuration Register + */ +#define SDRAM_MBCF_BA_MASK PPC_REG_VAL(12, 0x1FFF) +#define SDRAM_MBCF_SZ_MASK PPC_REG_VAL(19, 0xF) +#define SDRAM_MBCF_SZ_DECODE(mbxcf) PPC_REG_DECODE(19, mbxcf) +#define SDRAM_MBCF_SZ_4MB PPC_REG_VAL(19, 0x0) +#define SDRAM_MBCF_SZ_8MB PPC_REG_VAL(19, 0x1) +#define SDRAM_MBCF_SZ_16MB PPC_REG_VAL(19, 0x2) +#define SDRAM_MBCF_SZ_32MB PPC_REG_VAL(19, 0x3) +#define SDRAM_MBCF_SZ_64MB PPC_REG_VAL(19, 0x4) +#define SDRAM_MBCF_SZ_128MB PPC_REG_VAL(19, 0x5) +#define SDRAM_MBCF_SZ_256MB PPC_REG_VAL(19, 0x6) +#define SDRAM_MBCF_SZ_512MB PPC_REG_VAL(19, 0x7) +#define SDRAM_MBCF_SZ_1GB PPC_REG_VAL(19, 0x8) +#define SDRAM_MBCF_SZ_2GB PPC_REG_VAL(19, 0x9) +#define SDRAM_MBCF_SZ_4GB PPC_REG_VAL(19, 0xA) +#define SDRAM_MBCF_SZ_8GB PPC_REG_VAL(19, 0xB) +#define SDRAM_MBCF_AM_MASK PPC_REG_VAL(23, 0xF) +#define SDRAM_MBCF_AM_MODE0 PPC_REG_VAL(23, 0x0) +#define SDRAM_MBCF_AM_MODE1 PPC_REG_VAL(23, 0x1) +#define SDRAM_MBCF_AM_MODE2 PPC_REG_VAL(23, 0x2) +#define SDRAM_MBCF_AM_MODE3 PPC_REG_VAL(23, 0x3) +#define SDRAM_MBCF_AM_MODE4 PPC_REG_VAL(23, 0x4) +#define SDRAM_MBCF_AM_MODE5 PPC_REG_VAL(23, 0x5) +#define SDRAM_MBCF_AM_MODE6 PPC_REG_VAL(23, 0x6) +#define SDRAM_MBCF_AM_MODE7 PPC_REG_VAL(23, 0x7) +#define SDRAM_MBCF_AM_MODE8 PPC_REG_VAL(23, 0x8) +#define SDRAM_MBCF_AM_MODE9 PPC_REG_VAL(23, 0x9) +#define SDRAM_MBCF_BE_MASK PPC_REG_VAL(31, 0x1) +#define SDRAM_MBCF_BE_DISABLE PPC_REG_VAL(31, 0x0) +#define SDRAM_MBCF_BE_ENABLE PPC_REG_VAL(31, 0x1) + +/* + * ECC Error Status + */ +#define SDRAM_ECCES_MASK PPC_REG_VAL(21, 0x3FFFFF) +#define SDRAM_ECCES_BNCE_MASK PPC_REG_VAL(15, 0xFFFF) +#define SDRAM_ECCES_BNCE_ENCODE(lane) PPC_REG_VAL(((lane) & 0xF), 1) +#define SDRAM_ECCES_CKBER_MASK PPC_REG_VAL(17, 0x3) +#define SDRAM_ECCES_CKBER_NONE PPC_REG_VAL(17, 0) +#define SDRAM_ECCES_CKBER_16_ECC_0_3 PPC_REG_VAL(17, 2) +#define SDRAM_ECCES_CKBER_32_ECC_0_3 PPC_REG_VAL(17, 1) +#define SDRAM_ECCES_CKBER_32_ECC_4_8 PPC_REG_VAL(17, 2) +#define SDRAM_ECCES_CKBER_32_ECC_0_8 PPC_REG_VAL(17, 3) +#define SDRAM_ECCES_CE PPC_REG_VAL(18, 1) +#define SDRAM_ECCES_UE PPC_REG_VAL(19, 1) +#define SDRAM_ECCES_BKNER_MASK PPC_REG_VAL(21, 0x3) +#define SDRAM_ECCES_BK0ER PPC_REG_VAL(20, 1) +#define SDRAM_ECCES_BK1ER PPC_REG_VAL(21, 1) + +#endif /* __PPC4XX_EDAC_H */ diff --git a/trunk/drivers/gpio/gpiolib.c b/trunk/drivers/gpio/gpiolib.c index 42fb2fd24c0c..51a8d4103be5 100644 --- a/trunk/drivers/gpio/gpiolib.c +++ b/trunk/drivers/gpio/gpiolib.c @@ -69,20 +69,24 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) * those calls have no teeth) we can't avoid autorequesting. This nag * message should motivate switching to explicit requests... so should * the weaker cleanup after faults, compared to gpio_request(). + * + * NOTE: the autorequest mechanism is going away; at this point it's + * only "legal" in the sense that (old) code using it won't break yet, + * but instead only triggers a WARN() stack dump. */ static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset) { - if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { - struct gpio_chip *chip = desc->chip; - int gpio = chip->base + offset; + const struct gpio_chip *chip = desc->chip; + const int gpio = chip->base + offset; + if (WARN(test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0, + "autorequest GPIO-%d\n", gpio)) { if (!try_module_get(chip->owner)) { pr_err("GPIO-%d: module can't be gotten \n", gpio); clear_bit(FLAG_REQUESTED, &desc->flags); /* lose */ return -EIO; } - pr_warning("GPIO-%d autorequested\n", gpio); desc_set_label(desc, "[auto]"); /* caller must chip->request() w/o spinlock */ if (chip->request) @@ -438,6 +442,7 @@ int gpio_export(unsigned gpio, bool direction_may_change) unsigned long flags; struct gpio_desc *desc; int status = -EINVAL; + char *ioname = NULL; /* can't export until sysfs is available ... */ if (!gpio_class.p) { @@ -461,11 +466,14 @@ int gpio_export(unsigned gpio, bool direction_may_change) } spin_unlock_irqrestore(&gpio_lock, flags); + if (desc->chip->names && desc->chip->names[gpio - desc->chip->base]) + ioname = desc->chip->names[gpio - desc->chip->base]; + if (status == 0) { struct device *dev; dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, "gpio%d", gpio); + desc, ioname ? ioname : "gpio%d", gpio); if (dev) { if (direction_may_change) status = sysfs_create_group(&dev->kobj, @@ -513,6 +521,7 @@ void gpio_unexport(unsigned gpio) mutex_lock(&sysfs_lock); desc = &gpio_desc[gpio]; + if (test_bit(FLAG_EXPORT, &desc->flags)) { struct device *dev = NULL; diff --git a/trunk/drivers/gpu/drm/drm_crtc_helper.c b/trunk/drivers/gpu/drm/drm_crtc_helper.c index 1c3a8c557140..a04639dc633d 100644 --- a/trunk/drivers/gpu/drm/drm_crtc_helper.c +++ b/trunk/drivers/gpu/drm/drm_crtc_helper.c @@ -42,6 +42,26 @@ static struct drm_display_mode std_modes[] = { DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, }; +static void drm_mode_validate_flag(struct drm_connector *connector, + int flags) +{ + struct drm_display_mode *mode, *t; + + if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) + return; + + list_for_each_entry_safe(mode, t, &connector->modes, head) { + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && + !(flags & DRM_MODE_FLAG_INTERLACE)) + mode->status = MODE_NO_INTERLACE; + if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && + !(flags & DRM_MODE_FLAG_DBLSCAN)) + mode->status = MODE_NO_DBLESCAN; + } + + return; +} + /** * drm_helper_probe_connector_modes - get complete set of display modes * @dev: DRM device @@ -72,6 +92,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; int count = 0; + int mode_flags = 0; DRM_DEBUG("%s\n", drm_get_connector_name(connector)); /* set all modes to the unverified state */ @@ -96,6 +117,13 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, if (maxX && maxY) drm_mode_validate_size(dev, &connector->modes, maxX, maxY, 0); + + if (connector->interlace_allowed) + mode_flags |= DRM_MODE_FLAG_INTERLACE; + if (connector->doublescan_allowed) + mode_flags |= DRM_MODE_FLAG_DBLSCAN; + drm_mode_validate_flag(connector, mode_flags); + list_for_each_entry_safe(mode, t, &connector->modes, head) { if (mode->status == MODE_OK) mode->status = connector_funcs->mode_valid(connector, @@ -885,7 +913,6 @@ bool drm_helper_plugged_event(struct drm_device *dev) /** * drm_initial_config - setup a sane initial connector configuration * @dev: DRM device - * @can_grow: this configuration is growable * * LOCKING: * Called at init time, must take mode config lock. @@ -897,7 +924,7 @@ bool drm_helper_plugged_event(struct drm_device *dev) * RETURNS: * Zero if everything went ok, nonzero otherwise. */ -bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) +bool drm_helper_initial_config(struct drm_device *dev) { struct drm_connector *connector; int count = 0; diff --git a/trunk/drivers/gpu/drm/drm_edid.c b/trunk/drivers/gpu/drm/drm_edid.c index c67400067b85..ca9c61656714 100644 --- a/trunk/drivers/gpu/drm/drm_edid.c +++ b/trunk/drivers/gpu/drm/drm_edid.c @@ -125,10 +125,8 @@ static bool edid_is_valid(struct edid *edid) DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); goto bad; } - if (edid->revision > 3) { - DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision); - goto bad; - } + if (edid->revision > 4) + DRM_DEBUG("EDID minor > 4, assuming backward compatibility\n"); for (i = 0; i < EDID_LENGTH; i++) csum += raw_edid[i]; @@ -162,7 +160,7 @@ static bool edid_vendor(struct edid *edid, char *vendor) edid_vendor[0] = ((edid->mfg_id[0] & 0x7c) >> 2) + '@'; edid_vendor[1] = (((edid->mfg_id[0] & 0x3) << 3) | ((edid->mfg_id[1] & 0xe0) >> 5)) + '@'; - edid_vendor[2] = (edid->mfg_id[2] & 0x1f) + '@'; + edid_vendor[2] = (edid->mfg_id[1] & 0x1f) + '@'; return !strncmp(edid_vendor, vendor, 3); } diff --git a/trunk/drivers/gpu/drm/drm_gem.c b/trunk/drivers/gpu/drm/drm_gem.c index c1173d8c4588..4984aa89cf3d 100644 --- a/trunk/drivers/gpu/drm/drm_gem.c +++ b/trunk/drivers/gpu/drm/drm_gem.c @@ -505,7 +505,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) struct drm_local_map *map = NULL; struct drm_gem_object *obj; struct drm_hash_item *hash; - unsigned long prot; int ret = 0; mutex_lock(&dev->struct_mutex); @@ -538,11 +537,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = obj->dev->driver->gem_vm_ops; vma->vm_private_data = map->handle; /* FIXME: use pgprot_writecombine when available */ - prot = pgprot_val(vma->vm_page_prot); -#ifdef CONFIG_X86 - prot |= _PAGE_CACHE_WC; -#endif - vma->vm_page_prot = __pgprot(prot); + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); /* Take a ref for this mapping of the object, so that the fault * handler can dereference the mmap offset's pointer to the object. diff --git a/trunk/drivers/gpu/drm/drm_sysfs.c b/trunk/drivers/gpu/drm/drm_sysfs.c index 5de573a981cb..bc0c6849360c 100644 --- a/trunk/drivers/gpu/drm/drm_sysfs.c +++ b/trunk/drivers/gpu/drm/drm_sysfs.c @@ -451,6 +451,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev) kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); } +EXPORT_SYMBOL(drm_sysfs_hotplug_event); /** * drm_sysfs_device_add - adds a class device to sysfs for a character driver diff --git a/trunk/drivers/gpu/drm/i915/i915_dma.c b/trunk/drivers/gpu/drm/i915/i915_dma.c index 85549f615b1f..c23b3a95b7ce 100644 --- a/trunk/drivers/gpu/drm/i915/i915_dma.c +++ b/trunk/drivers/gpu/drm/i915/i915_dma.c @@ -922,7 +922,7 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size, * Some of the preallocated space is taken by the GTT * and popup. GTT is 1K per MB of aperture size, and popup is 4K. */ - if (IS_G4X(dev)) + if (IS_G4X(dev) || IS_IGD(dev)) overhead = 4096; else overhead = (*aperture_size / 1024) + 4096; @@ -1030,13 +1030,6 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto destroy_ringbuffer; - /* FIXME: re-add hotplug support */ -#if 0 - ret = drm_hotplug_init(dev); - if (ret) - goto destroy_ringbuffer; -#endif - /* Always safe in the mode setting case. */ /* FIXME: do pre/post-mode set stuff in core KMS code */ dev->vblank_disable_allowed = 1; @@ -1049,7 +1042,7 @@ static int i915_load_modeset_init(struct drm_device *dev) intel_modeset_init(dev); - drm_helper_initial_config(dev, false); + drm_helper_initial_config(dev); return 0; diff --git a/trunk/drivers/gpu/drm/i915/i915_drv.h b/trunk/drivers/gpu/drm/i915/i915_drv.h index c1685d0c704f..317b1223e091 100644 --- a/trunk/drivers/gpu/drm/i915/i915_drv.h +++ b/trunk/drivers/gpu/drm/i915/i915_drv.h @@ -159,6 +159,9 @@ typedef struct drm_i915_private { u32 irq_mask_reg; u32 pipestat[2]; + u32 hotplug_supported_mask; + struct work_struct hotplug_work; + int tex_lru_log_granularity; int allow_batchbuffer; struct mem_block *agp_heap; @@ -297,6 +300,7 @@ typedef struct drm_i915_private { * * A reference is held on the buffer while on this list. */ + spinlock_t active_list_lock; struct list_head active_list; /** @@ -810,6 +814,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev)) +#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) #define PRIMARY_RINGBUFFER_SIZE (128*1024) diff --git a/trunk/drivers/gpu/drm/i915/i915_gem.c b/trunk/drivers/gpu/drm/i915/i915_gem.c index e0389ad1477d..1449b452cc63 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem.c @@ -1072,6 +1072,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) case -EAGAIN: return VM_FAULT_OOM; case -EFAULT: + case -EINVAL: return VM_FAULT_SIGBUS; default: return VM_FAULT_NOPAGE; @@ -1324,8 +1325,10 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno) obj_priv->active = 1; } /* Move from whatever list we were on to the tail of execution. */ + spin_lock(&dev_priv->mm.active_list_lock); list_move_tail(&obj_priv->list, &dev_priv->mm.active_list); + spin_unlock(&dev_priv->mm.active_list_lock); obj_priv->last_rendering_seqno = seqno; } @@ -1467,6 +1470,7 @@ i915_gem_retire_request(struct drm_device *dev, /* Move any buffers on the active list that are no longer referenced * by the ringbuffer to the flushing/inactive lists as appropriate. */ + spin_lock(&dev_priv->mm.active_list_lock); while (!list_empty(&dev_priv->mm.active_list)) { struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; @@ -1481,7 +1485,7 @@ i915_gem_retire_request(struct drm_device *dev, * this seqno. */ if (obj_priv->last_rendering_seqno != request->seqno) - return; + goto out; #if WATCH_LRU DRM_INFO("%s: retire %d moves to inactive list %p\n", @@ -1493,6 +1497,8 @@ i915_gem_retire_request(struct drm_device *dev, else i915_gem_object_move_to_inactive(obj); } +out: + spin_unlock(&dev_priv->mm.active_list_lock); } /** @@ -1990,20 +1996,23 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) int regnum = obj_priv->fence_reg; uint32_t val; uint32_t pitch_val; + uint32_t fence_size_bits; - if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) || + if ((obj_priv->gtt_offset & ~I830_FENCE_START_MASK) || (obj_priv->gtt_offset & (obj->size - 1))) { - WARN(1, "%s: object 0x%08x not 1M or size aligned\n", + WARN(1, "%s: object 0x%08x not 512K or size aligned\n", __func__, obj_priv->gtt_offset); return; } pitch_val = (obj_priv->stride / 128) - 1; - + WARN_ON(pitch_val & ~0x0000000f); val = obj_priv->gtt_offset; if (obj_priv->tiling_mode == I915_TILING_Y) val |= 1 << I830_FENCE_TILING_Y_SHIFT; - val |= I830_FENCE_SIZE_BITS(obj->size); + fence_size_bits = I830_FENCE_SIZE_BITS(obj->size); + WARN_ON(fence_size_bits & ~0x00000f00); + val |= fence_size_bits; val |= pitch_val << I830_FENCE_PITCH_SHIFT; val |= I830_FENCE_REG_VALID; @@ -2194,7 +2203,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) return -EBUSY; if (alignment == 0) alignment = i915_gem_get_gtt_alignment(obj); - if (alignment & (PAGE_SIZE - 1)) { + if (alignment & (i915_gem_get_gtt_alignment(obj) - 1)) { DRM_ERROR("Invalid object alignment requested %u\n", alignment); return -EINVAL; } @@ -2211,15 +2220,20 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) } } if (obj_priv->gtt_space == NULL) { + bool lists_empty; + /* If the gtt is empty and we're still having trouble * fitting our object in, we're out of memory. */ #if WATCH_LRU DRM_INFO("%s: GTT full, evicting something\n", __func__); #endif - if (list_empty(&dev_priv->mm.inactive_list) && - list_empty(&dev_priv->mm.flushing_list) && - list_empty(&dev_priv->mm.active_list)) { + spin_lock(&dev_priv->mm.active_list_lock); + lists_empty = (list_empty(&dev_priv->mm.inactive_list) && + list_empty(&dev_priv->mm.flushing_list) && + list_empty(&dev_priv->mm.active_list)); + spin_unlock(&dev_priv->mm.active_list_lock); + if (lists_empty) { DRM_ERROR("GTT full, but LRU list empty\n"); return -ENOMEM; } @@ -3675,6 +3689,7 @@ i915_gem_idle(struct drm_device *dev) i915_gem_retire_requests(dev); + spin_lock(&dev_priv->mm.active_list_lock); if (!dev_priv->mm.wedged) { /* Active and flushing should now be empty as we've * waited for a sequence higher than any pending execbuffer @@ -3701,6 +3716,7 @@ i915_gem_idle(struct drm_device *dev) obj_priv->obj->write_domain &= ~I915_GEM_GPU_DOMAINS; i915_gem_object_move_to_inactive(obj_priv->obj); } + spin_unlock(&dev_priv->mm.active_list_lock); while (!list_empty(&dev_priv->mm.flushing_list)) { struct drm_i915_gem_object *obj_priv; @@ -3949,7 +3965,10 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, if (ret != 0) return ret; + spin_lock(&dev_priv->mm.active_list_lock); BUG_ON(!list_empty(&dev_priv->mm.active_list)); + spin_unlock(&dev_priv->mm.active_list_lock); + BUG_ON(!list_empty(&dev_priv->mm.flushing_list)); BUG_ON(!list_empty(&dev_priv->mm.inactive_list)); BUG_ON(!list_empty(&dev_priv->mm.request_list)); @@ -3993,6 +4012,7 @@ i915_gem_load(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + spin_lock_init(&dev_priv->mm.active_list_lock); INIT_LIST_HEAD(&dev_priv->mm.active_list); INIT_LIST_HEAD(&dev_priv->mm.flushing_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_debug.c b/trunk/drivers/gpu/drm/i915/i915_gem_debug.c index 131c088f8c8a..8d0b943e2c5a 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem_debug.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem_debug.c @@ -105,12 +105,14 @@ i915_dump_lru(struct drm_device *dev, const char *where) struct drm_i915_gem_object *obj_priv; DRM_INFO("active list %s {\n", where); + spin_lock(&dev_priv->mm.active_list_lock); list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) { DRM_INFO(" %p: %08x\n", obj_priv, obj_priv->last_rendering_seqno); } + spin_unlock(&dev_priv->mm.active_list_lock); DRM_INFO("}\n"); DRM_INFO("flushing list %s {\n", where); list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_debugfs.c b/trunk/drivers/gpu/drm/i915/i915_gem_debugfs.c index 455ec970b385..a1ac0c5e7307 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem_debugfs.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem_debugfs.c @@ -69,10 +69,13 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv; + spinlock_t *lock = NULL; switch (list) { case ACTIVE_LIST: seq_printf(m, "Active:\n"); + lock = &dev_priv->mm.active_list_lock; + spin_lock(lock); head = &dev_priv->mm.active_list; break; case INACTIVE_LIST: @@ -104,6 +107,9 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) seq_printf(m, " (fence: %d\n", obj_priv->fence_reg); seq_printf(m, "\n"); } + + if (lock) + spin_unlock(lock); return 0; } diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c b/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c index 4cce1aef438e..6be3f927c86a 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -216,6 +216,22 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) else tile_width = 512; + /* check maximum stride & object size */ + if (IS_I965G(dev)) { + /* i965 stores the end address of the gtt mapping in the fence + * reg, so dont bother to check the size */ + if (stride / 128 > I965_FENCE_MAX_PITCH_VAL) + return false; + } else if (IS_I9XX(dev)) { + if (stride / tile_width > I830_FENCE_MAX_PITCH_VAL || + size > (I830_FENCE_MAX_SIZE_VAL << 20)) + return false; + } else { + if (stride / 128 > I830_FENCE_MAX_PITCH_VAL || + size > (I830_FENCE_MAX_SIZE_VAL << 19)) + return false; + } + /* 965+ just needs multiples of tile width */ if (IS_I965G(dev)) { if (stride & (tile_width - 1)) diff --git a/trunk/drivers/gpu/drm/i915/i915_irq.c b/trunk/drivers/gpu/drm/i915/i915_irq.c index 87b6b603469e..ee7ce7b78cf7 100644 --- a/trunk/drivers/gpu/drm/i915/i915_irq.c +++ b/trunk/drivers/gpu/drm/i915/i915_irq.c @@ -48,10 +48,6 @@ /** Interrupts that we mask and unmask at runtime. */ #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) -/** These are all of the interrupts used by the driver */ -#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ - I915_INTERRUPT_ENABLE_VAR) - #define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ PIPE_VBLANK_INTERRUPT_STATUS) @@ -187,6 +183,19 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) return I915_READ(reg); } +/* + * Handle hotplug events outside the interrupt handler proper. + */ +static void i915_hotplug_work_func(struct work_struct *work) +{ + drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, + hotplug_work); + struct drm_device *dev = dev_priv->dev; + + /* Just fire off a uevent and let userspace tell us what to do */ + drm_sysfs_hotplug_event(dev); +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; @@ -244,6 +253,20 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) ret = IRQ_HANDLED; + /* Consume port. Then clear IIR or we'll miss events */ + if ((I915_HAS_HOTPLUG(dev)) && + (iir & I915_DISPLAY_PORT_INTERRUPT)) { + u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + + DRM_DEBUG("hotplug event received, stat 0x%08x\n", + hotplug_status); + if (hotplug_status & dev_priv->hotplug_supported_mask) + schedule_work(&dev_priv->hotplug_work); + + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + I915_READ(PORT_HOTPLUG_STAT); + } + I915_WRITE(IIR, iir); new_iir = I915_READ(IIR); /* Flush posted writes */ @@ -528,17 +551,24 @@ void i915_driver_irq_preinstall(struct drm_device * dev) atomic_set(&dev_priv->irq_received, 0); + if (I915_HAS_HOTPLUG(dev)) { + I915_WRITE(PORT_HOTPLUG_EN, 0); + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + } + I915_WRITE(HWSTAM, 0xeffe); I915_WRITE(PIPEASTAT, 0); I915_WRITE(PIPEBSTAT, 0); I915_WRITE(IMR, 0xffffffff); I915_WRITE(IER, 0x0); (void) I915_READ(IER); + INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); } int i915_driver_irq_postinstall(struct drm_device *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; @@ -550,13 +580,35 @@ int i915_driver_irq_postinstall(struct drm_device *dev) dev_priv->pipestat[0] = 0; dev_priv->pipestat[1] = 0; + if (I915_HAS_HOTPLUG(dev)) { + u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); + + /* Leave other bits alone */ + hotplug_en |= HOTPLUG_EN_MASK; + I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); + + dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS | + TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS | + SDVOB_HOTPLUG_INT_STATUS; + if (IS_G4X(dev)) { + dev_priv->hotplug_supported_mask |= + HDMIB_HOTPLUG_INT_STATUS | + HDMIC_HOTPLUG_INT_STATUS | + HDMID_HOTPLUG_INT_STATUS; + } + /* Enable in IER... */ + enable_mask |= I915_DISPLAY_PORT_INTERRUPT; + /* and unmask in IMR */ + i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT); + } + /* Disable pipe interrupt enables, clear pending pipe status */ I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); /* Clear pending interrupt status */ I915_WRITE(IIR, I915_READ(IIR)); - I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); + I915_WRITE(IER, enable_mask); I915_WRITE(IMR, dev_priv->irq_mask_reg); (void) I915_READ(IER); @@ -575,6 +627,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev) dev_priv->vblank_pipe = 0; + if (I915_HAS_HOTPLUG(dev)) { + I915_WRITE(PORT_HOTPLUG_EN, 0); + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + } + I915_WRITE(HWSTAM, 0xffffffff); I915_WRITE(PIPEASTAT, 0); I915_WRITE(PIPEBSTAT, 0); diff --git a/trunk/drivers/gpu/drm/i915/i915_reg.h b/trunk/drivers/gpu/drm/i915/i915_reg.h index 377cc588f5e9..e805b590ae71 100644 --- a/trunk/drivers/gpu/drm/i915/i915_reg.h +++ b/trunk/drivers/gpu/drm/i915/i915_reg.h @@ -190,6 +190,8 @@ #define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8) #define I830_FENCE_PITCH_SHIFT 4 #define I830_FENCE_REG_VALID (1<<0) +#define I830_FENCE_MAX_PITCH_VAL 0x10 +#define I830_FENCE_MAX_SIZE_VAL (1<<8) #define I915_FENCE_START_MASK 0x0ff00000 #define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8) @@ -198,6 +200,7 @@ #define I965_FENCE_PITCH_SHIFT 2 #define I965_FENCE_TILING_Y_SHIFT 1 #define I965_FENCE_REG_VALID (1<<0) +#define I965_FENCE_MAX_PITCH_VAL 0x0400 /* * Instruction and interrupt control regs @@ -648,6 +651,14 @@ #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) #define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ +#define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f +#define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \ + HDMIC_HOTPLUG_INT_EN | \ + HDMID_HOTPLUG_INT_EN | \ + SDVOB_HOTPLUG_INT_EN | \ + SDVOC_HOTPLUG_INT_EN | \ + TV_HOTPLUG_INT_EN | \ + CRT_HOTPLUG_INT_EN) #define PORT_HOTPLUG_STAT 0x61114 diff --git a/trunk/drivers/gpu/drm/i915/intel_crt.c b/trunk/drivers/gpu/drm/i915/intel_crt.c index 2b6d44381c31..9bdd959260a5 100644 --- a/trunk/drivers/gpu/drm/i915/intel_crt.c +++ b/trunk/drivers/gpu/drm/i915/intel_crt.c @@ -41,7 +41,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) temp = I915_READ(ADPA); temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); - temp &= ~ADPA_DAC_ENABLE; + temp |= ADPA_DAC_ENABLE; switch(mode) { case DRM_MODE_DPMS_ON: @@ -158,7 +158,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) else tries = 1; hotplug_en = I915_READ(PORT_HOTPLUG_EN); - hotplug_en &= ~(CRT_HOTPLUG_MASK); + hotplug_en &= CRT_FORCE_HOTPLUG_MASK; hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; if (IS_GM45(dev)) diff --git a/trunk/drivers/gpu/drm/i915/intel_display.c b/trunk/drivers/gpu/drm/i915/intel_display.c index d9c50ff94d76..64773ce52964 100644 --- a/trunk/drivers/gpu/drm/i915/intel_display.c +++ b/trunk/drivers/gpu/drm/i915/intel_display.c @@ -636,7 +636,7 @@ void intel_wait_for_vblank(struct drm_device *dev) { /* Wait for 20ms, i.e. one cycle at 50hz. */ - udelay(20000); + mdelay(20); } static int @@ -1106,6 +1106,26 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, return -EINVAL; } + /* SDVO TV has fixed PLL values depend on its clock range, + this mirrors vbios setting. */ + if (is_sdvo && is_tv) { + if (adjusted_mode->clock >= 100000 + && adjusted_mode->clock < 140500) { + clock.p1 = 2; + clock.p2 = 10; + clock.n = 3; + clock.m1 = 16; + clock.m2 = 8; + } else if (adjusted_mode->clock >= 140500 + && adjusted_mode->clock <= 200000) { + clock.p1 = 1; + clock.p2 = 10; + clock.n = 6; + clock.m1 = 12; + clock.m2 = 8; + } + } + if (IS_IGD(dev)) fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2; else diff --git a/trunk/drivers/gpu/drm/i915/intel_modes.c b/trunk/drivers/gpu/drm/i915/intel_modes.c index e42019e5d661..07d7ec976168 100644 --- a/trunk/drivers/gpu/drm/i915/intel_modes.c +++ b/trunk/drivers/gpu/drm/i915/intel_modes.c @@ -76,6 +76,7 @@ int intel_ddc_get_modes(struct intel_output *intel_output) drm_mode_connector_update_edid_property(&intel_output->base, edid); ret = drm_add_edid_modes(&intel_output->base, edid); + intel_output->base.display_info.raw_edid = NULL; kfree(edid); } diff --git a/trunk/drivers/gpu/drm/i915/intel_sdvo.c b/trunk/drivers/gpu/drm/i915/intel_sdvo.c index fbe6f3931b1b..7b31f55f55c8 100644 --- a/trunk/drivers/gpu/drm/i915/intel_sdvo.c +++ b/trunk/drivers/gpu/drm/i915/intel_sdvo.c @@ -273,20 +273,20 @@ static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd, struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; int i; - DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); + printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd); for (i = 0; i < args_len; i++) - printk("%02X ", ((u8 *)args)[i]); + printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]); for (; i < 8; i++) - printk(" "); + printk(KERN_DEBUG " "); for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - printk("(%s)", sdvo_cmd_names[i].name); + printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name); break; } } if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0])) - printk("(%02X)",cmd); - printk("\n"); + printk(KERN_DEBUG "(%02X)", cmd); + printk(KERN_DEBUG "\n"); } #else #define intel_sdvo_debug_write(o, c, a, l) @@ -323,17 +323,18 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output, u8 status) { struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; + int i; - DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv)); + printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv)); for (i = 0; i < response_len; i++) - printk("%02X ", ((u8 *)response)[i]); + printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]); for (; i < 8; i++) - printk(" "); + printk(KERN_DEBUG " "); if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - printk("(%s)", cmd_status_names[status]); + printk(KERN_DEBUG "(%s)", cmd_status_names[status]); else - printk("(??? %d)", status); - printk("\n"); + printk(KERN_DEBUG "(??? %d)", status); + printk(KERN_DEBUG "\n"); } #else #define intel_sdvo_debug_response(o, r, l, s) @@ -588,9 +589,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output, struct intel_sdvo_preferred_input_timing_args args; uint8_t status; + memset(&args, 0, sizeof(args)); args.clock = clock; args.width = width; args.height = height; + args.interlace = 0; + args.scaled = 0; intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, &args, sizeof(args)); status = intel_sdvo_read_response(output, NULL, 0); @@ -683,7 +687,7 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, dtd->part1.v_high = (((height >> 8) & 0xf) << 4) | ((v_blank_len >> 8) & 0xf); - dtd->part2.h_sync_off = h_sync_offset; + dtd->part2.h_sync_off = h_sync_offset & 0xff; dtd->part2.h_sync_width = h_sync_len & 0xff; dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 | (v_sync_len & 0xf); @@ -705,27 +709,10 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd, static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, struct intel_sdvo_dtd *dtd) { - uint16_t width, height; - uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len; - uint16_t h_sync_offset, v_sync_offset; - - width = mode->crtc_hdisplay; - height = mode->crtc_vdisplay; - - /* do some mode translations */ - h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start; - h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; - - v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start; - v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; - - h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start; - v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start; - mode->hdisplay = dtd->part1.h_active; mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8; mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off; - mode->hsync_start += (dtd->part2.sync_off_width_high & 0xa0) << 2; + mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2; mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width; mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4; mode->htotal = mode->hdisplay + dtd->part1.h_blank; @@ -735,7 +722,7 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8; mode->vsync_start = mode->vdisplay; mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf; - mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0a) << 2; + mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2; mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0; mode->vsync_end = mode->vsync_start + (dtd->part2.v_sync_off_width & 0xf); @@ -745,7 +732,7 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode, mode->clock = dtd->part1.clock * 10; - mode->flags &= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); + mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC); if (dtd->part2.dtd_flags & 0x2) mode->flags |= DRM_MODE_FLAG_PHSYNC; if (dtd->part2.dtd_flags & 0x4) @@ -924,6 +911,27 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output, SDVO_HBUF_TX_VSYNC); } +static void intel_sdvo_set_tv_format(struct intel_output *output) +{ + struct intel_sdvo_priv *sdvo_priv = output->dev_priv; + struct intel_sdvo_tv_format *format, unset; + u8 status; + + format = &sdvo_priv->tv_format; + memset(&unset, 0, sizeof(unset)); + if (memcmp(format, &unset, sizeof(*format))) { + DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n", + SDVO_NAME(sdvo_priv)); + format->ntsc_m = 1; + intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, format, + sizeof(*format)); + status = intel_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + DRM_DEBUG("%s: Failed to set TV format\n", + SDVO_NAME(sdvo_priv)); + } +} + static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -968,6 +976,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); + drm_mode_set_crtcinfo(adjusted_mode, 0); + + mode->clock = adjusted_mode->clock; + + adjusted_mode->clock *= + intel_sdvo_get_pixel_multiplier(mode); } else { return false; } @@ -1012,7 +1026,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, sdvox |= SDVO_AUDIO_ENABLE; } - intel_sdvo_get_dtd_from_mode(&input_dtd, mode); + /* We have tried to get input timing in mode_fixup, and filled into + adjusted_mode */ + if (sdvo_priv->is_tv) + intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); + else + intel_sdvo_get_dtd_from_mode(&input_dtd, mode); /* If it's a TV, we already set the output timing in mode_fixup. * Otherwise, the output timing is equal to the input timing. @@ -1027,6 +1046,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* Set the input timing to the screen. Assume always input 0. */ intel_sdvo_set_target_input(output, true, false); + if (sdvo_priv->is_tv) + intel_sdvo_set_tv_format(output); + /* We would like to use intel_sdvo_create_preferred_input_timing() to * provide the device with a timing it can support, if it supports that * feature. However, presumably we would need to adjust the CRTC to @@ -1395,7 +1417,7 @@ static void intel_sdvo_check_tv_format(struct intel_output *output) { struct intel_sdvo_priv *dev_priv = output->dev_priv; - struct intel_sdvo_tv_format format, unset; + struct intel_sdvo_tv_format format; uint8_t status; intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0); @@ -1403,15 +1425,7 @@ intel_sdvo_check_tv_format(struct intel_output *output) if (status != SDVO_CMD_STATUS_SUCCESS) return; - memset(&unset, 0, sizeof(unset)); - if (memcmp(&format, &unset, sizeof(format))) { - DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n", - SDVO_NAME(dev_priv)); - - format.ntsc_m = true; - intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, NULL, 0); - status = intel_sdvo_read_response(output, NULL, 0); - } + memcpy(&dev_priv->tv_format, &format, sizeof(format)); } /* @@ -1420,68 +1434,70 @@ intel_sdvo_check_tv_format(struct intel_output *output) * XXX: all 60Hz refresh? */ struct drm_display_mode sdvo_tv_modes[] = { - { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815680, 321, 384, 416, - 200, 0, 232, 201, 233, 4196112, 0, + { DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384, + 416, 0, 200, 201, 232, 233, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814080, 321, 384, 416, - 240, 0, 272, 241, 273, 4196112, 0, + { DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384, + 416, 0, 240, 241, 272, 273, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910080, 401, 464, 496, - 300, 0, 332, 301, 333, 4196112, 0, + { DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464, + 496, 0, 300, 301, 332, 333, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913280, 641, 704, 736, - 350, 0, 382, 351, 383, 4196112, 0, + { DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704, + 736, 0, 350, 351, 382, 383, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736, - 400, 0, 432, 401, 433, 4196112, 0, + { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704, + 736, 0, 400, 401, 432, 433, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736, - 400, 0, 432, 401, 433, 4196112, 0, + { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704, + 736, 0, 480, 481, 512, 513, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624000, 705, 768, 800, - 480, 0, 512, 481, 513, 4196112, 0, + { DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768, + 800, 0, 480, 481, 512, 513, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232000, 705, 768, 800, - 576, 0, 608, 577, 609, 4196112, 0, + { DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768, + 800, 0, 576, 577, 608, 609, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751680, 721, 784, 816, - 350, 0, 382, 351, 383, 4196112, 0, + { DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784, + 816, 0, 350, 351, 382, 383, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199680, 721, 784, 816, - 400, 0, 432, 401, 433, 4196112, 0, + { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784, + 816, 0, 400, 401, 432, 433, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116480, 721, 784, 816, - 480, 0, 512, 481, 513, 4196112, 0, + { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784, + 816, 0, 480, 481, 512, 513, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054080, 721, 784, 816, - 540, 0, 572, 541, 573, 4196112, 0, + { DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784, + 816, 0, 540, 541, 572, 573, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816640, 721, 784, 816, - 576, 0, 608, 577, 609, 4196112, 0, + { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784, + 816, 0, 576, 577, 608, 609, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570560, 769, 832, 864, - 576, 0, 608, 577, 609, 4196112, 0, + { DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832, + 864, 0, 576, 577, 608, 609, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030080, 801, 864, 896, - 600, 0, 632, 601, 633, 4196112, 0, + { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864, + 896, 0, 600, 601, 632, 633, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581760, 833, 896, 928, - 624, 0, 656, 625, 657, 4196112, 0, + { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896, + 928, 0, 624, 625, 656, 657, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707040, 921, 984, 1016, - 766, 0, 798, 767, 799, 4196112, 0, + { DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984, + 1016, 0, 766, 767, 798, 799, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827200, 1025, 1088, 1120, - 768, 0, 800, 769, 801, 4196112, 0, + { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088, + 1120, 0, 768, 769, 800, 801, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, - { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265920, 1281, 1344, 1376, - 1024, 0, 1056, 1025, 1057, 4196112, 0, + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344, + 1376, 0, 1024, 1025, 1056, 1057, 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, }; static void intel_sdvo_get_tv_modes(struct drm_connector *connector) { struct intel_output *output = to_intel_output(connector); + struct intel_sdvo_priv *sdvo_priv = output->dev_priv; + struct intel_sdvo_sdtv_resolution_request tv_res; uint32_t reply = 0; uint8_t status; int i = 0; @@ -1491,15 +1507,22 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) /* Read the list of supported input resolutions for the selected TV * format. */ + memset(&tv_res, 0, sizeof(tv_res)); + memcpy(&tv_res, &sdvo_priv->tv_format, sizeof(tv_res)); intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT, - NULL, 0); + &tv_res, sizeof(tv_res)); status = intel_sdvo_read_response(output, &reply, 3); if (status != SDVO_CMD_STATUS_SUCCESS) return; for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++) - if (reply & (1 << i)) - drm_mode_probed_add(connector, &sdvo_tv_modes[i]); + if (reply & (1 << i)) { + struct drm_display_mode *nmode; + nmode = drm_mode_duplicate(connector->dev, + &sdvo_tv_modes[i]); + if (nmode) + drm_mode_probed_add(connector, nmode); + } } static int intel_sdvo_get_modes(struct drm_connector *connector) diff --git a/trunk/drivers/gpu/drm/i915/intel_sdvo_regs.h b/trunk/drivers/gpu/drm/i915/intel_sdvo_regs.h index 1117b9c151a6..193938b7d7f9 100644 --- a/trunk/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/trunk/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -100,6 +100,9 @@ struct intel_sdvo_preferred_input_timing_args { u16 clock; u16 width; u16 height; + u8 interlace:1; + u8 scaled:1; + u8 pad:6; } __attribute__((packed)); /* I2C registers for SDVO */ diff --git a/trunk/drivers/gpu/drm/i915/intel_tv.c b/trunk/drivers/gpu/drm/i915/intel_tv.c index ceca9471a75a..d2c32983242d 100644 --- a/trunk/drivers/gpu/drm/i915/intel_tv.c +++ b/trunk/drivers/gpu/drm/i915/intel_tv.c @@ -1570,33 +1570,49 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop struct drm_device *dev = connector->dev; struct intel_output *intel_output = to_intel_output(connector); struct intel_tv_priv *tv_priv = intel_output->dev_priv; + struct drm_encoder *encoder = &intel_output->enc; + struct drm_crtc *crtc = encoder->crtc; int ret = 0; + bool changed = false; ret = drm_connector_property_set_value(connector, property, val); if (ret < 0) goto out; - if (property == dev->mode_config.tv_left_margin_property) + if (property == dev->mode_config.tv_left_margin_property && + tv_priv->margin[TV_MARGIN_LEFT] != val) { tv_priv->margin[TV_MARGIN_LEFT] = val; - else if (property == dev->mode_config.tv_right_margin_property) + changed = true; + } else if (property == dev->mode_config.tv_right_margin_property && + tv_priv->margin[TV_MARGIN_RIGHT] != val) { tv_priv->margin[TV_MARGIN_RIGHT] = val; - else if (property == dev->mode_config.tv_top_margin_property) + changed = true; + } else if (property == dev->mode_config.tv_top_margin_property && + tv_priv->margin[TV_MARGIN_TOP] != val) { tv_priv->margin[TV_MARGIN_TOP] = val; - else if (property == dev->mode_config.tv_bottom_margin_property) + changed = true; + } else if (property == dev->mode_config.tv_bottom_margin_property && + tv_priv->margin[TV_MARGIN_BOTTOM] != val) { tv_priv->margin[TV_MARGIN_BOTTOM] = val; - else if (property == dev->mode_config.tv_mode_property) { + changed = true; + } else if (property == dev->mode_config.tv_mode_property) { if (val >= NUM_TV_MODES) { ret = -EINVAL; goto out; } + if (!strcmp(tv_priv->tv_format, tv_modes[val].name)) + goto out; + tv_priv->tv_format = tv_modes[val].name; - intel_tv_mode_set(&intel_output->enc, NULL, NULL); + changed = true; } else { ret = -EINVAL; goto out; } - intel_tv_mode_set(&intel_output->enc, NULL, NULL); + if (changed && crtc) + drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, + crtc->y, crtc->fb); out: return ret; } diff --git a/trunk/drivers/gpu/drm/radeon/r600_cp.c b/trunk/drivers/gpu/drm/radeon/r600_cp.c index 9d14eee3ed09..bc9d09dfa8e7 100644 --- a/trunk/drivers/gpu/drm/radeon/r600_cp.c +++ b/trunk/drivers/gpu/drm/radeon/r600_cp.c @@ -388,17 +388,17 @@ static void r600_cp_load_microcode(drm_radeon_private_t *dev_priv) DRM_INFO("Loading RS780 CP Microcode\n"); for (i = 0; i < PM4_UCODE_SIZE; i++) { RADEON_WRITE(R600_CP_ME_RAM_DATA, - RV670_cp_microcode[i][0]); + RS780_cp_microcode[i][0]); RADEON_WRITE(R600_CP_ME_RAM_DATA, - RV670_cp_microcode[i][1]); + RS780_cp_microcode[i][1]); RADEON_WRITE(R600_CP_ME_RAM_DATA, - RV670_cp_microcode[i][2]); + RS780_cp_microcode[i][2]); } RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0); DRM_INFO("Loading RS780 PFP Microcode\n"); for (i = 0; i < PFP_UCODE_SIZE; i++) - RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RV670_pfp_microcode[i]); + RADEON_WRITE(R600_CP_PFP_UCODE_DATA, RS780_pfp_microcode[i]); } RADEON_WRITE(R600_CP_PFP_UCODE_ADDR, 0); RADEON_WRITE(R600_CP_ME_RAM_WADDR, 0); diff --git a/trunk/drivers/hwmon/Kconfig b/trunk/drivers/hwmon/Kconfig index 51ff9b3d7ea2..ce52bf2f235e 100644 --- a/trunk/drivers/hwmon/Kconfig +++ b/trunk/drivers/hwmon/Kconfig @@ -571,6 +571,17 @@ config SENSORS_LM93 This driver can also be built as a module. If so, the module will be called lm93. +config SENSORS_LTC4215 + tristate "Linear Technology LTC4215" + depends on I2C && EXPERIMENTAL + default n + help + If you say yes here you get support for Linear Technology LTC4215 + Hot Swap Controller I2C interface. + + This driver can also be built as a module. If so, the module will + be called ltc4215. + config SENSORS_LTC4245 tristate "Linear Technology LTC4245" depends on I2C && EXPERIMENTAL @@ -582,6 +593,15 @@ config SENSORS_LTC4245 This driver can also be built as a module. If so, the module will be called ltc4245. +config SENSORS_LM95241 + tristate "National Semiconductor LM95241 sensor chip" + depends on I2C + help + If you say yes here you get support for LM95241 sensor chip. + + This driver can also be built as a module. If so, the module + will be called lm95241. + config SENSORS_MAX1111 tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip" depends on SPI_MASTER @@ -912,6 +932,22 @@ config SENSORS_LIS3LV02D Say Y here if you have an applicable laptop and want to experience the awesome power of lis3lv02d. +config SENSORS_LIS3_SPI + tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" + depends on !ACPI && SPI_MASTER && INPUT + default n + help + This driver provides support for the LIS3LV02Dx accelerometer connected + via SPI. The accelerometer data is readable via + /sys/devices/platform/lis3lv02d. + + This driver also provides an absolute input class device, allowing + the laptop to act as a pinball machine-esque joystick. + + This driver can also be built as modules. If so, the core module + will be called lis3lv02d and a specific module for the SPI transport + is called lis3lv02d_spi. + config SENSORS_APPLESMC tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" depends on INPUT && X86 diff --git a/trunk/drivers/hwmon/Makefile b/trunk/drivers/hwmon/Makefile index e332d6267920..3a6b1f06f8f4 100644 --- a/trunk/drivers/hwmon/Makefile +++ b/trunk/drivers/hwmon/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o +obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM70) += lm70.o obj-$(CONFIG_SENSORS_LM75) += lm75.o @@ -64,6 +65,8 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o obj-$(CONFIG_SENSORS_LM90) += lm90.o obj-$(CONFIG_SENSORS_LM92) += lm92.o obj-$(CONFIG_SENSORS_LM93) += lm93.o +obj-$(CONFIG_SENSORS_LM95241) += lm95241.o +obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o obj-$(CONFIG_SENSORS_MAX1111) += max1111.o obj-$(CONFIG_SENSORS_MAX1619) += max1619.o diff --git a/trunk/drivers/hwmon/hp_accel.c b/trunk/drivers/hwmon/hp_accel.c index 29c83b5b9697..55d3dc565be6 100644 --- a/trunk/drivers/hwmon/hp_accel.c +++ b/trunk/drivers/hwmon/hp_accel.c @@ -85,25 +85,31 @@ MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); /** * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. - * @handle: the handle of the device + * @lis3: pointer to the device struct * - * Returns AE_OK on success. + * Returns 0 on success. */ -acpi_status lis3lv02d_acpi_init(acpi_handle handle) +int lis3lv02d_acpi_init(struct lis3lv02d *lis3) { - return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL); + struct acpi_device *dev = lis3->bus_priv; + if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI, + NULL, NULL) != AE_OK) + return -EINVAL; + + return 0; } /** * lis3lv02d_acpi_read - ACPI ALRD method: read a register - * @handle: the handle of the device + * @lis3: pointer to the device struct * @reg: the register to read * @ret: result of the operation * - * Returns AE_OK on success. + * Returns 0 on success. */ -acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret) +int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret) { + struct acpi_device *dev = lis3->bus_priv; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; unsigned long long lret; @@ -111,21 +117,22 @@ acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret) arg0.integer.value = reg; - status = acpi_evaluate_integer(handle, "ALRD", &args, &lret); + status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret); *ret = lret; - return status; + return (status != AE_OK) ? -EINVAL : 0; } /** * lis3lv02d_acpi_write - ACPI ALWR method: write to a register - * @handle: the handle of the device + * @lis3: pointer to the device struct * @reg: the register to write to * @val: the value to write * - * Returns AE_OK on success. + * Returns 0 on success. */ -acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val) +int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val) { + struct acpi_device *dev = lis3->bus_priv; unsigned long long ret; /* Not used when writting */ union acpi_object in_obj[2]; struct acpi_object_list args = { 2, in_obj }; @@ -135,12 +142,15 @@ acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val) in_obj[1].type = ACPI_TYPE_INTEGER; in_obj[1].integer.value = val; - return acpi_evaluate_integer(handle, "ALWR", &args, &ret); + if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK) + return -EINVAL; + + return 0; } static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) { - adev.ac = *((struct axis_conversion *)dmi->driver_data); + lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data); printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident); return 1; @@ -187,6 +197,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), + AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted), AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd), AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd), AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), @@ -201,6 +212,8 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { PRODUCT_NAME, "HP Pavilion dv5", BOARD_NAME, "3600", y_inverted), + AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted), + AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted), { NULL, } /* Laptop models without axis info (yet): * "NC6910" "HP Compaq 6910" @@ -214,7 +227,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) { - acpi_handle handle = adev.device->handle; + struct acpi_device *dev = lis3_dev.bus_priv; unsigned long long ret; /* Not used when writing */ union acpi_object in_obj[1]; struct acpi_object_list args = { 1, in_obj }; @@ -222,7 +235,7 @@ static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness in_obj[0].type = ACPI_TYPE_INTEGER; in_obj[0].integer.value = !!value; - acpi_evaluate_integer(handle, "ALED", &args, &ret); + acpi_evaluate_integer(dev->handle, "ALED", &args, &ret); } static struct delayed_led_classdev hpled_led = { @@ -254,28 +267,11 @@ static void lis3lv02d_enum_resources(struct acpi_device *device) acpi_status status; status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, - lis3lv02d_get_resource, &adev.irq); + lis3lv02d_get_resource, &lis3_dev.irq); if (ACPI_FAILURE(status)) printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n"); } -static s16 lis3lv02d_read_16(acpi_handle handle, int reg) -{ - u8 lo, hi; - - adev.read(handle, reg - 1, &lo); - adev.read(handle, reg, &hi); - /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ - return (s16)((hi << 8) | lo); -} - -static s16 lis3lv02d_read_8(acpi_handle handle, int reg) -{ - s8 lo; - adev.read(handle, reg, &lo); - return lo; -} - static int lis3lv02d_add(struct acpi_device *device) { int ret; @@ -283,51 +279,35 @@ static int lis3lv02d_add(struct acpi_device *device) if (!device) return -EINVAL; - adev.device = device; - adev.init = lis3lv02d_acpi_init; - adev.read = lis3lv02d_acpi_read; - adev.write = lis3lv02d_acpi_write; + lis3_dev.bus_priv = device; + lis3_dev.init = lis3lv02d_acpi_init; + lis3_dev.read = lis3lv02d_acpi_read; + lis3_dev.write = lis3lv02d_acpi_write; strcpy(acpi_device_name(device), DRIVER_NAME); strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); - device->driver_data = &adev; - - lis3lv02d_acpi_read(device->handle, WHO_AM_I, &adev.whoami); - switch (adev.whoami) { - case LIS_DOUBLE_ID: - printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n"); - adev.read_data = lis3lv02d_read_16; - adev.mdps_max_val = 2048; - break; - case LIS_SINGLE_ID: - printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n"); - adev.read_data = lis3lv02d_read_8; - adev.mdps_max_val = 128; - break; - default: - printk(KERN_ERR DRIVER_NAME - ": unknown sensor type 0x%X\n", adev.whoami); - return -EINVAL; - } + device->driver_data = &lis3_dev; + + /* obtain IRQ number of our device from ACPI */ + lis3lv02d_enum_resources(device); /* If possible use a "standard" axes order */ if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { printk(KERN_INFO DRIVER_NAME ": laptop model unknown, " "using default axes configuration\n"); - adev.ac = lis3lv02d_axis_normal; + lis3_dev.ac = lis3lv02d_axis_normal; } - INIT_WORK(&hpled_led.work, delayed_set_status_worker); - ret = led_classdev_register(NULL, &hpled_led.led_classdev); + /* call the core layer do its init */ + ret = lis3lv02d_init_device(&lis3_dev); if (ret) return ret; - /* obtain IRQ number of our device from ACPI */ - lis3lv02d_enum_resources(adev.device); - - ret = lis3lv02d_init_device(&adev); + INIT_WORK(&hpled_led.work, delayed_set_status_worker); + ret = led_classdev_register(NULL, &hpled_led.led_classdev); if (ret) { + lis3lv02d_joystick_disable(); + lis3lv02d_poweroff(&lis3_dev); flush_work(&hpled_led.work); - led_classdev_unregister(&hpled_led.led_classdev); return ret; } @@ -340,7 +320,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type) return -EINVAL; lis3lv02d_joystick_disable(); - lis3lv02d_poweroff(device->handle); + lis3lv02d_poweroff(&lis3_dev); flush_work(&hpled_led.work); led_classdev_unregister(&hpled_led.led_classdev); @@ -353,19 +333,19 @@ static int lis3lv02d_remove(struct acpi_device *device, int type) static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) { /* make sure the device is off when we suspend */ - lis3lv02d_poweroff(device->handle); + lis3lv02d_poweroff(&lis3_dev); return 0; } static int lis3lv02d_resume(struct acpi_device *device) { /* put back the device in the right state (ACPI might turn it on) */ - mutex_lock(&adev.lock); - if (adev.usage > 0) - lis3lv02d_poweron(device->handle); + mutex_lock(&lis3_dev.lock); + if (lis3_dev.usage > 0) + lis3lv02d_poweron(&lis3_dev); else - lis3lv02d_poweroff(device->handle); - mutex_unlock(&adev.lock); + lis3lv02d_poweroff(&lis3_dev); + mutex_unlock(&lis3_dev.lock); return 0; } #else diff --git a/trunk/drivers/hwmon/lis3lv02d.c b/trunk/drivers/hwmon/lis3lv02d.c index 8bb2158f0453..778eb7795983 100644 --- a/trunk/drivers/hwmon/lis3lv02d.c +++ b/trunk/drivers/hwmon/lis3lv02d.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include "lis3lv02d.h" @@ -53,13 +52,30 @@ * joystick. */ -struct acpi_lis3lv02d adev = { - .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(adev.misc_wait), +struct lis3lv02d lis3_dev = { + .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait), }; -EXPORT_SYMBOL_GPL(adev); +EXPORT_SYMBOL_GPL(lis3_dev); -static int lis3lv02d_add_fs(struct acpi_device *device); +static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg) +{ + s8 lo; + if (lis3->read(lis3, reg, &lo) < 0) + return 0; + + return lo; +} + +static s16 lis3lv02d_read_16(struct lis3lv02d *lis3, int reg) +{ + u8 lo, hi; + + lis3->read(lis3, reg - 1, &lo); + lis3->read(lis3, reg, &hi); + /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ + return (s16)((hi << 8) | lo); +} /** * lis3lv02d_get_axis - For the given axis, give the value converted @@ -78,36 +94,36 @@ static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3]) /** * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer - * @handle: the handle to the device - * @x: where to store the X axis value - * @y: where to store the Y axis value - * @z: where to store the Z axis value + * @lis3: pointer to the device struct + * @x: where to store the X axis value + * @y: where to store the Y axis value + * @z: where to store the Z axis value * * Note that 40Hz input device can eat up about 10% CPU at 800MHZ */ -static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z) +static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) { int position[3]; - position[0] = adev.read_data(handle, OUTX); - position[1] = adev.read_data(handle, OUTY); - position[2] = adev.read_data(handle, OUTZ); + position[0] = lis3_dev.read_data(lis3, OUTX); + position[1] = lis3_dev.read_data(lis3, OUTY); + position[2] = lis3_dev.read_data(lis3, OUTZ); - *x = lis3lv02d_get_axis(adev.ac.x, position); - *y = lis3lv02d_get_axis(adev.ac.y, position); - *z = lis3lv02d_get_axis(adev.ac.z, position); + *x = lis3lv02d_get_axis(lis3_dev.ac.x, position); + *y = lis3lv02d_get_axis(lis3_dev.ac.y, position); + *z = lis3lv02d_get_axis(lis3_dev.ac.z, position); } -void lis3lv02d_poweroff(acpi_handle handle) +void lis3lv02d_poweroff(struct lis3lv02d *lis3) { - adev.is_on = 0; + lis3_dev.is_on = 0; } EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); -void lis3lv02d_poweron(acpi_handle handle) +void lis3lv02d_poweron(struct lis3lv02d *lis3) { - adev.is_on = 1; - adev.init(handle); + lis3_dev.is_on = 1; + lis3_dev.init(lis3); } EXPORT_SYMBOL_GPL(lis3lv02d_poweron); @@ -116,13 +132,13 @@ EXPORT_SYMBOL_GPL(lis3lv02d_poweron); * device will always be on until a call to lis3lv02d_decrease_use(). Not to be * used from interrupt context. */ -static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev) +static void lis3lv02d_increase_use(struct lis3lv02d *dev) { mutex_lock(&dev->lock); dev->usage++; if (dev->usage == 1) { if (!dev->is_on) - lis3lv02d_poweron(dev->device->handle); + lis3lv02d_poweron(dev); } mutex_unlock(&dev->lock); } @@ -131,12 +147,12 @@ static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev) * To be called whenever a usage of the device is stopped. * It will make sure to turn off the device when there is not usage. */ -static void lis3lv02d_decrease_use(struct acpi_lis3lv02d *dev) +static void lis3lv02d_decrease_use(struct lis3lv02d *dev) { mutex_lock(&dev->lock); dev->usage--; if (dev->usage == 0) - lis3lv02d_poweroff(dev->device->handle); + lis3lv02d_poweroff(dev); mutex_unlock(&dev->lock); } @@ -147,10 +163,10 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy) * the lid is closed. This leads to interrupts as soon as a little move * is done. */ - atomic_inc(&adev.count); + atomic_inc(&lis3_dev.count); - wake_up_interruptible(&adev.misc_wait); - kill_fasync(&adev.async_queue, SIGIO, POLL_IN); + wake_up_interruptible(&lis3_dev.misc_wait); + kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); return IRQ_HANDLED; } @@ -158,10 +174,10 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) { int ret; - if (test_and_set_bit(0, &adev.misc_opened)) + if (test_and_set_bit(0, &lis3_dev.misc_opened)) return -EBUSY; /* already open */ - atomic_set(&adev.count, 0); + atomic_set(&lis3_dev.count, 0); /* * The sensor can generate interrupts for free-fall and direction @@ -174,25 +190,25 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) * io-apic is not configurable (and generates a warning) but I keep it * in case of support for other hardware. */ - ret = request_irq(adev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING, - DRIVER_NAME, &adev); + ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING, + DRIVER_NAME, &lis3_dev); if (ret) { - clear_bit(0, &adev.misc_opened); - printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", adev.irq); + clear_bit(0, &lis3_dev.misc_opened); + printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq); return -EBUSY; } - lis3lv02d_increase_use(&adev); - printk("lis3: registered interrupt %d\n", adev.irq); + lis3lv02d_increase_use(&lis3_dev); + printk("lis3: registered interrupt %d\n", lis3_dev.irq); return 0; } static int lis3lv02d_misc_release(struct inode *inode, struct file *file) { - fasync_helper(-1, file, 0, &adev.async_queue); - lis3lv02d_decrease_use(&adev); - free_irq(adev.irq, &adev); - clear_bit(0, &adev.misc_opened); /* release the device */ + fasync_helper(-1, file, 0, &lis3_dev.async_queue); + lis3lv02d_decrease_use(&lis3_dev); + free_irq(lis3_dev.irq, &lis3_dev); + clear_bit(0, &lis3_dev.misc_opened); /* release the device */ return 0; } @@ -207,10 +223,10 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, if (count < 1) return -EINVAL; - add_wait_queue(&adev.misc_wait, &wait); + add_wait_queue(&lis3_dev.misc_wait, &wait); while (true) { set_current_state(TASK_INTERRUPTIBLE); - data = atomic_xchg(&adev.count, 0); + data = atomic_xchg(&lis3_dev.count, 0); if (data) break; @@ -240,22 +256,22 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, out: __set_current_state(TASK_RUNNING); - remove_wait_queue(&adev.misc_wait, &wait); + remove_wait_queue(&lis3_dev.misc_wait, &wait); return retval; } static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) { - poll_wait(file, &adev.misc_wait, wait); - if (atomic_read(&adev.count)) + poll_wait(file, &lis3_dev.misc_wait, wait); + if (atomic_read(&lis3_dev.count)) return POLLIN | POLLRDNORM; return 0; } static int lis3lv02d_misc_fasync(int fd, struct file *file, int on) { - return fasync_helper(fd, file, on, &adev.async_queue); + return fasync_helper(fd, file, on, &lis3_dev.async_queue); } static const struct file_operations lis3lv02d_misc_fops = { @@ -283,12 +299,12 @@ static int lis3lv02d_joystick_kthread(void *data) int x, y, z; while (!kthread_should_stop()) { - lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z); - input_report_abs(adev.idev, ABS_X, x - adev.xcalib); - input_report_abs(adev.idev, ABS_Y, y - adev.ycalib); - input_report_abs(adev.idev, ABS_Z, z - adev.zcalib); + lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); + input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib); + input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib); + input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib); - input_sync(adev.idev); + input_sync(lis3_dev.idev); try_to_freeze(); msleep_interruptible(MDPS_POLL_INTERVAL); @@ -299,11 +315,11 @@ static int lis3lv02d_joystick_kthread(void *data) static int lis3lv02d_joystick_open(struct input_dev *input) { - lis3lv02d_increase_use(&adev); - adev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d"); - if (IS_ERR(adev.kthread)) { - lis3lv02d_decrease_use(&adev); - return PTR_ERR(adev.kthread); + lis3lv02d_increase_use(&lis3_dev); + lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d"); + if (IS_ERR(lis3_dev.kthread)) { + lis3lv02d_decrease_use(&lis3_dev); + return PTR_ERR(lis3_dev.kthread); } return 0; @@ -311,45 +327,46 @@ static int lis3lv02d_joystick_open(struct input_dev *input) static void lis3lv02d_joystick_close(struct input_dev *input) { - kthread_stop(adev.kthread); - lis3lv02d_decrease_use(&adev); + kthread_stop(lis3_dev.kthread); + lis3lv02d_decrease_use(&lis3_dev); } static inline void lis3lv02d_calibrate_joystick(void) { - lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib); + lis3lv02d_get_xyz(&lis3_dev, + &lis3_dev.xcalib, &lis3_dev.ycalib, &lis3_dev.zcalib); } int lis3lv02d_joystick_enable(void) { int err; - if (adev.idev) + if (lis3_dev.idev) return -EINVAL; - adev.idev = input_allocate_device(); - if (!adev.idev) + lis3_dev.idev = input_allocate_device(); + if (!lis3_dev.idev) return -ENOMEM; lis3lv02d_calibrate_joystick(); - adev.idev->name = "ST LIS3LV02DL Accelerometer"; - adev.idev->phys = DRIVER_NAME "/input0"; - adev.idev->id.bustype = BUS_HOST; - adev.idev->id.vendor = 0; - adev.idev->dev.parent = &adev.pdev->dev; - adev.idev->open = lis3lv02d_joystick_open; - adev.idev->close = lis3lv02d_joystick_close; + lis3_dev.idev->name = "ST LIS3LV02DL Accelerometer"; + lis3_dev.idev->phys = DRIVER_NAME "/input0"; + lis3_dev.idev->id.bustype = BUS_HOST; + lis3_dev.idev->id.vendor = 0; + lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev; + lis3_dev.idev->open = lis3lv02d_joystick_open; + lis3_dev.idev->close = lis3lv02d_joystick_close; - set_bit(EV_ABS, adev.idev->evbit); - input_set_abs_params(adev.idev, ABS_X, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); - input_set_abs_params(adev.idev, ABS_Y, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); - input_set_abs_params(adev.idev, ABS_Z, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); + set_bit(EV_ABS, lis3_dev.idev->evbit); + input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); + input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); + input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); - err = input_register_device(adev.idev); + err = input_register_device(lis3_dev.idev); if (err) { - input_free_device(adev.idev); - adev.idev = NULL; + input_free_device(lis3_dev.idev); + lis3_dev.idev = NULL; } return err; @@ -358,71 +375,40 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); void lis3lv02d_joystick_disable(void) { - if (!adev.idev) + if (!lis3_dev.idev) return; misc_deregister(&lis3lv02d_misc_device); - input_unregister_device(adev.idev); - adev.idev = NULL; + input_unregister_device(lis3_dev.idev); + lis3_dev.idev = NULL; } EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); -/* - * Initialise the accelerometer and the various subsystems. - * Should be rather independant of the bus system. - */ -int lis3lv02d_init_device(struct acpi_lis3lv02d *dev) -{ - mutex_init(&dev->lock); - lis3lv02d_add_fs(dev->device); - lis3lv02d_increase_use(dev); - - if (lis3lv02d_joystick_enable()) - printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); - - printk("lis3_init_device: irq %d\n", dev->irq); - - /* if we did not get an IRQ from ACPI - we have nothing more to do */ - if (!dev->irq) { - printk(KERN_ERR DRIVER_NAME - ": No IRQ in ACPI. Disabling /dev/freefall\n"); - goto out; - } - - printk("lis3: registering device\n"); - if (misc_register(&lis3lv02d_misc_device)) - printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); -out: - lis3lv02d_decrease_use(dev); - return 0; -} -EXPORT_SYMBOL_GPL(lis3lv02d_init_device); - /* Sysfs stuff */ static ssize_t lis3lv02d_position_show(struct device *dev, struct device_attribute *attr, char *buf) { int x, y, z; - lis3lv02d_increase_use(&adev); - lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z); - lis3lv02d_decrease_use(&adev); + lis3lv02d_increase_use(&lis3_dev); + lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); + lis3lv02d_decrease_use(&lis3_dev); return sprintf(buf, "(%d,%d,%d)\n", x, y, z); } static ssize_t lis3lv02d_calibrate_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "(%d,%d,%d)\n", adev.xcalib, adev.ycalib, adev.zcalib); + return sprintf(buf, "(%d,%d,%d)\n", lis3_dev.xcalib, lis3_dev.ycalib, lis3_dev.zcalib); } static ssize_t lis3lv02d_calibrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - lis3lv02d_increase_use(&adev); + lis3lv02d_increase_use(&lis3_dev); lis3lv02d_calibrate_joystick(); - lis3lv02d_decrease_use(&adev); + lis3lv02d_decrease_use(&lis3_dev); return count; } @@ -434,9 +420,9 @@ static ssize_t lis3lv02d_rate_show(struct device *dev, u8 ctrl; int val; - lis3lv02d_increase_use(&adev); - adev.read(adev.device->handle, CTRL_REG1, &ctrl); - lis3lv02d_decrease_use(&adev); + lis3lv02d_increase_use(&lis3_dev); + lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); + lis3lv02d_decrease_use(&lis3_dev); val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); } @@ -458,23 +444,73 @@ static struct attribute_group lis3lv02d_attribute_group = { }; -static int lis3lv02d_add_fs(struct acpi_device *device) +static int lis3lv02d_add_fs(struct lis3lv02d *lis3) { - adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); - if (IS_ERR(adev.pdev)) - return PTR_ERR(adev.pdev); + lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); + if (IS_ERR(lis3_dev.pdev)) + return PTR_ERR(lis3_dev.pdev); - return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); + return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); } int lis3lv02d_remove_fs(void) { - sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); - platform_device_unregister(adev.pdev); + sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); + platform_device_unregister(lis3_dev.pdev); return 0; } EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); +/* + * Initialise the accelerometer and the various subsystems. + * Should be rather independant of the bus system. + */ +int lis3lv02d_init_device(struct lis3lv02d *dev) +{ + dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); + + switch (dev->whoami) { + case LIS_DOUBLE_ID: + printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n"); + dev->read_data = lis3lv02d_read_16; + dev->mdps_max_val = 2048; + break; + case LIS_SINGLE_ID: + printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n"); + dev->read_data = lis3lv02d_read_8; + dev->mdps_max_val = 128; + break; + default: + printk(KERN_ERR DRIVER_NAME + ": unknown sensor type 0x%X\n", lis3_dev.whoami); + return -EINVAL; + } + + mutex_init(&dev->lock); + lis3lv02d_add_fs(dev); + lis3lv02d_increase_use(dev); + + if (lis3lv02d_joystick_enable()) + printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); + + printk("lis3_init_device: irq %d\n", dev->irq); + + /* bail if we did not get an IRQ from the bus layer */ + if (!dev->irq) { + printk(KERN_ERR DRIVER_NAME + ": No IRQ. Disabling /dev/freefall\n"); + goto out; + } + + printk("lis3: registering device\n"); + if (misc_register(&lis3lv02d_misc_device)) + printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); +out: + lis3lv02d_decrease_use(dev); + return 0; +} +EXPORT_SYMBOL_GPL(lis3lv02d_init_device); + MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/hwmon/lis3lv02d.h b/trunk/drivers/hwmon/lis3lv02d.h index 75972bf372ff..745ec96806d4 100644 --- a/trunk/drivers/hwmon/lis3lv02d.h +++ b/trunk/drivers/hwmon/lis3lv02d.h @@ -159,14 +159,14 @@ struct axis_conversion { s8 z; }; -struct acpi_lis3lv02d { - struct acpi_device *device; /* The ACPI device */ - acpi_status (*init) (acpi_handle handle); - acpi_status (*write) (acpi_handle handle, int reg, u8 val); - acpi_status (*read) (acpi_handle handle, int reg, u8 *ret); +struct lis3lv02d { + void *bus_priv; /* used by the bus layer only */ + int (*init) (struct lis3lv02d *lis3); + int (*write) (struct lis3lv02d *lis3, int reg, u8 val); + int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret); u8 whoami; /* 3Ah: 2-byte registries, 3Bh: 1-byte registries */ - s16 (*read_data) (acpi_handle handle, int reg); + s16 (*read_data) (struct lis3lv02d *lis3, int reg); int mdps_max_val; struct input_dev *idev; /* input device */ @@ -187,11 +187,11 @@ struct acpi_lis3lv02d { unsigned long misc_opened; /* bit0: whether the device is open */ }; -int lis3lv02d_init_device(struct acpi_lis3lv02d *dev); +int lis3lv02d_init_device(struct lis3lv02d *lis3); int lis3lv02d_joystick_enable(void); void lis3lv02d_joystick_disable(void); -void lis3lv02d_poweroff(acpi_handle handle); -void lis3lv02d_poweron(acpi_handle handle); +void lis3lv02d_poweroff(struct lis3lv02d *lis3); +void lis3lv02d_poweron(struct lis3lv02d *lis3); int lis3lv02d_remove_fs(void); -extern struct acpi_lis3lv02d adev; +extern struct lis3lv02d lis3_dev; diff --git a/trunk/drivers/hwmon/lis3lv02d_spi.c b/trunk/drivers/hwmon/lis3lv02d_spi.c new file mode 100644 index 000000000000..07ae74b0e191 --- /dev/null +++ b/trunk/drivers/hwmon/lis3lv02d_spi.c @@ -0,0 +1,114 @@ +/* + * lis3lv02d_spi - SPI glue layer for lis3lv02d + * + * Copyright (c) 2009 Daniel Mack + * + * 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 + * publishhed by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lis3lv02d.h" + +#define DRV_NAME "lis3lv02d_spi" +#define LIS3_SPI_READ 0x80 + +static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) +{ + struct spi_device *spi = lis3->bus_priv; + int ret = spi_w8r8(spi, reg | LIS3_SPI_READ); + if (ret < 0) + return -EINVAL; + + *v = (u8) ret; + return 0; +} + +static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) +{ + u8 tmp[2] = { reg, val }; + struct spi_device *spi = lis3->bus_priv; + return spi_write(spi, tmp, sizeof(tmp)); +} + +static int lis3_spi_init(struct lis3lv02d *lis3) +{ + u8 reg; + int ret; + + /* power up the device */ + ret = lis3->read(lis3, CTRL_REG1, ®); + if (ret < 0) + return ret; + + reg |= CTRL1_PD0; + return lis3->write(lis3, CTRL_REG1, reg); +} + +static struct axis_conversion lis3lv02d_axis_normal = { 1, 2, 3 }; + +static int __devinit lis302dl_spi_probe(struct spi_device *spi) +{ + int ret; + + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + ret = spi_setup(spi); + if (ret < 0) + return ret; + + lis3_dev.bus_priv = spi; + lis3_dev.init = lis3_spi_init; + lis3_dev.read = lis3_spi_read; + lis3_dev.write = lis3_spi_write; + lis3_dev.irq = spi->irq; + lis3_dev.ac = lis3lv02d_axis_normal; + spi_set_drvdata(spi, &lis3_dev); + + ret = lis3lv02d_init_device(&lis3_dev); + return ret; +} + +static int __devexit lis302dl_spi_remove(struct spi_device *spi) +{ + struct lis3lv02d *lis3 = spi_get_drvdata(spi); + lis3lv02d_joystick_disable(); + lis3lv02d_poweroff(lis3); + return 0; +} + +static struct spi_driver lis302dl_spi_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = lis302dl_spi_probe, + .remove = __devexit_p(lis302dl_spi_remove), +}; + +static int __init lis302dl_init(void) +{ + return spi_register_driver(&lis302dl_spi_driver); +} + +static void __exit lis302dl_exit(void) +{ + spi_unregister_driver(&lis302dl_spi_driver); +} + +module_init(lis302dl_init); +module_exit(lis302dl_exit); + +MODULE_AUTHOR("Daniel Mack "); +MODULE_DESCRIPTION("lis3lv02d SPI glue layer"); +MODULE_LICENSE("GPL"); + diff --git a/trunk/drivers/hwmon/lm95241.c b/trunk/drivers/hwmon/lm95241.c new file mode 100644 index 000000000000..091d95f38aaa --- /dev/null +++ b/trunk/drivers/hwmon/lm95241.c @@ -0,0 +1,527 @@ +/* + * lm95241.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2008 Davide Rizzo + * + * Based on the max1619 driver. The LM95241 is a sensor chip made by National + * Semiconductors. + * It reports up to three temperatures (its own plus up to + * two external ones). Complete datasheet can be + * obtained from National's website at: + * http://www.national.com/ds.cgi/LM/LM95241.pdf + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const unsigned short normal_i2c[] = { + 0x19, 0x2a, 0x2b, I2C_CLIENT_END}; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(lm95241); + +/* LM95241 registers */ +#define LM95241_REG_R_MAN_ID 0xFE +#define LM95241_REG_R_CHIP_ID 0xFF +#define LM95241_REG_R_STATUS 0x02 +#define LM95241_REG_RW_CONFIG 0x03 +#define LM95241_REG_RW_REM_FILTER 0x06 +#define LM95241_REG_RW_TRUTHERM 0x07 +#define LM95241_REG_W_ONE_SHOT 0x0F +#define LM95241_REG_R_LOCAL_TEMPH 0x10 +#define LM95241_REG_R_REMOTE1_TEMPH 0x11 +#define LM95241_REG_R_REMOTE2_TEMPH 0x12 +#define LM95241_REG_R_LOCAL_TEMPL 0x20 +#define LM95241_REG_R_REMOTE1_TEMPL 0x21 +#define LM95241_REG_R_REMOTE2_TEMPL 0x22 +#define LM95241_REG_RW_REMOTE_MODEL 0x30 + +/* LM95241 specific bitfields */ +#define CFG_STOP 0x40 +#define CFG_CR0076 0x00 +#define CFG_CR0182 0x10 +#define CFG_CR1000 0x20 +#define CFG_CR2700 0x30 +#define R1MS_SHIFT 0 +#define R2MS_SHIFT 2 +#define R1MS_MASK (0x01 << (R1MS_SHIFT)) +#define R2MS_MASK (0x01 << (R2MS_SHIFT)) +#define R1DF_SHIFT 1 +#define R2DF_SHIFT 2 +#define R1DF_MASK (0x01 << (R1DF_SHIFT)) +#define R2DF_MASK (0x01 << (R2DF_SHIFT)) +#define R1FE_MASK 0x01 +#define R2FE_MASK 0x05 +#define TT1_SHIFT 0 +#define TT2_SHIFT 4 +#define TT_OFF 0 +#define TT_ON 1 +#define TT_MASK 7 +#define MANUFACTURER_ID 0x01 +#define DEFAULT_REVISION 0xA4 + +/* Conversions and various macros */ +#define TEMP_FROM_REG(val_h, val_l) (((val_h) & 0x80 ? (val_h) - 0x100 : \ + (val_h)) * 1000 + (val_l) * 1000 / 256) + +/* Functions declaration */ +static int lm95241_attach_adapter(struct i2c_adapter *adapter); +static int lm95241_detect(struct i2c_adapter *adapter, int address, + int kind); +static void lm95241_init_client(struct i2c_client *client); +static int lm95241_detach_client(struct i2c_client *client); +static struct lm95241_data *lm95241_update_device(struct device *dev); + +/* Driver data (common to all clients) */ +static struct i2c_driver lm95241_driver = { + .driver = { + .name = "lm95241", + }, + .attach_adapter = lm95241_attach_adapter, + .detach_client = lm95241_detach_client, +}; + +/* Client data (each client gets its own) */ +struct lm95241_data { + struct i2c_client client; + struct device *hwmon_dev; + struct mutex update_lock; + unsigned long last_updated, rate; /* in jiffies */ + char valid; /* zero until following fields are valid */ + /* registers values */ + u8 local_h, local_l; /* local */ + u8 remote1_h, remote1_l; /* remote1 */ + u8 remote2_h, remote2_l; /* remote2 */ + u8 config, model, trutherm; +}; + +/* Sysfs stuff */ +#define show_temp(value) \ +static ssize_t show_##value(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct lm95241_data *data = lm95241_update_device(dev); \ + snprintf(buf, PAGE_SIZE - 1, "%d\n", \ + TEMP_FROM_REG(data->value##_h, data->value##_l)); \ + return strlen(buf); \ +} +show_temp(local); +show_temp(remote1); +show_temp(remote2); + +static ssize_t show_rate(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm95241_data *data = lm95241_update_device(dev); + + snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->rate / HZ); + return strlen(buf); +} + +static ssize_t set_rate(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); + + strict_strtol(buf, 10, &data->rate); + data->rate = data->rate * HZ / 1000; + + return count; +} + +#define show_type(flag) \ +static ssize_t show_type##flag(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm95241_data *data = i2c_get_clientdata(client); \ +\ + snprintf(buf, PAGE_SIZE - 1, \ + data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \ + return strlen(buf); \ +} +show_type(1); +show_type(2); + +#define show_min(flag) \ +static ssize_t show_min##flag(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm95241_data *data = i2c_get_clientdata(client); \ +\ + snprintf(buf, PAGE_SIZE - 1, \ + data->config & R##flag##DF_MASK ? \ + "-127000\n" : "0\n"); \ + return strlen(buf); \ +} +show_min(1); +show_min(2); + +#define show_max(flag) \ +static ssize_t show_max##flag(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm95241_data *data = i2c_get_clientdata(client); \ +\ + snprintf(buf, PAGE_SIZE - 1, \ + data->config & R##flag##DF_MASK ? \ + "127000\n" : "255000\n"); \ + return strlen(buf); \ +} +show_max(1); +show_max(2); + +#define set_type(flag) \ +static ssize_t set_type##flag(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm95241_data *data = i2c_get_clientdata(client); \ +\ + long val; \ + strict_strtol(buf, 10, &val); \ +\ + if ((val == 1) || (val == 2)) { \ +\ + mutex_lock(&data->update_lock); \ +\ + data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \ + if (val == 1) { \ + data->model |= R##flag##MS_MASK; \ + data->trutherm |= (TT_ON << TT##flag##_SHIFT); \ + } \ + else { \ + data->model &= ~R##flag##MS_MASK; \ + data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \ + } \ +\ + data->valid = 0; \ +\ + i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \ + data->model); \ + i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \ + data->trutherm); \ +\ + mutex_unlock(&data->update_lock); \ +\ + } \ + return count; \ +} +set_type(1); +set_type(2); + +#define set_min(flag) \ +static ssize_t set_min##flag(struct device *dev, \ + struct device_attribute *devattr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm95241_data *data = i2c_get_clientdata(client); \ +\ + long val; \ + strict_strtol(buf, 10, &val); \ +\ + mutex_lock(&data->update_lock); \ +\ + if (val < 0) \ + data->config |= R##flag##DF_MASK; \ + else \ + data->config &= ~R##flag##DF_MASK; \ +\ + data->valid = 0; \ +\ + i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ + data->config); \ +\ + mutex_unlock(&data->update_lock); \ +\ + return count; \ +} +set_min(1); +set_min(2); + +#define set_max(flag) \ +static ssize_t set_max##flag(struct device *dev, \ + struct device_attribute *devattr, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm95241_data *data = i2c_get_clientdata(client); \ +\ + long val; \ + strict_strtol(buf, 10, &val); \ +\ + mutex_lock(&data->update_lock); \ +\ + if (val <= 127000) \ + data->config |= R##flag##DF_MASK; \ + else \ + data->config &= ~R##flag##DF_MASK; \ +\ + data->valid = 0; \ +\ + i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ + data->config); \ +\ + mutex_unlock(&data->update_lock); \ +\ + return count; \ +} +set_max(1); +set_max(2); + +static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL); +static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL); +static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL); +static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1); +static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2); +static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1); +static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2); +static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1); +static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2); +static DEVICE_ATTR(rate, S_IWUSR | S_IRUGO, show_rate, set_rate); + +static struct attribute *lm95241_attributes[] = { + &dev_attr_temp1_input.attr, + &dev_attr_temp2_input.attr, + &dev_attr_temp3_input.attr, + &dev_attr_temp2_type.attr, + &dev_attr_temp3_type.attr, + &dev_attr_temp2_min.attr, + &dev_attr_temp3_min.attr, + &dev_attr_temp2_max.attr, + &dev_attr_temp3_max.attr, + &dev_attr_rate.attr, + NULL +}; + +static const struct attribute_group lm95241_group = { + .attrs = lm95241_attributes, +}; + +/* Init/exit code */ +static int lm95241_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, lm95241_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int lm95241_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct lm95241_data *data; + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + /* The common I2C client data is placed right before the + LM95241-specific data. */ + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &lm95241_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + if (kind < 0) { /* detection */ + if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID) + != MANUFACTURER_ID) + || (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) + < DEFAULT_REVISION)) { + dev_dbg(&adapter->dev, + "LM95241 detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID) + == MANUFACTURER_ID) + && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) + >= DEFAULT_REVISION)) { + + kind = lm95241; + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, "Unsupported chip\n"); + goto exit_free; + } + } + } + + if (kind == lm95241) + name = "lm95241"; + + /* We can fill in the remaining client fields */ + strlcpy(new_client->name, name, I2C_NAME_SIZE); + data->valid = 0; + mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + err = i2c_attach_client(new_client); + if (err) + goto exit_free; + + /* Initialize the LM95241 chip */ + lm95241_init_client(new_client); + + /* Register sysfs hooks */ + err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group); + if (err) + goto exit_detach; + + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove_files; + } + + return 0; + +exit_remove_files: + sysfs_remove_group(&new_client->dev.kobj, &lm95241_group); +exit_detach: + i2c_detach_client(new_client); +exit_free: + kfree(data); +exit: + return err; +} + +static void lm95241_init_client(struct i2c_client *client) +{ + struct lm95241_data *data = i2c_get_clientdata(client); + + data->rate = HZ; /* 1 sec default */ + data->valid = 0; + data->config = CFG_CR0076; + data->model = 0; + data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT); + + i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, + data->config); + i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER, + R1FE_MASK | R2FE_MASK); + i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, + data->trutherm); + i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, + data->model); +} + +static int lm95241_detach_client(struct i2c_client *client) +{ + struct lm95241_data *data = i2c_get_clientdata(client); + int err; + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &lm95241_group); + + err = i2c_detach_client(client); + if (err) + return err; + + kfree(data); + return 0; +} + +static struct lm95241_data *lm95241_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct lm95241_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + data->rate) || + !data->valid) { + dev_dbg(&client->dev, "Updating lm95241 data.\n"); + data->local_h = + i2c_smbus_read_byte_data(client, + LM95241_REG_R_LOCAL_TEMPH); + data->local_l = + i2c_smbus_read_byte_data(client, + LM95241_REG_R_LOCAL_TEMPL); + data->remote1_h = + i2c_smbus_read_byte_data(client, + LM95241_REG_R_REMOTE1_TEMPH); + data->remote1_l = + i2c_smbus_read_byte_data(client, + LM95241_REG_R_REMOTE1_TEMPL); + data->remote2_h = + i2c_smbus_read_byte_data(client, + LM95241_REG_R_REMOTE2_TEMPH); + data->remote2_l = + i2c_smbus_read_byte_data(client, + LM95241_REG_R_REMOTE2_TEMPL); + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init sensors_lm95241_init(void) +{ + return i2c_add_driver(&lm95241_driver); +} + +static void __exit sensors_lm95241_exit(void) +{ + i2c_del_driver(&lm95241_driver); +} + +MODULE_AUTHOR("Davide Rizzo "); +MODULE_DESCRIPTION("LM95241 sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_lm95241_init); +module_exit(sensors_lm95241_exit); diff --git a/trunk/drivers/hwmon/ltc4215.c b/trunk/drivers/hwmon/ltc4215.c new file mode 100644 index 000000000000..9386e2a39211 --- /dev/null +++ b/trunk/drivers/hwmon/ltc4215.c @@ -0,0 +1,364 @@ +/* + * Driver for Linear Technology LTC4215 I2C Hot Swap Controller + * + * Copyright (C) 2009 Ira W. Snyder + * + * 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 of the License. + * + * Datasheet: + * http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1163,P17572,D12697 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(ltc4215); + +/* Here are names of the chip's registers (a.k.a. commands) */ +enum ltc4215_cmd { + LTC4215_CONTROL = 0x00, /* rw */ + LTC4215_ALERT = 0x01, /* rw */ + LTC4215_STATUS = 0x02, /* ro */ + LTC4215_FAULT = 0x03, /* rw */ + LTC4215_SENSE = 0x04, /* rw */ + LTC4215_SOURCE = 0x05, /* rw */ + LTC4215_ADIN = 0x06, /* rw */ +}; + +struct ltc4215_data { + struct device *hwmon_dev; + + struct mutex update_lock; + bool valid; + unsigned long last_updated; /* in jiffies */ + + /* Registers */ + u8 regs[7]; +}; + +static struct ltc4215_data *ltc4215_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ltc4215_data *data = i2c_get_clientdata(client); + s32 val; + int i; + + mutex_lock(&data->update_lock); + + /* The chip's A/D updates 10 times per second */ + if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) { + + dev_dbg(&client->dev, "Starting ltc4215 update\n"); + + /* Read all registers */ + for (i = 0; i < ARRAY_SIZE(data->regs); i++) { + val = i2c_smbus_read_byte_data(client, i); + if (unlikely(val < 0)) + data->regs[i] = 0; + else + data->regs[i] = val; + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* Return the voltage from the given register in millivolts */ +static int ltc4215_get_voltage(struct device *dev, u8 reg) +{ + struct ltc4215_data *data = ltc4215_update_device(dev); + const u8 regval = data->regs[reg]; + u32 voltage = 0; + + switch (reg) { + case LTC4215_SENSE: + /* 151 uV per increment */ + voltage = regval * 151 / 1000; + break; + case LTC4215_SOURCE: + /* 60.5 mV per increment */ + voltage = regval * 605 / 10; + break; + case LTC4215_ADIN: + /* The ADIN input is divided by 12.5, and has 4.82 mV + * per increment, so we have the additional multiply */ + voltage = regval * 482 * 125 / 1000; + break; + default: + /* If we get here, the developer messed up */ + WARN_ON_ONCE(1); + break; + } + + return voltage; +} + +/* Return the current from the sense resistor in mA */ +static unsigned int ltc4215_get_current(struct device *dev) +{ + struct ltc4215_data *data = ltc4215_update_device(dev); + + /* The strange looking conversions that follow are fixed-point + * math, since we cannot do floating point in the kernel. + * + * Step 1: convert sense register to microVolts + * Step 2: convert voltage to milliAmperes + * + * If you play around with the V=IR equation, you come up with + * the following: X uV / Y mOhm == Z mA + * + * With the resistors that are fractions of a milliOhm, we multiply + * the voltage and resistance by 10, to shift the decimal point. + * Now we can use the normal division operator again. + */ + + /* Calculate voltage in microVolts (151 uV per increment) */ + const unsigned int voltage = data->regs[LTC4215_SENSE] * 151; + + /* Calculate current in milliAmperes (4 milliOhm sense resistor) */ + const unsigned int curr = voltage / 4; + + return curr; +} + +static ssize_t ltc4215_show_voltage(struct device *dev, + struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + const int voltage = ltc4215_get_voltage(dev, attr->index); + + return snprintf(buf, PAGE_SIZE, "%d\n", voltage); +} + +static ssize_t ltc4215_show_current(struct device *dev, + struct device_attribute *da, + char *buf) +{ + const unsigned int curr = ltc4215_get_current(dev); + + return snprintf(buf, PAGE_SIZE, "%u\n", curr); +} + +static ssize_t ltc4215_show_power(struct device *dev, + struct device_attribute *da, + char *buf) +{ + const unsigned int curr = ltc4215_get_current(dev); + const int output_voltage = ltc4215_get_voltage(dev, LTC4215_ADIN); + + /* current in mA * voltage in mV == power in uW */ + const unsigned int power = abs(output_voltage * curr); + + return snprintf(buf, PAGE_SIZE, "%u\n", power); +} + +static ssize_t ltc4215_show_alarm(struct device *dev, + struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da); + struct ltc4215_data *data = ltc4215_update_device(dev); + const u8 reg = data->regs[attr->index]; + const u32 mask = attr->nr; + + return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0); +} + +/* These macros are used below in constructing device attribute objects + * for use with sysfs_create_group() to make a sysfs device file + * for each register. + */ + +#define LTC4215_VOLTAGE(name, ltc4215_cmd_idx) \ + static SENSOR_DEVICE_ATTR(name, S_IRUGO, \ + ltc4215_show_voltage, NULL, ltc4215_cmd_idx) + +#define LTC4215_CURRENT(name) \ + static SENSOR_DEVICE_ATTR(name, S_IRUGO, \ + ltc4215_show_current, NULL, 0); + +#define LTC4215_POWER(name) \ + static SENSOR_DEVICE_ATTR(name, S_IRUGO, \ + ltc4215_show_power, NULL, 0); + +#define LTC4215_ALARM(name, mask, reg) \ + static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \ + ltc4215_show_alarm, NULL, (mask), reg) + +/* Construct a sensor_device_attribute structure for each register */ + +/* Current */ +LTC4215_CURRENT(curr1_input); +LTC4215_ALARM(curr1_max_alarm, (1 << 2), LTC4215_STATUS); + +/* Power (virtual) */ +LTC4215_POWER(power1_input); +LTC4215_ALARM(power1_alarm, (1 << 3), LTC4215_STATUS); + +/* Input Voltage */ +LTC4215_VOLTAGE(in1_input, LTC4215_ADIN); +LTC4215_ALARM(in1_max_alarm, (1 << 0), LTC4215_STATUS); +LTC4215_ALARM(in1_min_alarm, (1 << 1), LTC4215_STATUS); + +/* Output Voltage */ +LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE); + +/* Finally, construct an array of pointers to members of the above objects, + * as required for sysfs_create_group() + */ +static struct attribute *ltc4215_attributes[] = { + &sensor_dev_attr_curr1_input.dev_attr.attr, + &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, + + NULL, +}; + +static const struct attribute_group ltc4215_group = { + .attrs = ltc4215_attributes, +}; + +static int ltc4215_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ltc4215_data *data; + int ret; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto out_kzalloc; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + /* Initialize the LTC4215 chip */ + /* TODO */ + + /* Register sysfs hooks */ + ret = sysfs_create_group(&client->dev.kobj, <c4215_group); + if (ret) + goto out_sysfs_create_group; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + ret = PTR_ERR(data->hwmon_dev); + goto out_hwmon_device_register; + } + + return 0; + +out_hwmon_device_register: + sysfs_remove_group(&client->dev.kobj, <c4215_group); +out_sysfs_create_group: + kfree(data); +out_kzalloc: + return ret; +} + +static int ltc4215_remove(struct i2c_client *client) +{ + struct ltc4215_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, <c4215_group); + + kfree(data); + + return 0; +} + +static int ltc4215_detect(struct i2c_client *client, + int kind, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + if (kind < 0) { /* probed detection - check the chip type */ + s32 v; /* 8 bits from the chip, or -ERRNO */ + + /* + * Register 0x01 bit b7 is reserved, expect 0 + * Register 0x03 bit b6 and b7 are reserved, expect 0 + */ + v = i2c_smbus_read_byte_data(client, LTC4215_ALERT); + if (v < 0 || (v & (1 << 7)) != 0) + return -ENODEV; + + v = i2c_smbus_read_byte_data(client, LTC4215_FAULT); + if (v < 0 || (v & ((1 << 6) | (1 << 7))) != 0) + return -ENODEV; + } + + strlcpy(info->type, "ltc4215", I2C_NAME_SIZE); + dev_info(&adapter->dev, "ltc4215 %s at address 0x%02x\n", + kind < 0 ? "probed" : "forced", + client->addr); + + return 0; +} + +static const struct i2c_device_id ltc4215_id[] = { + { "ltc4215", ltc4215 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ltc4215_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver ltc4215_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ltc4215", + }, + .probe = ltc4215_probe, + .remove = ltc4215_remove, + .id_table = ltc4215_id, + .detect = ltc4215_detect, + .address_data = &addr_data, +}; + +static int __init ltc4215_init(void) +{ + return i2c_add_driver(<c4215_driver); +} + +static void __exit ltc4215_exit(void) +{ + i2c_del_driver(<c4215_driver); +} + +MODULE_AUTHOR("Ira W. Snyder "); +MODULE_DESCRIPTION("LTC4215 driver"); +MODULE_LICENSE("GPL"); + +module_init(ltc4215_init); +module_exit(ltc4215_exit); diff --git a/trunk/drivers/ide/Kconfig b/trunk/drivers/ide/Kconfig index 640c99207242..cf06494bb744 100644 --- a/trunk/drivers/ide/Kconfig +++ b/trunk/drivers/ide/Kconfig @@ -222,7 +222,8 @@ comment "IDE chipset support/bugfixes" config IDE_GENERIC tristate "generic/default IDE chipset support" - depends on ALPHA || X86 || IA64 || M32R || MIPS + depends on ALPHA || X86 || IA64 || M32R || MIPS || ARCH_RPC || ARCH_SHARK + default ARM && (ARCH_RPC || ARCH_SHARK) help This is the generic IDE driver. This driver attaches to the fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and @@ -680,7 +681,7 @@ endif # TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF config BLK_DEV_IDE_PMAC tristate "PowerMac on-board IDE support" - depends on PPC_PMAC && IDE=y + depends on PPC_PMAC select IDE_TIMINGS select BLK_DEV_IDEDMA_PCI help @@ -731,11 +732,6 @@ config BLK_DEV_IDE_AT91 depends on ARM && ARCH_AT91 && !ARCH_AT91RM9200 && !ARCH_AT91X40 select IDE_TIMINGS -config IDE_ARM - tristate "ARM IDE support" - depends on ARM && (ARCH_RPC || ARCH_SHARK) - default y - config BLK_DEV_IDE_ICSIDE tristate "ICS IDE interface support" depends on ARM && ARCH_ACORN @@ -774,27 +770,20 @@ config BLK_DEV_GAYLE This includes on-board IDE interfaces on some Amiga models (A600, A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion bus (M-Tech E-Matrix 530 expansion card). - Say Y if you have an Amiga with a Gayle IDE interface and want to use - IDE devices (hard disks, CD-ROM drives, etc.) that are connected to - it. - Note that you also have to enable Zorro bus support if you want to - use Gayle IDE interfaces on the Zorro expansion bus. -config BLK_DEV_IDEDOUBLER - bool "Amiga IDE Doubler support (EXPERIMENTAL)" - depends on BLK_DEV_GAYLE && EXPERIMENTAL - ---help--- - This feature provides support for the so-called `IDE doublers' (made + It also provides support for the so-called `IDE doublers' (made by various manufacturers, e.g. Eyetech) that can be connected to the on-board IDE interface of some Amiga models. Using such an IDE doubler, you can connect up to four instead of two IDE devices to - the Amiga's on-board IDE interface. + the Amiga's on-board IDE interface. The feature is enabled at kernel + runtime using the "gayle.doubler" kernel boot parameter. - Note that the normal Amiga Gayle IDE driver may not work correctly - if you have an IDE doubler and don't enable this feature! + Say Y if you have an Amiga with a Gayle IDE interface and want to use + IDE devices (hard disks, CD-ROM drives, etc.) that are connected to + it. - Say Y if you have an IDE doubler. The feature is enabled at kernel - runtime using the "gayle.doubler" kernel boot parameter. + Note that you also have to enable Zorro bus support if you want to + use Gayle IDE interfaces on the Zorro expansion bus. config BLK_DEV_BUDDHA tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)" diff --git a/trunk/drivers/ide/Makefile b/trunk/drivers/ide/Makefile index 9b4bbe1cdc1a..81df925f0e8b 100644 --- a/trunk/drivers/ide/Makefile +++ b/trunk/drivers/ide/Makefile @@ -21,8 +21,6 @@ ide-core-$(CONFIG_IDE_LEGACY) += ide-legacy.o obj-$(CONFIG_IDE) += ide-core.o -obj-$(CONFIG_IDE_ARM) += ide_arm.o - obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o diff --git a/trunk/drivers/ide/alim15x3.c b/trunk/drivers/ide/alim15x3.c index d516168464fc..537da1cde16d 100644 --- a/trunk/drivers/ide/alim15x3.c +++ b/trunk/drivers/ide/alim15x3.c @@ -189,20 +189,20 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed) } /** - * ali15x3_dma_setup - begin a DMA phase + * ali_dma_check - DMA check * @drive: target device * @cmd: command * * Returns 1 if the DMA cannot be performed, zero on success. */ -static int ali15x3_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) +static int ali_dma_check(ide_drive_t *drive, struct ide_cmd *cmd) { if (m5229_revision < 0xC2 && drive->media != ide_disk) { if (cmd->tf_flags & IDE_TFLAG_WRITE) return 1; /* try PIO instead of DMA */ } - return ide_dma_setup(drive, cmd); + return 0; } /** @@ -503,13 +503,13 @@ static const struct ide_port_ops ali_port_ops = { static const struct ide_dma_ops ali_dma_ops = { .dma_host_set = ide_dma_host_set, - .dma_setup = ali15x3_dma_setup, + .dma_setup = ide_dma_setup, .dma_start = ide_dma_start, .dma_end = ide_dma_end, .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, + .dma_check = ali_dma_check, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/at91_ide.c b/trunk/drivers/ide/at91_ide.c index 27547121daff..8eda552326e9 100644 --- a/trunk/drivers/ide/at91_ide.c +++ b/trunk/drivers/ide/at91_ide.c @@ -192,15 +192,9 @@ static void at91_ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd) struct ide_taskfile *tf = &cmd->tf; u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; - if (cmd->tf_flags & IDE_FTFLAG_FLAGGED) + if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED) HIHI = 0xFF; - if (cmd->tf_flags & IDE_FTFLAG_OUT_DATA) { - u16 data = (tf->hob_data << 8) | tf->data; - - at91_ide_output_data(drive, NULL, &data, 2); - } - if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) ide_mm_outb(tf->hob_feature, io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) @@ -233,19 +227,11 @@ static void at91_ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) struct ide_io_ports *io_ports = &hwif->io_ports; struct ide_taskfile *tf = &cmd->tf; - if (cmd->tf_flags & IDE_FTFLAG_IN_DATA) { - u16 data; - - at91_ide_input_data(drive, NULL, &data, 2); - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - /* be sure we're looking at the low order bits */ - ide_mm_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); + ide_mm_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE) - tf->feature = ide_mm_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_ERROR) + tf->error = ide_mm_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_NSECT) tf->nsect = ide_mm_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_LBAL) @@ -258,18 +244,18 @@ static void at91_ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) tf->device = ide_mm_inb(io_ports->device_addr); if (cmd->tf_flags & IDE_TFLAG_LBA48) { - ide_mm_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); + ide_mm_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = ide_mm_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR) + tf->hob_error = ide_mm_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = ide_mm_inb(io_ports->nsect_addr); + tf->hob_nsect = ide_mm_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = ide_mm_inb(io_ports->lbal_addr); + tf->hob_lbal = ide_mm_inb(io_ports->lbal_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = ide_mm_inb(io_ports->lbam_addr); + tf->hob_lbam = ide_mm_inb(io_ports->lbam_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = ide_mm_inb(io_ports->lbah_addr); + tf->hob_lbah = ide_mm_inb(io_ports->lbah_addr); } } @@ -295,8 +281,9 @@ static const struct ide_tp_ops at91_ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, - .set_irq = ide_set_irq, + .write_devctl = ide_write_devctl, + .dev_select = ide_dev_select, .tf_load = at91_ide_tf_load, .tf_read = at91_ide_tf_read, diff --git a/trunk/drivers/ide/au1xxx-ide.c b/trunk/drivers/ide/au1xxx-ide.c index d3a9d6c15328..46013644c965 100644 --- a/trunk/drivers/ide/au1xxx-ide.c +++ b/trunk/drivers/ide/au1xxx-ide.c @@ -50,7 +50,7 @@ static _auide_hwif auide_hwif; #if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA) -void auide_insw(unsigned long port, void *addr, u32 count) +static inline void auide_insw(unsigned long port, void *addr, u32 count) { _auide_hwif *ahwif = &auide_hwif; chan_tab_t *ctp; @@ -68,7 +68,7 @@ void auide_insw(unsigned long port, void *addr, u32 count) ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp); } -void auide_outsw(unsigned long port, void *addr, u32 count) +static inline void auide_outsw(unsigned long port, void *addr, u32 count) { _auide_hwif *ahwif = &auide_hwif; chan_tab_t *ctp; @@ -236,7 +236,7 @@ static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) if (++count >= PRD_ENTRIES) { printk(KERN_WARNING "%s: DMA table too small\n", drive->name); - goto use_pio_instead; + return 0; } /* Lets enable intr for the last descriptor only */ @@ -272,16 +272,11 @@ static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) if (count) return 1; - use_pio_instead: - ide_destroy_dmatable(drive); - return 0; /* revert to PIO for this request */ } static int auide_dma_end(ide_drive_t *drive) { - ide_destroy_dmatable(drive); - return 0; } @@ -292,12 +287,9 @@ static void auide_dma_start(ide_drive_t *drive ) static int auide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) { - if (auide_build_dmatable(drive, cmd) == 0) { - ide_map_sg(drive, cmd); + if (auide_build_dmatable(drive, cmd) == 0) return 1; - } - drive->waiting_for_dma = 1; return 0; } @@ -322,16 +314,11 @@ static void auide_dma_host_set(ide_drive_t *drive, int on) static void auide_ddma_tx_callback(int irq, void *param) { - _auide_hwif *ahwif = (_auide_hwif*)param; - ahwif->drive->waiting_for_dma = 0; } static void auide_ddma_rx_callback(int irq, void *param) { - _auide_hwif *ahwif = (_auide_hwif*)param; - ahwif->drive->waiting_for_dma = 0; } - #endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */ static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize, u32 devwidth, u32 flags) @@ -353,7 +340,6 @@ static const struct ide_dma_ops au1xxx_dma_ops = { .dma_end = auide_dma_end, .dma_test_irq = auide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, - .dma_timeout = ide_dma_timeout, }; static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d) @@ -481,9 +467,9 @@ static const struct ide_tp_ops au1xxx_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = ide_tf_load, .tf_read = ide_tf_read, diff --git a/trunk/drivers/ide/cmd64x.c b/trunk/drivers/ide/cmd64x.c index bf0e3f470824..80b777e4247b 100644 --- a/trunk/drivers/ide/cmd64x.c +++ b/trunk/drivers/ide/cmd64x.c @@ -318,7 +318,6 @@ static int cmd646_1_dma_end(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; u8 dma_stat = 0, dma_cmd = 0; - drive->waiting_for_dma = 0; /* get DMA status */ dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); /* read DMA command state */ @@ -327,8 +326,6 @@ static int cmd646_1_dma_end(ide_drive_t *drive) outb(dma_cmd & ~1, hwif->dma_base + ATA_DMA_CMD); /* clear the INTR & ERROR bits */ outb(dma_stat | 6, hwif->dma_base + ATA_DMA_STATUS); - /* and free any DMA resources */ - ide_destroy_dmatable(drive); /* verify good DMA status */ return (dma_stat & 7) != 4; } @@ -384,7 +381,6 @@ static const struct ide_dma_ops cmd64x_dma_ops = { .dma_test_irq = cmd64x_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; @@ -396,7 +392,6 @@ static const struct ide_dma_ops cmd646_rev1_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; @@ -408,7 +403,6 @@ static const struct ide_dma_ops cmd648_dma_ops = { .dma_test_irq = cmd648_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/cs5530.c b/trunk/drivers/ide/cs5530.c index 8e8b35a89901..40bf05eddf6e 100644 --- a/trunk/drivers/ide/cs5530.c +++ b/trunk/drivers/ide/cs5530.c @@ -92,8 +92,7 @@ static u8 cs5530_udma_filter(ide_drive_t *drive) if ((mateid[ATA_ID_FIELD_VALID] & 4) && (mateid[ATA_ID_UDMA_MODES] & 7)) goto out; - if ((mateid[ATA_ID_FIELD_VALID] & 2) && - (mateid[ATA_ID_MWDMA_MODES] & 7)) + if (mateid[ATA_ID_MWDMA_MODES] & 7) mask = 0; } out: diff --git a/trunk/drivers/ide/cs5536.c b/trunk/drivers/ide/cs5536.c index d5dcf4899607..353a35bbba63 100644 --- a/trunk/drivers/ide/cs5536.c +++ b/trunk/drivers/ide/cs5536.c @@ -236,7 +236,6 @@ static const struct ide_dma_ops cs5536_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, }; static const struct ide_port_info cs5536_info = { diff --git a/trunk/drivers/ide/falconide.c b/trunk/drivers/ide/falconide.c index b368a5effc3a..afa2af9a362b 100644 --- a/trunk/drivers/ide/falconide.c +++ b/trunk/drivers/ide/falconide.c @@ -89,9 +89,9 @@ static const struct ide_tp_ops falconide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = ide_tf_load, .tf_read = ide_tf_read, diff --git a/trunk/drivers/ide/gayle.c b/trunk/drivers/ide/gayle.c index dc778251cb05..c7119516c5a7 100644 --- a/trunk/drivers/ide/gayle.c +++ b/trunk/drivers/ide/gayle.c @@ -53,11 +53,6 @@ #define GAYLE_NEXT_PORT 0x1000 -#ifndef CONFIG_BLK_DEV_IDEDOUBLER -#define GAYLE_NUM_HWIFS 1 -#define GAYLE_NUM_PROBE_HWIFS GAYLE_NUM_HWIFS -#define GAYLE_HAS_CONTROL_REG 1 -#else /* CONFIG_BLK_DEV_IDEDOUBLER */ #define GAYLE_NUM_HWIFS 2 #define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \ GAYLE_NUM_HWIFS-1) @@ -66,8 +61,6 @@ static int ide_doubler; module_param_named(doubler, ide_doubler, bool, 0); MODULE_PARM_DESC(doubler, "enable support for IDE doublers"); -#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ - /* * Check and acknowledge the interrupt status @@ -151,10 +144,7 @@ static int __init gayle_init(void) found: printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n", a4000 ? 4000 : 1200, -#ifdef CONFIG_BLK_DEV_IDEDOUBLER - ide_doubler ? ", IDE doubler" : -#endif - ""); + ide_doubler ? ", IDE doubler" : ""); if (a4000) { phys_base = GAYLE_BASE_4000; diff --git a/trunk/drivers/ide/hpt366.c b/trunk/drivers/ide/hpt366.c index dbaf184ed9c5..a0eb87f59134 100644 --- a/trunk/drivers/ide/hpt366.c +++ b/trunk/drivers/ide/hpt366.c @@ -835,12 +835,6 @@ static int hpt370_dma_end(ide_drive_t *drive) return ide_dma_end(drive); } -static void hpt370_dma_timeout(ide_drive_t *drive) -{ - hpt370_irq_timeout(drive); - ide_dma_timeout(drive); -} - /* returns 1 if DMA IRQ issued, 0 otherwise */ static int hpt374_dma_test_irq(ide_drive_t *drive) { @@ -1423,7 +1417,6 @@ static const struct ide_dma_ops hpt37x_dma_ops = { .dma_test_irq = hpt374_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; @@ -1435,7 +1428,7 @@ static const struct ide_dma_ops hpt370_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = hpt370_dma_timeout, + .dma_clear = hpt370_irq_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; @@ -1447,7 +1440,6 @@ static const struct ide_dma_ops hpt36x_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = hpt366_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/ht6560b.c b/trunk/drivers/ide/ht6560b.c index c7e5c2246b79..2fb0f2965009 100644 --- a/trunk/drivers/ide/ht6560b.c +++ b/trunk/drivers/ide/ht6560b.c @@ -103,7 +103,7 @@ /* * This routine is invoked from ide.c to prepare for access to a given drive. */ -static void ht6560b_selectproc (ide_drive_t *drive) +static void ht6560b_dev_select(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; unsigned long flags; @@ -143,6 +143,8 @@ static void ht6560b_selectproc (ide_drive_t *drive) #endif } local_irq_restore(flags); + + outb(drive->select | ATA_DEVICE_OBS, hwif->io_ports.device_addr); } /* @@ -305,15 +307,29 @@ static int probe_ht6560b; module_param_named(probe, probe_ht6560b, bool, 0); MODULE_PARM_DESC(probe, "probe for HT6560B chipset"); +static const struct ide_tp_ops ht6560b_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ht6560b_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + static const struct ide_port_ops ht6560b_port_ops = { .init_dev = ht6560b_init_dev, .set_pio_mode = ht6560b_set_pio_mode, - .selectproc = ht6560b_selectproc, }; static const struct ide_port_info ht6560b_port_info __initdata = { .name = DRV_NAME, .chipset = ide_ht6560b, + .tp_ops = &ht6560b_tp_ops, .port_ops = &ht6560b_port_ops, .host_flags = IDE_HFLAG_SERIALIZE | /* is this needed? */ IDE_HFLAG_NO_DMA | diff --git a/trunk/drivers/ide/icside.c b/trunk/drivers/ide/icside.c index 51ce404fe532..4e16ce68b063 100644 --- a/trunk/drivers/ide/icside.c +++ b/trunk/drivers/ide/icside.c @@ -287,13 +287,8 @@ static int icside_dma_end(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; struct expansion_card *ec = ECARD_DEV(hwif->dev); - drive->waiting_for_dma = 0; - disable_dma(ec->dma); - /* Teardown mappings after DMA has completed. */ - ide_destroy_dmatable(drive); - return get_dma_residue(ec->dma) != 0; } @@ -346,8 +341,6 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) set_dma_sg(ec->dma, hwif->sg_table, cmd->sg_nents); set_dma_mode(ec->dma, dma_mode); - drive->waiting_for_dma = 1; - return 0; } @@ -377,7 +370,6 @@ static const struct ide_dma_ops icside_v6_dma_ops = { .dma_start = icside_dma_start, .dma_end = icside_dma_end, .dma_test_irq = icside_dma_test_irq, - .dma_timeout = ide_dma_timeout, .dma_lost_irq = ide_dma_lost_irq, }; #else diff --git a/trunk/drivers/ide/ide-atapi.c b/trunk/drivers/ide/ide-atapi.c index 2fb5d28a9be5..3e43b889dd64 100644 --- a/trunk/drivers/ide/ide-atapi.c +++ b/trunk/drivers/ide/ide-atapi.c @@ -6,6 +6,8 @@ #include #include #include +#include + #include #ifdef DEBUG @@ -69,56 +71,6 @@ int ide_check_atapi_device(ide_drive_t *drive, const char *s) } EXPORT_SYMBOL_GPL(ide_check_atapi_device); -/* PIO data transfer routine using the scatter gather table. */ -int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, - unsigned int bcount, int write) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_tp_ops *tp_ops = hwif->tp_ops; - xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data; - struct scatterlist *sg = pc->sg; - char *buf; - int count, done = 0; - - while (bcount) { - count = min(sg->length - pc->b_count, bcount); - - if (PageHighMem(sg_page(sg))) { - unsigned long flags; - - local_irq_save(flags); - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - xf(drive, NULL, buf + pc->b_count, count); - kunmap_atomic(buf - sg->offset, KM_IRQ0); - local_irq_restore(flags); - } else { - buf = sg_virt(sg); - xf(drive, NULL, buf + pc->b_count, count); - } - - bcount -= count; - pc->b_count += count; - done += count; - - if (pc->b_count == sg->length) { - if (!--pc->sg_cnt) - break; - pc->sg = sg = sg_next(sg); - pc->b_count = 0; - } - } - - if (bcount) { - printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name, - bcount, write ? "padding with zeros" - : "discarding data"); - ide_pad_transfer(drive, write, bcount); - } - - return done; -} -EXPORT_SYMBOL_GPL(ide_io_buffers); - void ide_init_pc(struct ide_atapi_pc *pc) { memset(pc, 0, sizeof(*pc)); @@ -324,12 +276,14 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) { struct ide_atapi_pc *pc = drive->pc; ide_hwif_t *hwif = drive->hwif; + struct ide_cmd *cmd = &hwif->cmd; struct request *rq = hwif->rq; const struct ide_tp_ops *tp_ops = hwif->tp_ops; xfer_func_t *xferfunc; - unsigned int timeout, temp; + unsigned int timeout, done; u16 bcount; u8 stat, ireason, dsc = 0; + u8 write = !!(pc->flags & PC_FLAG_WRITING); debug_log("Enter %s - interrupt handler\n", __func__); @@ -340,8 +294,13 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) stat = tp_ops->read_status(hwif); if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { - if (hwif->dma_ops->dma_end(drive) || - (drive->media == ide_tape && (stat & ATA_ERR))) { + int rc; + + drive->waiting_for_dma = 0; + rc = hwif->dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); + + if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) { if (drive->media == ide_floppy) printk(KERN_ERR "%s: DMA %s error\n", drive->name, rq_data_dir(pc->rq) @@ -357,7 +316,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) /* No more interrupts */ if ((stat & ATA_DRQ) == 0) { - int uptodate; + int uptodate, error; + unsigned int done; debug_log("Packet command completed, %d bytes transferred\n", pc->xferred); @@ -404,16 +364,24 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if (blk_special_request(rq)) { rq->errors = 0; - ide_complete_rq(drive, 0, blk_rq_bytes(rq)); + done = blk_rq_bytes(rq); + error = 0; } else { + if (blk_fs_request(rq) == 0 && uptodate <= 0) { if (rq->errors == 0) rq->errors = -EIO; } - ide_complete_rq(drive, uptodate ? 0 : -EIO, - ide_rq_bytes(rq)); + + if (drive->media == ide_tape) + done = ide_rq_bytes(rq); /* FIXME */ + else + done = blk_rq_bytes(rq); + + error = uptodate ? 0 : -EIO; } + ide_complete_rq(drive, error, done); return ide_stopped; } @@ -433,8 +401,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) return ide_do_reset(drive); } - if (((ireason & ATAPI_IO) == ATAPI_IO) == - !!(pc->flags & PC_FLAG_WRITING)) { + if (((ireason & ATAPI_IO) == ATAPI_IO) == write) { /* Hopefully, we will never get here */ printk(KERN_ERR "%s: We wanted to %s, but the device wants us " "to %s!\n", drive->name, @@ -443,45 +410,30 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) return ide_do_reset(drive); } - if (!(pc->flags & PC_FLAG_WRITING)) { - /* Reading - Check that we have enough space */ - temp = pc->xferred + bcount; - if (temp > pc->req_xfer) { - if (temp > pc->buf_size) { - printk(KERN_ERR "%s: The device wants to send " - "us more data than expected - " - "discarding data\n", - drive->name); - - ide_pad_transfer(drive, 0, bcount); - goto next_irq; - } - debug_log("The device wants to send us more data than " - "expected - allowing transfer\n"); - } - xferfunc = tp_ops->input_data; - } else - xferfunc = tp_ops->output_data; - - if ((drive->media == ide_floppy && !pc->buf) || - (drive->media == ide_tape && pc->bh)) { - int done = drive->pc_io_buffers(drive, pc, bcount, - !!(pc->flags & PC_FLAG_WRITING)); - - /* FIXME: don't do partial completions */ - if (drive->media == ide_floppy) - ide_complete_rq(drive, 0, - done ? done : ide_rq_bytes(rq)); - } else - xferfunc(drive, NULL, pc->cur_pos, bcount); + xferfunc = write ? tp_ops->output_data : tp_ops->input_data; + + if (drive->media == ide_floppy && pc->buf == NULL) { + done = min_t(unsigned int, bcount, cmd->nleft); + ide_pio_bytes(drive, cmd, write, done); + } else if (drive->media == ide_tape && pc->bh) { + done = drive->pc_io_buffers(drive, pc, bcount, write); + } else { + done = min_t(unsigned int, bcount, pc->req_xfer - pc->xferred); + xferfunc(drive, NULL, pc->cur_pos, done); + } /* Update the current position */ - pc->xferred += bcount; - pc->cur_pos += bcount; + pc->xferred += done; + pc->cur_pos += done; + + bcount -= done; + + if (bcount) + ide_pad_transfer(drive, write, bcount); + + debug_log("[cmd %x] transferred %d bytes, padded %d bytes\n", + rq->cmd[0], done, bcount); - debug_log("[cmd %x] transferred %d bytes on that intr.\n", - rq->cmd[0], bcount); -next_irq: /* And set the interrupt handler again */ ide_set_handler(drive, ide_pc_intr, timeout); return ide_started; @@ -611,6 +563,10 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) : ide_pc_intr), timeout); + /* Send the actual packet */ + if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) + hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len); + /* Begin DMA, if necessary */ if (dev_is_idecd(drive)) { if (drive->dma) @@ -622,10 +578,6 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) } } - /* Send the actual packet */ - if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) - hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len); - return ide_started; } @@ -633,7 +585,6 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) { struct ide_atapi_pc *pc; ide_hwif_t *hwif = drive->hwif; - const struct ide_dma_ops *dma_ops = hwif->dma_ops; ide_expiry_t *expiry = NULL; struct request *rq = hwif->rq; unsigned int timeout; @@ -647,12 +598,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) expiry = ide_cd_expiry; timeout = ATAPI_WAIT_PC; - if (drive->dma) { - if (ide_build_sglist(drive, cmd)) - drive->dma = !dma_ops->dma_setup(drive, cmd); - else - drive->dma = 0; - } + if (drive->dma) + drive->dma = !ide_dma_prepare(drive, cmd); } else { pc = drive->pc; @@ -670,13 +617,8 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) ide_dma_off(drive); } - if ((pc->flags & PC_FLAG_DMA_OK) && - (drive->dev_flags & IDE_DFLAG_USING_DMA)) { - if (ide_build_sglist(drive, cmd)) - drive->dma = !dma_ops->dma_setup(drive, cmd); - else - drive->dma = 0; - } + if (pc->flags & PC_FLAG_DMA_OK) + drive->dma = !ide_dma_prepare(drive, cmd); if (!drive->dma) pc->flags &= ~PC_FLAG_DMA_OK; diff --git a/trunk/drivers/ide/ide-cd.c b/trunk/drivers/ide/ide-cd.c index 3f630e4080d4..35729a47f797 100644 --- a/trunk/drivers/ide/ide-cd.c +++ b/trunk/drivers/ide/ide-cd.c @@ -4,7 +4,7 @@ * Copyright (C) 1994-1996 Scott Snyder * Copyright (C) 1996-1998 Erik Andersen * Copyright (C) 1998-2000 Jens Axboe - * Copyright (C) 2005, 2007 Bartlomiej Zolnierkiewicz + * Copyright (C) 2005, 2007-2009 Bartlomiej Zolnierkiewicz * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. @@ -12,12 +12,9 @@ * See Documentation/cdrom/ide-cd for usage information. * * Suggestions are welcome. Patches that work are more welcome though. ;-) - * For those wishing to work on this driver, please be sure you download - * and comply with the latest Mt. Fuji (SFF8090 version 4) and ATAPI - * (SFF-8020i rev 2.6) standards. These documents can be obtained by - * anonymous ftp from: - * ftp://fission.dt.wdc.com/pub/standards/SFF_atapi/spec/SFF8020-r2.6/PS/8020r26.ps - * ftp://ftp.avc-pioneer.com/Mtfuji4/Spec/Fuji4r10.pdf + * + * Documentation: + * Mt. Fuji (SFF8090 version 4) and ATAPI (SFF-8020i rev 2.6) standards. * * For historical changelog please see: * Documentation/ide/ChangeLog.ide-cd.1994-2004 @@ -245,73 +242,34 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense, elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0); } -static void cdrom_end_request(ide_drive_t *drive, int uptodate) +static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) { - struct request *rq = drive->hwif->rq; - int nsectors = rq->hard_cur_sectors; - - ide_debug_log(IDE_DBG_FUNC, "cmd: 0x%x, uptodate: 0x%x, nsectors: %d", - rq->cmd[0], uptodate, nsectors); - - if (blk_sense_request(rq) && uptodate) { - /* - * For REQ_TYPE_SENSE, "rq->buffer" points to the original - * failed request - */ - struct request *failed = (struct request *) rq->buffer; - struct cdrom_info *info = drive->driver_data; - void *sense = &info->sense_data; - - if (failed) { - if (failed->sense) { - sense = failed->sense; - failed->sense_len = rq->sense_len; - } - cdrom_analyze_sense_data(drive, failed, sense); - /* - * now end the failed request - */ - if (blk_fs_request(failed)) { - if (ide_end_rq(drive, failed, -EIO, - failed->hard_nr_sectors << 9)) - BUG(); - } else { - if (blk_end_request(failed, -EIO, - failed->data_len)) - BUG(); - } - } else - cdrom_analyze_sense_data(drive, NULL, sense); - } - - if (!rq->current_nr_sectors && blk_fs_request(rq)) - uptodate = 1; - /* make sure it's fully ended */ - if (blk_pc_request(rq)) - nsectors = (rq->data_len + 511) >> 9; - if (!nsectors) - nsectors = 1; - - ide_debug_log(IDE_DBG_FUNC, "uptodate: 0x%x, nsectors: %d", - uptodate, nsectors); - - if (blk_fs_request(rq) == 0 && uptodate <= 0 && rq->errors == 0) - rq->errors = -EIO; + /* + * For REQ_TYPE_SENSE, "rq->buffer" points to the original + * failed request + */ + struct request *failed = (struct request *)rq->buffer; + struct cdrom_info *info = drive->driver_data; + void *sense = &info->sense_data; - ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); -} + if (failed) { + if (failed->sense) { + sense = failed->sense; + failed->sense_len = rq->sense_len; + } + cdrom_analyze_sense_data(drive, failed, sense); -static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 st) -{ - if (st & 0x80) - return; - ide_dump_status(drive, msg, st); + if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed))) + BUG(); + } else + cdrom_analyze_sense_data(drive, NULL, sense); } /* * Returns: * 0: if the request should be continued. - * 1: if the request was ended. + * 1: if the request will be going through error recovery. + * 2: if the request should be ended. */ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) { @@ -332,12 +290,6 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) err = ide_read_error(drive); sense_key = err >> 4; - if (rq == NULL) { - printk(KERN_ERR PFX "%s: missing rq in %s\n", - drive->name, __func__); - return 1; - } - ide_debug_log(IDE_DBG_RQ, "stat: 0x%x, good_stat: 0x%x, cmd[0]: 0x%x, " "rq->cmd_type: 0x%x, err: 0x%x", stat, good_stat, rq->cmd[0], rq->cmd_type, @@ -350,10 +302,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) * Just give up. */ rq->cmd_flags |= REQ_FAILED; - cdrom_end_request(drive, 0); - ide_error(drive, "request sense failure", stat); - return 1; - + return 2; } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) { /* All other functions, except for READ. */ @@ -456,21 +405,19 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) * No point in retrying after an illegal request or data * protect error. */ - ide_dump_status_no_sense(drive, "command error", stat); + ide_dump_status(drive, "command error", stat); do_end_request = 1; } else if (sense_key == MEDIUM_ERROR) { /* * No point in re-trying a zillion times on a bad * sector. If we got here the error is not correctable. */ - ide_dump_status_no_sense(drive, - "media error (bad sector)", - stat); + ide_dump_status(drive, "media error (bad sector)", + stat); do_end_request = 1; } else if (sense_key == BLANK_CHECK) { /* disk appears blank ?? */ - ide_dump_status_no_sense(drive, "media error (blank)", - stat); + ide_dump_status(drive, "media error (blank)", stat); do_end_request = 1; } else if ((err & ~ATA_ABORTED) != 0) { /* go to the default handler for other errors */ @@ -495,14 +442,12 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) */ if (stat & ATA_ERR) cdrom_queue_request_sense(drive, NULL, NULL); + return 1; } else { blk_dump_rq_flags(rq, PFX "bad rq"); - cdrom_end_request(drive, 0); + return 2; } - /* retry, or handle the next request */ - return 1; - end_request: if (stat & ATA_ERR) { struct request_queue *q = drive->queue; @@ -515,10 +460,9 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) hwif->rq = NULL; cdrom_queue_request_sense(drive, rq->sense, rq); + return 1; } else - cdrom_end_request(drive, 0); - - return 1; + return 2; } /* @@ -562,101 +506,13 @@ static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq, if (rq->cmd_type == REQ_TYPE_ATA_PC) rq->cmd_flags |= REQ_FAILED; - cdrom_end_request(drive, 0); return -1; } -/* - * Assume that the drive will always provide data in multiples of at least - * SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. - */ -static int ide_cd_check_transfer_size(ide_drive_t *drive, int len) +static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) { - ide_debug_log(IDE_DBG_FUNC, "len: %d", len); - - if ((len % SECTOR_SIZE) == 0) - return 0; + struct request *rq = cmd->rq; - printk(KERN_ERR PFX "%s: %s: Bad transfer size %d\n", drive->name, - __func__, len); - - if (drive->atapi_flags & IDE_AFLAG_LIMIT_NFRAMES) - printk(KERN_ERR PFX "This drive is not supported by this " - "version of the driver\n"); - else { - printk(KERN_ERR PFX "Trying to limit transfer sizes\n"); - drive->atapi_flags |= IDE_AFLAG_LIMIT_NFRAMES; - } - - return 1; -} - -static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive, - struct request *rq) -{ - ide_debug_log(IDE_DBG_RQ, "rq->cmd_flags: 0x%x", rq->cmd_flags); - - if (rq_data_dir(rq) == READ) { - unsigned short sectors_per_frame = - queue_hardsect_size(drive->queue) >> SECTOR_BITS; - int nskip = rq->sector & (sectors_per_frame - 1); - - /* - * If the requested sector doesn't start on a frame boundary, - * we must adjust the start of the transfer so that it does, - * and remember to skip the first few sectors. - * - * If the rq->current_nr_sectors field is larger than the size - * of the buffer, it will mean that we're to skip a number of - * sectors equal to the amount by which rq->current_nr_sectors - * is larger than the buffer size. - */ - if (nskip > 0) { - /* sanity check... */ - if (rq->current_nr_sectors != - bio_cur_sectors(rq->bio)) { - printk(KERN_ERR PFX "%s: %s: buffer botch (%u)\n", - drive->name, __func__, - rq->current_nr_sectors); - cdrom_end_request(drive, 0); - return ide_stopped; - } - rq->current_nr_sectors += nskip; - } - } - - /* set up the command */ - rq->timeout = ATAPI_WAIT_PC; - - return ide_started; -} - -/* - * Fix up a possibly partially-processed request so that we can start it over - * entirely, or even put it back on the request queue. - */ -static void ide_cd_restore_request(ide_drive_t *drive, struct request *rq) -{ - - ide_debug_log(IDE_DBG_FUNC, "enter"); - - if (rq->buffer != bio_data(rq->bio)) { - sector_t n = - (rq->buffer - (char *)bio_data(rq->bio)) / SECTOR_SIZE; - - rq->buffer = bio_data(rq->bio); - rq->nr_sectors += n; - rq->sector -= n; - } - rq->current_nr_sectors = bio_cur_sectors(rq->bio); - rq->hard_cur_sectors = rq->current_nr_sectors; - rq->hard_nr_sectors = rq->nr_sectors; - rq->hard_sector = rq->sector; - rq->q->prep_rq_fn(rq->q, rq); -} - -static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq) -{ ide_debug_log(IDE_DBG_FUNC, "rq->cmd[0]: 0x%x", rq->cmd[0]); /* @@ -664,11 +520,14 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct request *rq) * and some drives don't send them. Sigh. */ if (rq->cmd[0] == GPCMD_REQUEST_SENSE && - rq->data_len > 0 && rq->data_len <= 5) - while (rq->data_len > 0) { - *(u8 *)rq->data++ = 0; - --rq->data_len; + cmd->nleft > 0 && cmd->nleft <= 5) { + unsigned int ofs = cmd->nbytes - cmd->nleft; + + while (cmd->nleft > 0) { + *((u8 *)rq->data + ofs++) = 0; + cmd->nleft--; } + } } int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, @@ -748,24 +607,26 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, return (flags & REQ_FAILED) ? -EIO : 0; } -/* - * Called from blk_end_request_callback() after the data of the request is - * completed and before the request itself is completed. By returning value '1', - * blk_end_request_callback() returns immediately without completing it. - */ -static int cdrom_newpc_intr_dummy_cb(struct request *rq) +static void ide_cd_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) { - return 1; + unsigned int nr_bytes = cmd->nbytes - cmd->nleft; + + if (cmd->tf_flags & IDE_TFLAG_WRITE) + nr_bytes -= cmd->last_xfer_len; + + if (nr_bytes > 0) + ide_complete_rq(drive, 0, nr_bytes); } static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; + struct ide_cmd *cmd = &hwif->cmd; struct request *rq = hwif->rq; - xfer_func_t *xferfunc; ide_expiry_t *expiry = NULL; int dma_error = 0, dma, stat, thislen, uptodate = 0; - int write = (rq_data_dir(rq) == WRITE) ? 1 : 0; + int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc, nsectors; + int sense = blk_sense_request(rq); unsigned int timeout; u16 len; u8 ireason; @@ -777,7 +638,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) dma = drive->dma; if (dma) { drive->dma = 0; + drive->waiting_for_dma = 0; dma_error = hwif->dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); if (dma_error) { printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name, write ? "write" : "read"); @@ -785,27 +648,24 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) } } - if (cdrom_decode_status(drive, 0, &stat)) + rc = cdrom_decode_status(drive, 0, &stat); + if (rc) { + if (rc == 2) + goto out_end; return ide_stopped; + } /* using dma, transfer is complete now */ if (dma) { if (dma_error) return ide_error(drive, "dma error", stat); - if (blk_fs_request(rq)) { - ide_complete_rq(drive, 0, rq->nr_sectors - ? (rq->nr_sectors << 9) : ide_rq_bytes(rq)); - return ide_stopped; - } else if (rq->cmd_type == REQ_TYPE_ATA_PC && !rq->bio) { - ide_complete_rq(drive, 0, 512); - return ide_stopped; - } - goto end_request; + uptodate = 1; + goto out_end; } ide_read_bcount_and_ireason(drive, &len, &ireason); - thislen = blk_fs_request(rq) ? len : rq->data_len; + thislen = blk_fs_request(rq) ? len : cmd->nleft; if (thislen > len) thislen = len; @@ -820,60 +680,30 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) * Otherwise, complete the command normally. */ uptodate = 1; - if (rq->current_nr_sectors > 0) { + if (cmd->nleft > 0) { printk(KERN_ERR PFX "%s: %s: data underrun " - "(%d blocks)\n", - drive->name, __func__, - rq->current_nr_sectors); + "(%u bytes)\n", drive->name, __func__, + cmd->nleft); if (!write) rq->cmd_flags |= REQ_FAILED; uptodate = 0; } - cdrom_end_request(drive, uptodate); - return ide_stopped; } else if (!blk_pc_request(rq)) { - ide_cd_request_sense_fixup(drive, rq); + ide_cd_request_sense_fixup(drive, cmd); /* complain if we still have data left to transfer */ - uptodate = rq->data_len ? 0 : 1; + uptodate = cmd->nleft ? 0 : 1; + if (uptodate == 0) + rq->cmd_flags |= REQ_FAILED; } - goto end_request; + goto out_end; } /* check which way to transfer data */ - if (ide_cd_check_ireason(drive, rq, len, ireason, write)) - return ide_stopped; + rc = ide_cd_check_ireason(drive, rq, len, ireason, write); + if (rc) + goto out_end; - if (blk_fs_request(rq)) { - if (write == 0) { - int nskip; - - if (ide_cd_check_transfer_size(drive, len)) { - cdrom_end_request(drive, 0); - return ide_stopped; - } - - /* - * First, figure out if we need to bit-bucket - * any of the leading sectors. - */ - nskip = min_t(int, rq->current_nr_sectors - - bio_cur_sectors(rq->bio), - thislen >> 9); - if (nskip > 0) { - ide_pad_transfer(drive, write, nskip << 9); - rq->current_nr_sectors -= nskip; - thislen -= (nskip << 9); - } - } - } - - if (ireason == 0) { - write = 1; - xferfunc = hwif->tp_ops->output_data; - } else { - write = 0; - xferfunc = hwif->tp_ops->input_data; - } + cmd->last_xfer_len = 0; ide_debug_log(IDE_DBG_PC, "data transfer, rq->cmd_type: 0x%x, " "ireason: 0x%x", @@ -881,75 +711,31 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) /* transfer data */ while (thislen > 0) { - u8 *ptr = blk_fs_request(rq) ? NULL : rq->data; - int blen = rq->data_len; - - /* bio backed? */ - if (rq->bio) { - if (blk_fs_request(rq)) { - ptr = rq->buffer; - blen = rq->current_nr_sectors << 9; - } else { - ptr = bio_data(rq->bio); - blen = bio_iovec(rq->bio)->bv_len; - } - } + int blen = min_t(int, thislen, cmd->nleft); - if (!ptr) { - if (blk_fs_request(rq) && !write) - /* - * If the buffers are full, pipe the rest into - * oblivion. - */ - ide_pad_transfer(drive, 0, thislen); - else { - printk(KERN_ERR PFX "%s: confused, missing data\n", - drive->name); - blk_dump_rq_flags(rq, rq_data_dir(rq) - ? "cdrom_newpc_intr, write" - : "cdrom_newpc_intr, read"); - } + if (cmd->nleft == 0) break; - } - - if (blen > thislen) - blen = thislen; - xferfunc(drive, NULL, ptr, blen); + ide_pio_bytes(drive, cmd, write, blen); + cmd->last_xfer_len += blen; thislen -= blen; len -= blen; - if (blk_fs_request(rq)) { - rq->buffer += blen; - rq->nr_sectors -= (blen >> 9); - rq->current_nr_sectors -= (blen >> 9); - rq->sector += (blen >> 9); - - if (rq->current_nr_sectors == 0 && rq->nr_sectors) - cdrom_end_request(drive, 1); - } else { - rq->data_len -= blen; - - /* - * The request can't be completed until DRQ is cleared. - * So complete the data, but don't complete the request - * using the dummy function for the callback feature - * of blk_end_request_callback(). - */ - if (rq->bio) - blk_end_request_callback(rq, 0, blen, - cdrom_newpc_intr_dummy_cb); - else - rq->data += blen; - } - if (!write && blk_sense_request(rq)) + if (sense && write == 0) rq->sense_len += blen; } /* pad, if necessary */ - if (!blk_fs_request(rq) && len > 0) - ide_pad_transfer(drive, write, len); + if (len > 0) { + if (blk_fs_request(rq) == 0 || write == 0) + ide_pad_transfer(drive, write, len); + else { + printk(KERN_ERR PFX "%s: confused, missing data\n", + drive->name); + blk_dump_rq_flags(rq, "cdrom_newpc_intr"); + } + } if (blk_pc_request(rq)) { timeout = rq->timeout; @@ -963,21 +749,50 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) ide_set_handler(drive, cdrom_newpc_intr, timeout); return ide_started; -end_request: - if (blk_pc_request(rq)) { +out_end: + if (blk_pc_request(rq) && rc == 0) { unsigned int dlen = rq->data_len; - if (dma) - rq->data_len = 0; + rq->data_len = 0; if (blk_end_request(rq, 0, dlen)) BUG(); hwif->rq = NULL; } else { - if (!uptodate) - rq->cmd_flags |= REQ_FAILED; - cdrom_end_request(drive, uptodate); + if (sense && uptodate) + ide_cd_complete_failed_rq(drive, rq); + + if (blk_fs_request(rq)) { + if (cmd->nleft == 0) + uptodate = 1; + } else { + if (uptodate <= 0 && rq->errors == 0) + rq->errors = -EIO; + } + + if (uptodate == 0) + ide_cd_error_cmd(drive, cmd); + + /* make sure it's fully ended */ + if (blk_pc_request(rq)) + nsectors = (rq->data_len + 511) >> 9; + else + nsectors = rq->hard_nr_sectors; + + if (nsectors == 0) + nsectors = 1; + + if (blk_fs_request(rq) == 0) { + rq->data_len -= (cmd->nbytes - cmd->nleft); + if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) + rq->data_len += cmd->last_xfer_len; + } + + ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); + + if (sense && rc == 2) + ide_error(drive, "request sense failure", stat); } return ide_stopped; } @@ -985,42 +800,40 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq) { struct cdrom_info *cd = drive->driver_data; + struct request_queue *q = drive->queue; int write = rq_data_dir(rq) == WRITE; unsigned short sectors_per_frame = - queue_hardsect_size(drive->queue) >> SECTOR_BITS; + queue_hardsect_size(q) >> SECTOR_BITS; - ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, write: 0x%x, " + ide_debug_log(IDE_DBG_RQ, "rq->cmd[0]: 0x%x, rq->cmd_flags: 0x%x, " "secs_per_frame: %u", - rq->cmd[0], write, sectors_per_frame); + rq->cmd[0], rq->cmd_flags, sectors_per_frame); if (write) { /* disk has become write protected */ - if (get_disk_ro(cd->disk)) { - cdrom_end_request(drive, 0); + if (get_disk_ro(cd->disk)) return ide_stopped; - } } else { /* * We may be retrying this request after an error. Fix up any * weirdness which might be present in the request packet. */ - ide_cd_restore_request(drive, rq); + q->prep_rq_fn(q, rq); } - /* use DMA, if possible / writes *must* be hardware frame aligned */ + /* fs requests *must* be hardware frame aligned */ if ((rq->nr_sectors & (sectors_per_frame - 1)) || - (rq->sector & (sectors_per_frame - 1))) { - if (write) { - cdrom_end_request(drive, 0); - return ide_stopped; - } - drive->dma = 0; - } else - drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); + (rq->sector & (sectors_per_frame - 1))) + return ide_stopped; + + /* use DMA, if possible */ + drive->dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); if (write) cd->devinfo.media_written = 1; + rq->timeout = ATAPI_WAIT_PC; + return ide_started; } @@ -1068,6 +881,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, sector_t block) { struct ide_cmd cmd; + int uptodate = 0, nsectors; ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, block: %llu", rq->cmd[0], (unsigned long long)block); @@ -1077,10 +891,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, if (blk_fs_request(rq)) { if (cdrom_start_rw(drive, rq) == ide_stopped) - return ide_stopped; - - if (ide_cd_prepare_rw_request(drive, rq) == ide_stopped) - return ide_stopped; + goto out_end; } else if (blk_sense_request(rq) || blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) { if (!rq->timeout) @@ -1089,12 +900,13 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, cdrom_do_block_pc(drive, rq); } else if (blk_special_request(rq)) { /* right now this can only be a reset... */ - cdrom_end_request(drive, 1); - return ide_stopped; + uptodate = 1; + goto out_end; } else { blk_dump_rq_flags(rq, DRV_NAME " bad flags"); - cdrom_end_request(drive, 0); - return ide_stopped; + if (rq->errors == 0) + rq->errors = -EIO; + goto out_end; } memset(&cmd, 0, sizeof(cmd)); @@ -1104,7 +916,22 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, cmd.rq = rq; + if (blk_fs_request(rq) || rq->data_len) { + ide_init_sg_cmd(&cmd, blk_fs_request(rq) ? (rq->nr_sectors << 9) + : rq->data_len); + ide_map_sg(drive, &cmd); + } + return ide_issue_pc(drive, &cmd); +out_end: + nsectors = rq->hard_nr_sectors; + + if (nsectors == 0) + nsectors = 1; + + ide_complete_rq(drive, uptodate ? 0 : -EIO, nsectors << 9); + + return ide_stopped; } /* @@ -1696,9 +1523,6 @@ static const struct ide_proc_devset *ide_cd_proc_devsets(ide_drive_t *drive) #endif static const struct cd_list_entry ide_cd_quirks_list[] = { - /* Limit transfer size per interrupt. */ - { "SAMSUNG CD-ROM SCR-2430", NULL, IDE_AFLAG_LIMIT_NFRAMES }, - { "SAMSUNG CD-ROM SCR-2432", NULL, IDE_AFLAG_LIMIT_NFRAMES }, /* SCR-3231 doesn't support the SET_CD_SPEED command. */ { "SAMSUNG CD-ROM SCR-3231", NULL, IDE_AFLAG_NO_SPEED_SELECT }, /* Old NEC260 (not R) was released before ATAPI 1.2 spec. */ @@ -1759,18 +1583,18 @@ static int ide_cdrom_setup(ide_drive_t *drive) { struct cdrom_info *cd = drive->driver_data; struct cdrom_device_info *cdi = &cd->devinfo; + struct request_queue *q = drive->queue; u16 *id = drive->id; char *fw_rev = (char *)&id[ATA_ID_FW_REV]; int nslots; ide_debug_log(IDE_DBG_PROBE, "enter"); - blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn); - blk_queue_dma_alignment(drive->queue, 31); - blk_queue_update_dma_pad(drive->queue, 15); - drive->queue->unplug_delay = (1 * HZ) / 1000; - if (!drive->queue->unplug_delay) - drive->queue->unplug_delay = 1; + blk_queue_prep_rq(q, ide_cdrom_prep_fn); + blk_queue_dma_alignment(q, 31); + blk_queue_update_dma_pad(q, 15); + + q->unplug_delay = max((1 * HZ) / 1000, 1); drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id); @@ -1788,8 +1612,7 @@ static int ide_cdrom_setup(ide_drive_t *drive) nslots = ide_cdrom_probe_capabilities(drive); - /* set correct block size */ - blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE); + blk_queue_hardsect_size(q, CD_FRAMESIZE); if (ide_cdrom_register(drive, nslots)) { printk(KERN_ERR PFX "%s: %s failed to register device with the" @@ -1968,9 +1791,6 @@ static struct block_device_operations idecd_ops = { }; /* module options */ -static char *ignore; -module_param(ignore, charp, 0400); - static unsigned long debug_mask; module_param(debug_mask, ulong, 0644); @@ -1991,15 +1811,6 @@ static int ide_cd_probe(ide_drive_t *drive) if (drive->media != ide_cdrom && drive->media != ide_optical) goto failed; - /* skip drives that we were told to ignore */ - if (ignore != NULL) { - if (strstr(ignore, drive->name)) { - printk(KERN_INFO PFX "ignoring drive %s\n", - drive->name); - goto failed; - } - } - drive->debug_mask = debug_mask; drive->irq_handler = cdrom_newpc_intr; diff --git a/trunk/drivers/ide/ide-disk.c b/trunk/drivers/ide/ide-disk.c index ca934c8a1289..c998cf8e971a 100644 --- a/trunk/drivers/ide/ide-disk.c +++ b/trunk/drivers/ide/ide-disk.c @@ -227,7 +227,7 @@ static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) ide_no_data_taskfile(drive, &cmd); /* if OK, compute maximum address value */ - if ((tf->status & 0x01) == 0) + if (!(tf->status & ATA_ERR)) addr = ide_get_lba_addr(tf, lba48) + 1; return addr; @@ -267,7 +267,7 @@ static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48) ide_no_data_taskfile(drive, &cmd); /* if OK, compute maximum address value */ - if ((tf->status & 0x01) == 0) + if (!(tf->status & ATA_ERR)) addr_set = ide_get_lba_addr(tf, lba48) + 1; return addr_set; diff --git a/trunk/drivers/ide/ide-dma-sff.c b/trunk/drivers/ide/ide-dma-sff.c index 75a9ea2e4c82..16fc46edc32d 100644 --- a/trunk/drivers/ide/ide-dma-sff.c +++ b/trunk/drivers/ide/ide-dma-sff.c @@ -38,10 +38,9 @@ int config_drive_for_dma(ide_drive_t *drive) * Enable DMA on any drive that has mode2 DMA * (multi or single) enabled */ - if (id[ATA_ID_FIELD_VALID] & 2) /* regular DMA */ - if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 || - (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404) - return 1; + if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 || + (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404) + return 1; /* Consult the list of known "good" drives */ if (ide_dma_good_drive(drive)) @@ -166,8 +165,6 @@ int ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) printk(KERN_ERR "%s: %s\n", drive->name, count ? "DMA table too small" : "empty DMA table?"); - ide_destroy_dmatable(drive); - return 0; /* revert to PIO for this request */ } EXPORT_SYMBOL_GPL(ide_build_dmatable); @@ -218,7 +215,6 @@ int ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) /* clear INTR & ERROR flags */ ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR); - drive->waiting_for_dma = 1; return 0; } EXPORT_SYMBOL_GPL(ide_dma_setup); @@ -292,8 +288,6 @@ int ide_dma_end(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; u8 dma_stat = 0, dma_cmd = 0, mask; - drive->waiting_for_dma = 0; - /* stop DMA */ if (hwif->host_flags & IDE_HFLAG_MMIO) { dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD)); @@ -310,8 +304,6 @@ int ide_dma_end(ide_drive_t *drive) /* clear INTR & ERROR bits */ ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR); - /* purge DMA mappings */ - ide_destroy_dmatable(drive); wmb(); /* verify good DMA status */ @@ -338,9 +330,8 @@ const struct ide_dma_ops sff_dma_ops = { .dma_start = ide_dma_start, .dma_end = ide_dma_end, .dma_test_irq = ide_dma_test_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, .dma_sff_read_status = ide_dma_sff_read_status, }; EXPORT_SYMBOL_GPL(sff_dma_ops); diff --git a/trunk/drivers/ide/ide-dma.c b/trunk/drivers/ide/ide-dma.c index 3dbf80c15491..a0b8cab1d9a6 100644 --- a/trunk/drivers/ide/ide-dma.c +++ b/trunk/drivers/ide/ide-dma.c @@ -89,15 +89,16 @@ static const struct drive_list_entry drive_blacklist[] = { ide_startstop_t ide_dma_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; + struct ide_cmd *cmd = &hwif->cmd; u8 stat = 0, dma_stat = 0; + drive->waiting_for_dma = 0; dma_stat = hwif->dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); stat = hwif->tp_ops->read_status(hwif); if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | ATA_DRQ)) { if (!dma_stat) { - struct ide_cmd *cmd = &hwif->cmd; - if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) ide_finish_cmd(drive, cmd, stat); else @@ -117,8 +118,8 @@ int ide_dma_good_drive(ide_drive_t *drive) } /** - * ide_build_sglist - map IDE scatter gather for DMA I/O - * @drive: the drive to build the DMA table for + * ide_dma_map_sg - map IDE scatter gather for DMA I/O + * @drive: the drive to map the DMA table for * @cmd: command * * Perform the DMA mapping magic necessary to access the source or @@ -127,23 +128,19 @@ int ide_dma_good_drive(ide_drive_t *drive) * operate in a portable fashion. */ -int ide_build_sglist(ide_drive_t *drive, struct ide_cmd *cmd) +static int ide_dma_map_sg(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; int i; - ide_map_sg(drive, cmd); - if (cmd->tf_flags & IDE_TFLAG_WRITE) cmd->sg_dma_direction = DMA_TO_DEVICE; else cmd->sg_dma_direction = DMA_FROM_DEVICE; i = dma_map_sg(hwif->dev, sg, cmd->sg_nents, cmd->sg_dma_direction); - if (i == 0) - ide_map_sg(drive, cmd); - else { + if (i) { cmd->orig_sg_nents = cmd->sg_nents; cmd->sg_nents = i; } @@ -152,7 +149,7 @@ int ide_build_sglist(ide_drive_t *drive, struct ide_cmd *cmd) } /** - * ide_destroy_dmatable - clean up DMA mapping + * ide_dma_unmap_sg - clean up DMA mapping * @drive: The drive to unmap * * Teardown mappings after DMA has completed. This must be called @@ -162,15 +159,14 @@ int ide_build_sglist(ide_drive_t *drive, struct ide_cmd *cmd) * time. */ -void ide_destroy_dmatable(ide_drive_t *drive) +void ide_dma_unmap_sg(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; - struct ide_cmd *cmd = &hwif->cmd; dma_unmap_sg(hwif->dev, hwif->sg_table, cmd->orig_sg_nents, cmd->sg_dma_direction); } -EXPORT_SYMBOL_GPL(ide_destroy_dmatable); +EXPORT_SYMBOL_GPL(ide_dma_unmap_sg); /** * ide_dma_off_quietly - Generic DMA kill @@ -249,12 +245,11 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) case XFER_UDMA_0: if ((id[ATA_ID_FIELD_VALID] & 4) == 0) break; - + mask = id[ATA_ID_UDMA_MODES]; if (port_ops && port_ops->udma_filter) - mask = port_ops->udma_filter(drive); + mask &= port_ops->udma_filter(drive); else - mask = hwif->ultra_mask; - mask &= id[ATA_ID_UDMA_MODES]; + mask &= hwif->ultra_mask; /* * avoid false cable warning from eighty_ninty_three() @@ -265,18 +260,23 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) } break; case XFER_MW_DMA_0: - if ((id[ATA_ID_FIELD_VALID] & 2) == 0) - break; + mask = id[ATA_ID_MWDMA_MODES]; + + /* Also look for the CF specific MWDMA modes... */ + if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 0x38)) { + u8 mode = ((id[ATA_ID_CFA_MODES] & 0x38) >> 3) - 1; + + mask |= ((2 << mode) - 1) << 3; + } + if (port_ops && port_ops->mdma_filter) - mask = port_ops->mdma_filter(drive); + mask &= port_ops->mdma_filter(drive); else - mask = hwif->mwdma_mask; - mask &= id[ATA_ID_MWDMA_MODES]; + mask &= hwif->mwdma_mask; break; case XFER_SW_DMA_0: - if (id[ATA_ID_FIELD_VALID] & 2) { - mask = id[ATA_ID_SWDMA_MODES] & hwif->swdma_mask; - } else if (id[ATA_ID_OLD_DMA_MODES] >> 8) { + mask = id[ATA_ID_SWDMA_MODES]; + if (!(mask & ATA_SWDMA2) && (id[ATA_ID_OLD_DMA_MODES] >> 8)) { u8 mode = id[ATA_ID_OLD_DMA_MODES] >> 8; /* @@ -284,8 +284,9 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) * (the maximum allowed mode is XFER_SW_DMA_2) */ if (mode <= 2) - mask = ((2 << mode) - 1) & hwif->swdma_mask; + mask = (2 << mode) - 1; } + mask &= hwif->swdma_mask; break; default: BUG(); @@ -402,11 +403,10 @@ int ide_id_dma_bug(ide_drive_t *drive) if ((id[ATA_ID_UDMA_MODES] >> 8) && (id[ATA_ID_MWDMA_MODES] >> 8)) goto err_out; - } else if (id[ATA_ID_FIELD_VALID] & 2) { - if ((id[ATA_ID_MWDMA_MODES] >> 8) && - (id[ATA_ID_SWDMA_MODES] >> 8)) - goto err_out; - } + } else if ((id[ATA_ID_MWDMA_MODES] >> 8) && + (id[ATA_ID_SWDMA_MODES] >> 8)) + goto err_out; + return 0; err_out: printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name); @@ -460,21 +460,6 @@ void ide_dma_lost_irq(ide_drive_t *drive) } EXPORT_SYMBOL_GPL(ide_dma_lost_irq); -void ide_dma_timeout(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - - printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name); - - if (hwif->dma_ops->dma_test_irq(drive)) - return; - - ide_dump_status(drive, "DMA timeout", hwif->tp_ops->read_status(hwif)); - - hwif->dma_ops->dma_end(drive); -} -EXPORT_SYMBOL_GPL(ide_dma_timeout); - /* * un-busy the port etc, and clear any pending DMA status. we want to * retry the current request in pio mode instead of risking tossing it @@ -483,6 +468,8 @@ EXPORT_SYMBOL_GPL(ide_dma_timeout); ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) { ide_hwif_t *hwif = drive->hwif; + const struct ide_dma_ops *dma_ops = hwif->dma_ops; + struct ide_cmd *cmd = &hwif->cmd; struct request *rq; ide_startstop_t ret = ide_stopped; @@ -492,12 +479,23 @@ ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) if (error < 0) { printk(KERN_WARNING "%s: DMA timeout error\n", drive->name); - (void)hwif->dma_ops->dma_end(drive); + drive->waiting_for_dma = 0; + (void)dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); ret = ide_error(drive, "dma timeout error", hwif->tp_ops->read_status(hwif)); } else { printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name); - hwif->dma_ops->dma_timeout(drive); + if (dma_ops->dma_clear) + dma_ops->dma_clear(drive); + printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name); + if (dma_ops->dma_test_irq(drive) == 0) { + ide_dump_status(drive, "DMA timeout", + hwif->tp_ops->read_status(hwif)); + drive->waiting_for_dma = 0; + (void)dma_ops->dma_end(drive); + ide_dma_unmap_sg(drive, cmd); + } } /* @@ -567,3 +565,25 @@ int ide_allocate_dma_engine(ide_hwif_t *hwif) return 0; } EXPORT_SYMBOL_GPL(ide_allocate_dma_engine); + +int ide_dma_prepare(ide_drive_t *drive, struct ide_cmd *cmd) +{ + const struct ide_dma_ops *dma_ops = drive->hwif->dma_ops; + + if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 || + (dma_ops->dma_check && dma_ops->dma_check(drive, cmd))) + goto out; + ide_map_sg(drive, cmd); + if (ide_dma_map_sg(drive, cmd) == 0) + goto out_map; + if (dma_ops->dma_setup(drive, cmd)) + goto out_dma_unmap; + drive->waiting_for_dma = 1; + return 0; +out_dma_unmap: + ide_dma_unmap_sg(drive, cmd); +out_map: + ide_map_sg(drive, cmd); +out: + return 1; +} diff --git a/trunk/drivers/ide/ide-eh.c b/trunk/drivers/ide/ide-eh.c index 11664976eea3..5d5fb961b5ce 100644 --- a/trunk/drivers/ide/ide-eh.c +++ b/trunk/drivers/ide/ide-eh.c @@ -165,11 +165,12 @@ static ide_startstop_t do_reset1(ide_drive_t *, int); static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; u8 stat; - SELECT_DRIVE(drive); + tp_ops->dev_select(drive); udelay(10); - stat = hwif->tp_ops->read_status(hwif); + stat = tp_ops->read_status(hwif); if (OK_STAT(stat, 0, ATA_BUSY)) printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name); @@ -348,7 +349,7 @@ static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi) /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { pre_reset(drive); - SELECT_DRIVE(drive); + tp_ops->dev_select(drive); udelay(20); tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); ndelay(400); @@ -401,15 +402,14 @@ static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi) * immediate interrupt due to the edge transition it produces. * This single interrupt gives us a "fast poll" for drives that * recover from reset very quickly, saving us the first 50ms wait time. - * - * TODO: add ->softreset method and stop abusing ->set_irq */ /* set SRST and nIEN */ - tp_ops->set_irq(hwif, 4); + tp_ops->write_devctl(hwif, ATA_SRST | ATA_NIEN | ATA_DEVCTL_OBS); /* more than enough time */ udelay(10); /* clear SRST, leave nIEN (unless device is on the quirk list) */ - tp_ops->set_irq(hwif, drive->quirk_list == 2); + tp_ops->write_devctl(hwif, (drive->quirk_list == 2 ? 0 : ATA_NIEN) | + ATA_DEVCTL_OBS); /* more than enough time */ udelay(10); hwif->poll_timeout = jiffies + WAIT_WORSTCASE; diff --git a/trunk/drivers/ide/ide-floppy.c b/trunk/drivers/ide/ide-floppy.c index 7ae662334835..2b4868d95f8b 100644 --- a/trunk/drivers/ide/ide-floppy.c +++ b/trunk/drivers/ide/ide-floppy.c @@ -61,16 +61,6 @@ */ #define IDEFLOPPY_PC_DELAY (HZ/20) /* default delay for ZIP 100 (50ms) */ -static void idefloppy_update_buffers(ide_drive_t *drive, - struct ide_atapi_pc *pc) -{ - struct request *rq = pc->rq; - struct bio *bio = rq->bio; - - while ((bio = rq->bio) != NULL) - ide_complete_rq(drive, 0, ide_rq_bytes(rq)); -} - static int ide_floppy_callback(ide_drive_t *drive, int dsc) { struct ide_disk_obj *floppy = drive->driver_data; @@ -213,7 +203,6 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive, memcpy(rq->cmd, pc->c, 12); pc->rq = rq; - pc->b_count = 0; if (rq->cmd_flags & REQ_RW) pc->flags |= PC_FLAG_WRITING; pc->buf = NULL; @@ -227,7 +216,6 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, ide_init_pc(pc); memcpy(pc->c, rq->cmd, sizeof(pc->c)); pc->rq = rq; - pc->b_count = 0; if (rq->data_len && rq_data_dir(rq) == WRITE) pc->flags |= PC_FLAG_WRITING; pc->buf = rq->data; @@ -244,10 +232,11 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, struct request *rq, sector_t block) { struct ide_disk_obj *floppy = drive->driver_data; - ide_hwif_t *hwif = drive->hwif; struct ide_cmd cmd; struct ide_atapi_pc *pc; + ide_debug_log(IDE_DBG_FUNC, "enter, cmd: 0x%x\n", rq->cmd[0]); + if (drive->debug_mask & IDE_DBG_RQ) blk_dump_rq_flags(rq, (rq->rq_disk ? rq->rq_disk->disk_name @@ -294,13 +283,10 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, cmd.rq = rq; if (blk_fs_request(rq) || pc->req_xfer) { - ide_init_sg_cmd(&cmd, rq->nr_sectors << 9); + ide_init_sg_cmd(&cmd, pc->req_xfer); ide_map_sg(drive, &cmd); } - pc->sg = hwif->sg_table; - pc->sg_cnt = cmd.sg_nents; - pc->rq = rq; return ide_floppy_issue_pc(drive, &cmd, pc); @@ -385,9 +371,11 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) struct gendisk *disk = floppy->disk; struct ide_atapi_pc pc; u8 *cap_desc; - u8 header_len, desc_cnt; + u8 pc_buf[256], header_len, desc_cnt; int i, rc = 1, blocks, length; + ide_debug_log(IDE_DBG_FUNC, "enter"); + drive->bios_cyl = 0; drive->bios_head = drive->bios_sect = 0; floppy->blocks = 0; @@ -395,6 +383,9 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) drive->capacity64 = 0; ide_floppy_create_read_capacity_cmd(&pc); + pc.buf = &pc_buf[0]; + pc.buf_size = sizeof(pc_buf); + if (ide_queue_pc_tail(drive, disk, &pc)) { printk(KERN_ERR PFX "Can't get floppy parameters\n"); return 1; @@ -485,8 +476,6 @@ static void ide_floppy_setup(ide_drive_t *drive) u16 *id = drive->id; drive->pc_callback = ide_floppy_callback; - drive->pc_update_buffers = idefloppy_update_buffers; - drive->pc_io_buffers = ide_io_buffers; /* * We used to check revisions here. At this point however I'm giving up. diff --git a/trunk/drivers/ide/ide-floppy_ioctl.c b/trunk/drivers/ide/ide-floppy_ioctl.c index 8f8be8546038..cd8a42027ede 100644 --- a/trunk/drivers/ide/ide-floppy_ioctl.c +++ b/trunk/drivers/ide/ide-floppy_ioctl.c @@ -36,9 +36,9 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg) { struct ide_disk_obj *floppy = drive->driver_data; - u8 header_len, desc_cnt; int i, blocks, length, u_array_size, u_index; int __user *argp; + u8 pc_buf[256], header_len, desc_cnt; if (get_user(u_array_size, arg)) return -EFAULT; @@ -47,6 +47,9 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, return -EINVAL; ide_floppy_create_read_capacity_cmd(pc); + pc->buf = &pc_buf[0]; + pc->buf_size = sizeof(pc_buf); + if (ide_queue_pc_tail(drive, floppy->disk, pc)) { printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); return -EIO; diff --git a/trunk/drivers/ide/ide-generic.c b/trunk/drivers/ide/ide-generic.c index 9d03e8211536..7812ca0be13b 100644 --- a/trunk/drivers/ide/ide-generic.c +++ b/trunk/drivers/ide/ide-generic.c @@ -1,27 +1,22 @@ /* * generic/default IDE host driver * - * Copyright (C) 2004, 2008 Bartlomiej Zolnierkiewicz + * Copyright (C) 2004, 2008-2009 Bartlomiej Zolnierkiewicz * This code was split off from ide.c. See it for original copyrights. * * May be copied or modified under the terms of the GNU General Public License. */ -/* - * For special cases new interfaces may be added using sysfs, i.e. - * - * echo -n "0x168:0x36e:10" > /sys/class/ide_generic/add - * - * will add an interface using I/O ports 0x168-0x16f/0x36e and IRQ 10. - */ - #include #include #include #include #include -/* FIXME: convert m32r to use ide_platform host driver */ +/* FIXME: convert arm and m32r to use ide_platform host driver */ +#ifdef CONFIG_ARM +#include +#endif #ifdef CONFIG_M32R #include #endif @@ -36,62 +31,11 @@ static const struct ide_port_info ide_generic_port_info = { .host_flags = IDE_HFLAG_NO_DMA, }; -static ssize_t store_add(struct class *cls, const char *buf, size_t n) -{ - unsigned int base, ctl; - int irq, rc; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; - - if (sscanf(buf, "%x:%x:%d", &base, &ctl, &irq) != 3) - return -EINVAL; - - memset(&hw, 0, sizeof(hw)); - ide_std_init_ports(&hw, base, ctl); - hw.irq = irq; - hw.chipset = ide_generic; - - rc = ide_host_add(&ide_generic_port_info, hws, NULL); - if (rc) - return rc; - - return n; -}; - -static struct class_attribute ide_generic_class_attrs[] = { - __ATTR(add, S_IWUSR, NULL, store_add), - __ATTR_NULL -}; - -static void ide_generic_class_release(struct class *cls) -{ - kfree(cls); -} - -static int __init ide_generic_sysfs_init(void) -{ - struct class *cls; - int rc; - - cls = kzalloc(sizeof(*cls), GFP_KERNEL); - if (!cls) - return -ENOMEM; - - cls->name = DRV_NAME; - cls->owner = THIS_MODULE; - cls->class_release = ide_generic_class_release; - cls->class_attrs = ide_generic_class_attrs; - - rc = class_register(cls); - if (rc) { - kfree(cls); - return rc; - } - - return 0; -} - -#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) \ - || defined(CONFIG_PLAT_OPSPUT) +#ifdef CONFIG_ARM +static const u16 legacy_bases[] = { 0x1f0 }; +static const int legacy_irqs[] = { IRQ_HARDDISK }; +#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_MAPPI2) || \ + defined(CONFIG_PLAT_OPSPUT) static const u16 legacy_bases[] = { 0x1f0 }; static const int legacy_irqs[] = { PLD_IRQ_CFIREQ }; #elif defined(CONFIG_PLAT_MAPPI3) @@ -107,11 +51,11 @@ static const int legacy_irqs[] = { 14, 15, 11, 10, 8, 12 }; static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary) { +#ifdef CONFIG_PCI struct pci_dev *p = NULL; u16 val; for_each_pci_dev(p) { - if (pci_resource_start(p, 0) == 0x1f0) *primary = 1; if (pci_resource_start(p, 2) == 0x170) @@ -126,7 +70,6 @@ static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary) /* Intel MPIIX - PIO ATA on non PCI side of bridge */ if (p->vendor == PCI_VENDOR_ID_INTEL && p->device == PCI_DEVICE_ID_INTEL_82371MX) { - pci_read_config_word(p, 0x6C, &val); if (val & 0x8000) { /* ATA port enabled */ @@ -137,6 +80,7 @@ static void ide_generic_check_pci_legacy_iobases(int *primary, int *secondary) } } } +#endif } static int __init ide_generic_init(void) @@ -168,6 +112,7 @@ static int __init ide_generic_init(void) printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX " "not free.\n", DRV_NAME, io_addr, io_addr + 7); + rc = -EBUSY; continue; } @@ -176,6 +121,7 @@ static int __init ide_generic_init(void) "not free.\n", DRV_NAME, io_addr + 0x206); release_region(io_addr, 8); + rc = -EBUSY; continue; } @@ -196,10 +142,6 @@ static int __init ide_generic_init(void) } } - if (ide_generic_sysfs_init()) - printk(KERN_ERR DRV_NAME ": failed to create ide_generic " - "class\n"); - return rc; } diff --git a/trunk/drivers/ide/ide-h8300.c b/trunk/drivers/ide/ide-h8300.c index ff8339ed59ab..dac9a6d44963 100644 --- a/trunk/drivers/ide/ide-h8300.c +++ b/trunk/drivers/ide/ide-h8300.c @@ -54,9 +54,6 @@ static void h8300_tf_load(ide_drive_t *drive, struct ide_cmd *cmd) if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED) HIHI = 0xFF; - if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) - mm_outw((tf->hob_data << 8) | tf->data, io_ports->data_addr); - if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) outb(tf->hob_feature, io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) @@ -90,18 +87,11 @@ static void h8300_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) struct ide_io_ports *io_ports = &hwif->io_ports; struct ide_taskfile *tf = &cmd->tf; - if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { - u16 data = mm_inw(io_ports->data_addr); - - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - /* be sure we're looking at the low order bits */ - outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); + outb(ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE) - tf->feature = inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_ERROR) + tf->error = inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_NSECT) tf->nsect = inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_LBAL) @@ -114,18 +104,18 @@ static void h8300_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) tf->device = inb(io_ports->device_addr); if (cmd->tf_flags & IDE_TFLAG_LBA48) { - outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); + outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR) + tf->hob_error = inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = inb(io_ports->nsect_addr); + tf->hob_nsect = inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = inb(io_ports->lbal_addr); + tf->hob_lbal = inb(io_ports->lbal_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = inb(io_ports->lbam_addr); + tf->hob_lbam = inb(io_ports->lbam_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = inb(io_ports->lbah_addr); + tf->hob_lbah = inb(io_ports->lbah_addr); } } @@ -159,9 +149,9 @@ static const struct ide_tp_ops h8300_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = h8300_tf_load, .tf_read = h8300_tf_read, diff --git a/trunk/drivers/ide/ide-io-std.c b/trunk/drivers/ide/ide-io-std.c index 2d9c6dc3f956..9cac281d82c4 100644 --- a/trunk/drivers/ide/ide-io-std.c +++ b/trunk/drivers/ide/ide-io-std.c @@ -64,23 +64,26 @@ u8 ide_read_altstatus(ide_hwif_t *hwif) } EXPORT_SYMBOL_GPL(ide_read_altstatus); -void ide_set_irq(ide_hwif_t *hwif, int on) +void ide_write_devctl(ide_hwif_t *hwif, u8 ctl) { - u8 ctl = ATA_DEVCTL_OBS; - - if (on == 4) { /* hack for SRST */ - ctl |= 4; - on &= ~4; - } - - ctl |= on ? 0 : 2; - if (hwif->host_flags & IDE_HFLAG_MMIO) writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr); else outb(ctl, hwif->io_ports.ctl_addr); } -EXPORT_SYMBOL_GPL(ide_set_irq); +EXPORT_SYMBOL_GPL(ide_write_devctl); + +void ide_dev_select(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + u8 select = drive->select | ATA_DEVICE_OBS; + + if (hwif->host_flags & IDE_HFLAG_MMIO) + writeb(select, (void __iomem *)hwif->io_ports.device_addr); + else + outb(select, hwif->io_ports.device_addr); +} +EXPORT_SYMBOL_GPL(ide_dev_select); void ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd) { @@ -99,15 +102,6 @@ void ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd) if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED) HIHI = 0xFF; - if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { - u16 data = (tf->hob_data << 8) | tf->data; - - if (mmio) - writew(data, (void __iomem *)io_ports->data_addr); - else - outw(data, io_ports->data_addr); - } - if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) tf_outb(tf->hob_feature, io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) @@ -153,23 +147,11 @@ void ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) tf_inb = ide_inb; } - if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { - u16 data; - - if (mmio) - data = readw((void __iomem *)io_ports->data_addr); - else - data = inw(io_ports->data_addr); - - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - /* be sure we're looking at the low order bits */ - tf_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); + tf_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE) - tf->feature = tf_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_ERROR) + tf->error = tf_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_NSECT) tf->nsect = tf_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_LBAL) @@ -182,18 +164,18 @@ void ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) tf->device = tf_inb(io_ports->device_addr); if (cmd->tf_flags & IDE_TFLAG_LBA48) { - tf_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); + tf_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = tf_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR) + tf->hob_error = tf_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = tf_inb(io_ports->nsect_addr); + tf->hob_nsect = tf_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = tf_inb(io_ports->lbal_addr); + tf->hob_lbal = tf_inb(io_ports->lbal_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = tf_inb(io_ports->lbam_addr); + tf->hob_lbam = tf_inb(io_ports->lbam_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = tf_inb(io_ports->lbah_addr); + tf->hob_lbah = tf_inb(io_ports->lbah_addr); } } EXPORT_SYMBOL_GPL(ide_tf_read); @@ -225,11 +207,10 @@ void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; unsigned long data_addr = io_ports->data_addr; + unsigned int words = (len + 1) >> 1; u8 io_32bit = drive->io_32bit; u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - len++; - if (io_32bit) { unsigned long uninitialized_var(flags); @@ -238,27 +219,26 @@ void ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, ata_vlb_sync(io_ports->nsect_addr); } + words >>= 1; if (mmio) - __ide_mm_insl((void __iomem *)data_addr, buf, len / 4); + __ide_mm_insl((void __iomem *)data_addr, buf, words); else - insl(data_addr, buf, len / 4); + insl(data_addr, buf, words); if ((io_32bit & 2) && !mmio) local_irq_restore(flags); - if ((len & 3) >= 2) { - if (mmio) - __ide_mm_insw((void __iomem *)data_addr, - (u8 *)buf + (len & ~3), 1); - else - insw(data_addr, (u8 *)buf + (len & ~3), 1); - } - } else { - if (mmio) - __ide_mm_insw((void __iomem *)data_addr, buf, len / 2); - else - insw(data_addr, buf, len / 2); + if (((len + 1) & 3) < 2) + return; + + buf += len & ~3; + words = 1; } + + if (mmio) + __ide_mm_insw((void __iomem *)data_addr, buf, words); + else + insw(data_addr, buf, words); } EXPORT_SYMBOL_GPL(ide_input_data); @@ -271,11 +251,10 @@ void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, ide_hwif_t *hwif = drive->hwif; struct ide_io_ports *io_ports = &hwif->io_ports; unsigned long data_addr = io_ports->data_addr; + unsigned int words = (len + 1) >> 1; u8 io_32bit = drive->io_32bit; u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0; - len++; - if (io_32bit) { unsigned long uninitialized_var(flags); @@ -284,27 +263,26 @@ void ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, void *buf, ata_vlb_sync(io_ports->nsect_addr); } + words >>= 1; if (mmio) - __ide_mm_outsl((void __iomem *)data_addr, buf, len / 4); + __ide_mm_outsl((void __iomem *)data_addr, buf, words); else - outsl(data_addr, buf, len / 4); + outsl(data_addr, buf, words); if ((io_32bit & 2) && !mmio) local_irq_restore(flags); - if ((len & 3) >= 2) { - if (mmio) - __ide_mm_outsw((void __iomem *)data_addr, - (u8 *)buf + (len & ~3), 1); - else - outsw(data_addr, (u8 *)buf + (len & ~3), 1); - } - } else { - if (mmio) - __ide_mm_outsw((void __iomem *)data_addr, buf, len / 2); - else - outsw(data_addr, buf, len / 2); + if (((len + 1) & 3) < 2) + return; + + buf += len & ~3; + words = 1; } + + if (mmio) + __ide_mm_outsw((void __iomem *)data_addr, buf, words); + else + outsw(data_addr, buf, words); } EXPORT_SYMBOL_GPL(ide_output_data); @@ -312,9 +290,9 @@ const struct ide_tp_ops default_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = ide_tf_load, .tf_read = ide_tf_read, diff --git a/trunk/drivers/ide/ide-io.c b/trunk/drivers/ide/ide-io.c index 1adc5e2e7fb3..1deb6d29b186 100644 --- a/trunk/drivers/ide/ide-io.c +++ b/trunk/drivers/ide/ide-io.c @@ -73,6 +73,7 @@ EXPORT_SYMBOL_GPL(ide_end_rq); void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) { + const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops; struct ide_taskfile *tf = &cmd->tf; struct request *rq = cmd->rq; u8 tf_cmd = tf->command; @@ -80,7 +81,16 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) tf->error = err; tf->status = stat; - drive->hwif->tp_ops->tf_read(drive, cmd); + if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { + u8 data[2]; + + tp_ops->input_data(drive, cmd, data, 2); + + tf->data = data[0]; + tf->hob_data = data[1]; + } + + tp_ops->tf_read(drive, cmd); if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) && tf_cmd == ATA_CMD_IDLEIMMEDIATE) { @@ -338,7 +348,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) if (blk_pm_request(rq)) ide_check_pm_state(drive, rq); - SELECT_DRIVE(drive); + drive->hwif->tp_ops->dev_select(drive); if (ide_wait_stat(&startstop, drive, drive->ready_stat, ATA_BUSY | ATA_DRQ, WAIT_READY)) { printk(KERN_ERR "%s: drive not ready for command\n", drive->name); @@ -481,11 +491,10 @@ void do_ide_request(struct request_queue *q) prev_port = hwif->host->cur_port; hwif->rq = NULL; - if (drive->dev_flags & IDE_DFLAG_SLEEPING) { - if (time_before(drive->sleep, jiffies)) { - ide_unlock_port(hwif); - goto plug_device; - } + if (drive->dev_flags & IDE_DFLAG_SLEEPING && + time_after(drive->sleep, jiffies)) { + ide_unlock_port(hwif); + goto plug_device; } if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) && @@ -495,7 +504,9 @@ void do_ide_request(struct request_queue *q) * quirk_list may not like intr setups/cleanups */ if (prev_port && prev_port->cur_dev->quirk_list == 0) - prev_port->tp_ops->set_irq(prev_port, 0); + prev_port->tp_ops->write_devctl(prev_port, + ATA_NIEN | + ATA_DEVCTL_OBS); hwif->host->cur_port = hwif; } diff --git a/trunk/drivers/ide/ide-iops.c b/trunk/drivers/ide/ide-iops.c index 5403e4a44be4..27bb70ddd459 100644 --- a/trunk/drivers/ide/ide-iops.c +++ b/trunk/drivers/ide/ide-iops.c @@ -27,21 +27,6 @@ #include #include -void SELECT_DRIVE(ide_drive_t *drive) -{ - ide_hwif_t *hwif = drive->hwif; - const struct ide_port_ops *port_ops = hwif->port_ops; - struct ide_cmd cmd; - - if (port_ops && port_ops->selectproc) - port_ops->selectproc(drive); - - memset(&cmd, 0, sizeof(cmd)); - cmd.tf_flags = IDE_TFLAG_OUT_DEVICE; - - drive->hwif->tp_ops->tf_load(drive, &cmd); -} - void SELECT_MASK(ide_drive_t *drive, int mask) { const struct ide_port_ops *port_ops = drive->hwif->port_ops; @@ -55,7 +40,7 @@ u8 ide_read_error(ide_drive_t *drive) struct ide_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.tf_flags = IDE_TFLAG_IN_FEATURE; + cmd.tf_flags = IDE_TFLAG_IN_ERROR; drive->hwif->tp_ops->tf_read(drive, &cmd); @@ -306,6 +291,7 @@ int ide_driveid_update(ide_drive_t *drive) drive->id[ATA_ID_UDMA_MODES] = id[ATA_ID_UDMA_MODES]; drive->id[ATA_ID_MWDMA_MODES] = id[ATA_ID_MWDMA_MODES]; drive->id[ATA_ID_SWDMA_MODES] = id[ATA_ID_SWDMA_MODES]; + drive->id[ATA_ID_CFA_MODES] = id[ATA_ID_CFA_MODES]; /* anything more ? */ kfree(id); @@ -356,10 +342,10 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) disable_irq_nosync(hwif->irq); udelay(1); - SELECT_DRIVE(drive); + tp_ops->dev_select(drive); SELECT_MASK(drive, 1); udelay(1); - tp_ops->set_irq(hwif, 0); + tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); memset(&cmd, 0, sizeof(cmd)); cmd.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT; @@ -371,7 +357,7 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) tp_ops->exec_command(hwif, ATA_CMD_SET_FEATURES); if (drive->quirk_list == 2) - tp_ops->set_irq(hwif, 1); + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); error = __ide_wait_stat(drive, drive->ready_stat, ATA_BUSY | ATA_DRQ | ATA_ERR, @@ -386,9 +372,14 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) return error; } - id[ATA_ID_UDMA_MODES] &= ~0xFF00; - id[ATA_ID_MWDMA_MODES] &= ~0x0F00; - id[ATA_ID_SWDMA_MODES] &= ~0x0F00; + if (speed >= XFER_SW_DMA_0) { + id[ATA_ID_UDMA_MODES] &= ~0xFF00; + id[ATA_ID_MWDMA_MODES] &= ~0x0700; + id[ATA_ID_SWDMA_MODES] &= ~0x0700; + if (ata_id_is_cfa(id)) + id[ATA_ID_CFA_MODES] &= ~0x0E00; + } else if (ata_id_is_cfa(id)) + id[ATA_ID_CFA_MODES] &= ~0x01C0; skip: #ifdef CONFIG_BLK_DEV_IDEDMA @@ -401,12 +392,18 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) if (speed >= XFER_UDMA_0) { i = 1 << (speed - XFER_UDMA_0); id[ATA_ID_UDMA_MODES] |= (i << 8 | i); + } else if (ata_id_is_cfa(id) && speed >= XFER_MW_DMA_3) { + i = speed - XFER_MW_DMA_2; + id[ATA_ID_CFA_MODES] |= i << 9; } else if (speed >= XFER_MW_DMA_0) { i = 1 << (speed - XFER_MW_DMA_0); id[ATA_ID_MWDMA_MODES] |= (i << 8 | i); } else if (speed >= XFER_SW_DMA_0) { i = 1 << (speed - XFER_SW_DMA_0); id[ATA_ID_SWDMA_MODES] |= (i << 8 | i); + } else if (ata_id_is_cfa(id) && speed >= XFER_PIO_5) { + i = speed - XFER_PIO_4; + id[ATA_ID_CFA_MODES] |= i << 6; } if (!drive->init_speed) diff --git a/trunk/drivers/ide/ide-pm.c b/trunk/drivers/ide/ide-pm.c index ebf2d21ebdcb..bb7858ebb7d1 100644 --- a/trunk/drivers/ide/ide-pm.c +++ b/trunk/drivers/ide/ide-pm.c @@ -223,6 +223,7 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq) * point. */ ide_hwif_t *hwif = drive->hwif; + const struct ide_tp_ops *tp_ops = hwif->tp_ops; struct request_queue *q = drive->queue; unsigned long flags; int rc; @@ -232,8 +233,8 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq) rc = ide_wait_not_busy(hwif, 35000); if (rc) printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); - SELECT_DRIVE(drive); - hwif->tp_ops->set_irq(hwif, 1); + tp_ops->dev_select(drive); + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); rc = ide_wait_not_busy(hwif, 100000); if (rc) printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); diff --git a/trunk/drivers/ide/ide-probe.c b/trunk/drivers/ide/ide-probe.c index 548864510ba9..d8c1c3e735bb 100644 --- a/trunk/drivers/ide/ide-probe.c +++ b/trunk/drivers/ide/ide-probe.c @@ -260,7 +260,7 @@ int ide_dev_read_id(ide_drive_t *drive, u8 cmd, u16 *id) * during the identify phase that the IRQ handler isn't expecting. */ if (io_ports->ctl_addr) - tp_ops->set_irq(hwif, 0); + tp_ops->write_devctl(hwif, ATA_NIEN | ATA_DEVCTL_OBS); /* take a deep breath */ msleep(50); @@ -390,13 +390,13 @@ static int do_probe (ide_drive_t *drive, u8 cmd) * (e.g. crw9624 as drive0 with disk as slave) */ msleep(50); - SELECT_DRIVE(drive); + tp_ops->dev_select(drive); msleep(50); if (ide_read_device(drive) != drive->select && present == 0) { if (drive->dn & 1) { /* exit with drive0 selected */ - SELECT_DRIVE(hwif->devices[0]); + tp_ops->dev_select(hwif->devices[0]); /* allow ATA_BUSY to assert & clear */ msleep(50); } @@ -422,7 +422,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) printk(KERN_ERR "%s: no response (status = 0x%02x), " "resetting drive\n", drive->name, stat); msleep(50); - SELECT_DRIVE(drive); + tp_ops->dev_select(drive); msleep(50); tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET); (void)ide_busy_sleep(hwif, WAIT_WORSTCASE, 0); @@ -441,7 +441,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) } if (drive->dn & 1) { /* exit with drive0 selected */ - SELECT_DRIVE(hwif->devices[0]); + tp_ops->dev_select(hwif->devices[0]); msleep(50); /* ensure drive irq is clear */ (void)tp_ops->read_status(hwif); @@ -605,6 +605,7 @@ static int ide_register_port(ide_hwif_t *hwif) static int ide_port_wait_ready(ide_hwif_t *hwif) { + const struct ide_tp_ops *tp_ops = hwif->tp_ops; ide_drive_t *drive; int i, rc; @@ -627,8 +628,8 @@ static int ide_port_wait_ready(ide_hwif_t *hwif) /* Ignore disks that we will not probe for later. */ if ((drive->dev_flags & IDE_DFLAG_NOPROBE) == 0 || (drive->dev_flags & IDE_DFLAG_PRESENT)) { - SELECT_DRIVE(drive); - hwif->tp_ops->set_irq(hwif, 1); + tp_ops->dev_select(drive); + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); mdelay(2); rc = ide_wait_not_busy(hwif, 35000); if (rc) @@ -640,7 +641,7 @@ static int ide_port_wait_ready(ide_hwif_t *hwif) out: /* Exit function with master reselected (let's be sane) */ if (i) - SELECT_DRIVE(hwif->devices[0]); + tp_ops->dev_select(hwif->devices[0]); return rc; } @@ -845,7 +846,7 @@ static int init_irq (ide_hwif_t *hwif) irq_handler = ide_intr; if (io_ports->ctl_addr) - hwif->tp_ops->set_irq(hwif, 1); + hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif)) goto out_up; @@ -942,20 +943,16 @@ EXPORT_SYMBOL_GPL(ide_init_disk); static void drive_release_dev (struct device *dev) { ide_drive_t *drive = container_of(dev, ide_drive_t, gendev); - ide_hwif_t *hwif = drive->hwif; ide_proc_unregister_device(drive); - spin_lock_irq(&hwif->lock); + blk_cleanup_queue(drive->queue); + drive->queue = NULL; + kfree(drive->id); drive->id = NULL; + drive->dev_flags &= ~IDE_DFLAG_PRESENT; - /* Messed up locking ... */ - spin_unlock_irq(&hwif->lock); - blk_cleanup_queue(drive->queue); - spin_lock_irq(&hwif->lock); - drive->queue = NULL; - spin_unlock_irq(&hwif->lock); complete(&drive->gendev_rel_comp); } diff --git a/trunk/drivers/ide/ide-tape.c b/trunk/drivers/ide/ide-tape.c index 64dfa7458f8d..cb942a9b580f 100644 --- a/trunk/drivers/ide/ide-tape.c +++ b/trunk/drivers/ide/ide-tape.c @@ -297,19 +297,15 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i) return tape; } -static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, +static int idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount) { struct idetape_bh *bh = pc->bh; int count; while (bcount) { - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_input_buffers\n"); - ide_pad_transfer(drive, 0, bcount); - return; - } + if (bh == NULL) + break; count = min( (unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount); @@ -323,21 +319,21 @@ static void idetape_input_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, atomic_set(&bh->b_count, 0); } } + pc->bh = bh; + + return bcount; } -static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, +static int idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount) { struct idetape_bh *bh = pc->bh; int count; while (bcount) { - if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in %s\n", - __func__); - return; - } + if (bh == NULL) + break; count = min((unsigned int)pc->b_count, (unsigned int)bcount); drive->hwif->tp_ops->output_data(drive, NULL, pc->b_data, count); bcount -= count; @@ -352,6 +348,8 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, } } } + + return bcount; } static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc) @@ -563,12 +561,14 @@ static void ide_tape_handle_dsc(ide_drive_t *drive) static int ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, unsigned int bcount, int write) { + unsigned int bleft; + if (write) - idetape_output_buffers(drive, pc, bcount); + bleft = idetape_output_buffers(drive, pc, bcount); else - idetape_input_buffers(drive, pc, bcount); + bleft = idetape_input_buffers(drive, pc, bcount); - return bcount; + return bcount - bleft; } /* @@ -2014,9 +2014,13 @@ static void idetape_get_inquiry_results(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc pc; + u8 pc_buf[256]; char fw_rev[4], vendor_id[8], product_id[16]; idetape_create_inquiry_cmd(&pc); + pc.buf = &pc_buf[0]; + pc.buf_size = sizeof(pc_buf); + if (ide_queue_pc_tail(drive, tape->disk, &pc)) { printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name); diff --git a/trunk/drivers/ide/ide-taskfile.c b/trunk/drivers/ide/ide-taskfile.c index 84532be97c00..243421ce40d0 100644 --- a/trunk/drivers/ide/ide-taskfile.c +++ b/trunk/drivers/ide/ide-taskfile.c @@ -80,8 +80,14 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { ide_tf_dump(drive->name, tf); - tp_ops->set_irq(hwif, 1); + tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); SELECT_MASK(drive, 0); + + if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { + u8 data[2] = { tf->data, tf->hob_data }; + + tp_ops->output_data(drive, cmd, data, 2); + } tp_ops->tf_load(drive, cmd); } @@ -100,9 +106,7 @@ ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE); return ide_started; case ATA_PROT_DMA: - if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 || - ide_build_sglist(drive, cmd) == 0 || - dma_ops->dma_setup(drive, cmd)) + if (ide_dma_prepare(drive, cmd)) return ide_stopped; hwif->expiry = dma_ops->dma_timer_expiry; ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD); @@ -188,70 +192,68 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) return stat; } -static void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, - unsigned int write, unsigned int nr_bytes) +void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, + unsigned int write, unsigned int len) { ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; struct scatterlist *cursg = cmd->cursg; struct page *page; -#ifdef CONFIG_HIGHMEM unsigned long flags; -#endif unsigned int offset; u8 *buf; cursg = cmd->cursg; - if (!cursg) { - cursg = sg; - cmd->cursg = sg; - } + if (cursg == NULL) + cursg = cmd->cursg = sg; - page = sg_page(cursg); - offset = cursg->offset + cmd->cursg_ofs; + while (len) { + unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs); - /* get the current page and offset */ - page = nth_page(page, (offset >> PAGE_SHIFT)); - offset %= PAGE_SIZE; + if (nr_bytes > PAGE_SIZE) + nr_bytes = PAGE_SIZE; -#ifdef CONFIG_HIGHMEM - local_irq_save(flags); -#endif - buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset; + page = sg_page(cursg); + offset = cursg->offset + cmd->cursg_ofs; - cmd->nleft -= nr_bytes; - cmd->cursg_ofs += nr_bytes; + /* get the current page and offset */ + page = nth_page(page, (offset >> PAGE_SHIFT)); + offset %= PAGE_SIZE; - if (cmd->cursg_ofs == cursg->length) { - cmd->cursg = sg_next(cmd->cursg); - cmd->cursg_ofs = 0; - } + if (PageHighMem(page)) + local_irq_save(flags); - /* do the actual data transfer */ - if (write) - hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes); - else - hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes); + buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset; - kunmap_atomic(buf, KM_BIO_SRC_IRQ); -#ifdef CONFIG_HIGHMEM - local_irq_restore(flags); -#endif -} + cmd->nleft -= nr_bytes; + cmd->cursg_ofs += nr_bytes; -static void ide_pio_multi(ide_drive_t *drive, struct ide_cmd *cmd, - unsigned int write) -{ - unsigned int nsect; + if (cmd->cursg_ofs == cursg->length) { + cursg = cmd->cursg = sg_next(cmd->cursg); + cmd->cursg_ofs = 0; + } + + /* do the actual data transfer */ + if (write) + hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes); + else + hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes); + + kunmap_atomic(buf, KM_BIO_SRC_IRQ); - nsect = min_t(unsigned int, cmd->nleft >> 9, drive->mult_count); - while (nsect--) - ide_pio_bytes(drive, cmd, write, SECTOR_SIZE); + if (PageHighMem(page)) + local_irq_restore(flags); + + len -= nr_bytes; + } } +EXPORT_SYMBOL_GPL(ide_pio_bytes); static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd, unsigned int write) { + unsigned int nr_bytes; + u8 saved_io_32bit = drive->io_32bit; if (cmd->tf_flags & IDE_TFLAG_FS) @@ -263,9 +265,11 @@ static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd, touch_softlockup_watchdog(); if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) - ide_pio_multi(drive, cmd, write); + nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9); else - ide_pio_bytes(drive, cmd, write, SECTOR_SIZE); + nr_bytes = SECTOR_SIZE; + + ide_pio_bytes(drive, cmd, write, nr_bytes); drive->io_32bit = saved_io_32bit; } diff --git a/trunk/drivers/ide/ide-timings.c b/trunk/drivers/ide/ide-timings.c index 81f527af8fae..001a56365be5 100644 --- a/trunk/drivers/ide/ide-timings.c +++ b/trunk/drivers/ide/ide-timings.c @@ -43,6 +43,8 @@ static struct ide_timing ide_timing[] = { { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 }, + { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 }, { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, @@ -51,7 +53,8 @@ static struct ide_timing ide_timing[] = { { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, - { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, + { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 }, + { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 }, { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, @@ -90,6 +93,10 @@ u16 ide_pio_cycle_time(ide_drive_t *drive, u8 pio) /* conservative "downgrade" for all pre-ATA2 drives */ if (pio < 3 && cycle < t->cycle) cycle = 0; /* use standard timing */ + + /* Use the standard timing for the CF specific modes too */ + if (pio > 4 && ata_id_is_cfa(id)) + cycle = 0; } return cycle ? cycle : t->cycle; @@ -161,7 +168,8 @@ int ide_timing_compute(ide_drive_t *drive, u8 speed, if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO]; - else if (speed <= XFER_PIO_5) + else if ((speed <= XFER_PIO_4) || + (speed == XFER_PIO_5 && !ata_id_is_cfa(id))) p.cycle = p.cyc8b = id[ATA_ID_EIDE_PIO_IORDY]; else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) p.cycle = id[ATA_ID_EIDE_DMA_MIN]; diff --git a/trunk/drivers/ide/ide-xfer-mode.c b/trunk/drivers/ide/ide-xfer-mode.c index 6910f6a257e8..af44be9d546c 100644 --- a/trunk/drivers/ide/ide-xfer-mode.c +++ b/trunk/drivers/ide/ide-xfer-mode.c @@ -9,11 +9,11 @@ static const char *udma_str[] = { "UDMA/16", "UDMA/25", "UDMA/33", "UDMA/44", "UDMA/66", "UDMA/100", "UDMA/133", "UDMA7" }; static const char *mwdma_str[] = - { "MWDMA0", "MWDMA1", "MWDMA2" }; + { "MWDMA0", "MWDMA1", "MWDMA2", "MWDMA3", "MWDMA4" }; static const char *swdma_str[] = { "SWDMA0", "SWDMA1", "SWDMA2" }; static const char *pio_str[] = - { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5" }; + { "PIO0", "PIO1", "PIO2", "PIO3", "PIO4", "PIO5", "PIO6" }; /** * ide_xfer_verbose - return IDE mode names @@ -30,11 +30,11 @@ const char *ide_xfer_verbose(u8 mode) if (mode >= XFER_UDMA_0 && mode <= XFER_UDMA_7) s = udma_str[i]; - else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_2) + else if (mode >= XFER_MW_DMA_0 && mode <= XFER_MW_DMA_4) s = mwdma_str[i]; else if (mode >= XFER_SW_DMA_0 && mode <= XFER_SW_DMA_2) s = swdma_str[i]; - else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_5) + else if (mode >= XFER_PIO_0 && mode <= XFER_PIO_6) s = pio_str[i & 0x7]; else if (mode == XFER_PIO_SLOW) s = "PIO SLOW"; @@ -79,7 +79,10 @@ u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode) } if (id[ATA_ID_FIELD_VALID] & 2) { /* ATA2? */ - if (ata_id_has_iordy(id)) { + if (ata_id_is_cfa(id) && (id[ATA_ID_CFA_MODES] & 7)) + pio_mode = 4 + min_t(int, 2, + id[ATA_ID_CFA_MODES] & 7); + else if (ata_id_has_iordy(id)) { if (id[ATA_ID_PIO_MODES] & 7) { overridden = 0; if (id[ATA_ID_PIO_MODES] & 4) @@ -239,7 +242,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) BUG_ON(rate < XFER_PIO_0); - if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) + if (rate >= XFER_PIO_0 && rate <= XFER_PIO_6) return ide_set_pio_mode(drive, rate); return ide_set_dma_mode(drive, rate); diff --git a/trunk/drivers/ide/ide_arm.c b/trunk/drivers/ide/ide_arm.c deleted file mode 100644 index cf6385446ece..000000000000 --- a/trunk/drivers/ide/ide_arm.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * ARM default IDE host driver - * - * Copyright (C) 2004 Bartlomiej Zolnierkiewicz - * Based on code by: Russell King, Ian Molton and Alexander Schulz. - * - * May be copied or modified under the terms of the GNU General Public License. - */ - -#include -#include -#include - -#include - -#define DRV_NAME "ide_arm" - -#define IDE_ARM_IO 0x1f0 -#define IDE_ARM_IRQ IRQ_HARDDISK - -static const struct ide_port_info ide_arm_port_info = { - .host_flags = IDE_HFLAG_NO_DMA, -}; - -static int __init ide_arm_init(void) -{ - unsigned long base = IDE_ARM_IO, ctl = IDE_ARM_IO + 0x206; - hw_regs_t hw, *hws[] = { &hw, NULL, NULL, NULL }; - - if (!request_region(base, 8, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n", - DRV_NAME, base, base + 7); - return -EBUSY; - } - - if (!request_region(ctl, 1, DRV_NAME)) { - printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n", - DRV_NAME, ctl); - release_region(base, 8); - return -EBUSY; - } - - memset(&hw, 0, sizeof(hw)); - ide_std_init_ports(&hw, base, ctl); - hw.irq = IDE_ARM_IRQ; - hw.chipset = ide_generic; - - return ide_host_add(&ide_arm_port_info, hws, NULL); -} - -module_init(ide_arm_init); - -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/ide/it821x.c b/trunk/drivers/ide/it821x.c index 0d4ac65cf949..51aa745246dc 100644 --- a/trunk/drivers/ide/it821x.c +++ b/trunk/drivers/ide/it821x.c @@ -511,9 +511,8 @@ static struct ide_dma_ops it821x_pass_through_dma_ops = { .dma_start = it821x_dma_start, .dma_end = it821x_dma_end, .dma_test_irq = ide_dma_test_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_lost_irq = ide_dma_lost_irq, + .dma_timer_expiry = ide_dma_sff_timer_expiry, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/ns87415.c b/trunk/drivers/ide/ns87415.c index 7b65fe5bf449..71a39fb3856f 100644 --- a/trunk/drivers/ide/ns87415.c +++ b/trunk/drivers/ide/ns87415.c @@ -66,18 +66,11 @@ static void superio_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) struct ide_io_ports *io_ports = &drive->hwif->io_ports; struct ide_taskfile *tf = &cmd->tf; - if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { - u16 data = inw(io_ports->data_addr); - - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - /* be sure we're looking at the low order bits */ - outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); + outb(ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE) - tf->feature = inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_ERROR) + tf->error = inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_NSECT) tf->nsect = inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_LBAL) @@ -90,28 +83,30 @@ static void superio_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) tf->device = superio_ide_inb(io_ports->device_addr); if (cmd->tf_flags & IDE_TFLAG_LBA48) { - outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); + outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR) + tf->hob_error = inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = inb(io_ports->nsect_addr); + tf->hob_nsect = inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = inb(io_ports->lbal_addr); + tf->hob_lbal = inb(io_ports->lbal_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = inb(io_ports->lbam_addr); + tf->hob_lbam = inb(io_ports->lbam_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = inb(io_ports->lbah_addr); + tf->hob_lbah = inb(io_ports->lbah_addr); } } +static void ns87415_dev_select(ide_drive_t *drive); + static const struct ide_tp_ops superio_tp_ops = { .exec_command = ide_exec_command, .read_status = superio_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ns87415_dev_select, .tf_load = ide_tf_load, .tf_read = superio_tf_read, @@ -190,10 +185,18 @@ static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma) local_irq_restore(flags); } -static void ns87415_selectproc (ide_drive_t *drive) +static void ns87415_dev_select(ide_drive_t *drive) { ns87415_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA)); + + outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); +} + +static void ns87415_dma_start(ide_drive_t *drive) +{ + ns87415_prepare_drive(drive, 1); + ide_dma_start(drive); } static int ns87415_dma_end(ide_drive_t *drive) @@ -201,7 +204,6 @@ static int ns87415_dma_end(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; u8 dma_stat = 0, dma_cmd = 0; - drive->waiting_for_dma = 0; dma_stat = hwif->dma_ops->dma_sff_read_status(hwif); /* get DMA command mode */ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); @@ -210,21 +212,11 @@ static int ns87415_dma_end(ide_drive_t *drive) /* from ERRATA: clear the INTR & ERROR bits */ dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); outb(dma_cmd | 6, hwif->dma_base + ATA_DMA_CMD); - /* and free any DMA resources */ - ide_destroy_dmatable(drive); - /* verify good DMA status */ - return (dma_stat & 7) != 4; -} -static int ns87415_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) -{ - /* select DMA xfer */ - ns87415_prepare_drive(drive, 1); - if (ide_dma_setup(drive, cmd) == 0) - return 0; - /* DMA failed: select PIO xfer */ ns87415_prepare_drive(drive, 0); - return 1; + + /* verify good DMA status */ + return (dma_stat & 7) != 4; } static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) @@ -242,7 +234,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) * Also, leave IRQ masked during drive probing, to prevent infinite * interrupts from a potentially floating INTA.. * - * IRQs get unmasked in selectproc when drive is first used. + * IRQs get unmasked in dev_select() when drive is first used. */ (void) pci_read_config_dword(dev, 0x40, &ctrl); (void) pci_read_config_byte(dev, 0x09, &progif); @@ -270,7 +262,7 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) #ifdef __sparc_v9__ /* * XXX: Reset the device, if we don't it will not respond to - * SELECT_DRIVE() properly during first ide_probe_port(). + * dev_select() properly during first ide_probe_port(). */ timeout = 10000; outb(12, hwif->io_ports.ctl_addr); @@ -294,26 +286,35 @@ static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif) outb(0x60, hwif->dma_base + ATA_DMA_STATUS); } -static const struct ide_port_ops ns87415_port_ops = { - .selectproc = ns87415_selectproc, +static const struct ide_tp_ops ns87415_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = ns87415_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, }; static const struct ide_dma_ops ns87415_dma_ops = { .dma_host_set = ide_dma_host_set, - .dma_setup = ns87415_dma_setup, - .dma_start = ide_dma_start, + .dma_setup = ide_dma_setup, + .dma_start = ns87415_dma_start, .dma_end = ns87415_dma_end, .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = superio_dma_sff_read_status, }; static const struct ide_port_info ns87415_chipset __devinitdata = { .name = DRV_NAME, .init_hwif = init_hwif_ns87415, - .port_ops = &ns87415_port_ops, + .tp_ops = &ns87415_tp_ops, .dma_ops = &ns87415_dma_ops, .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA | IDE_HFLAG_NO_ATAPI_DMA, diff --git a/trunk/drivers/ide/pdc202xx_old.c b/trunk/drivers/ide/pdc202xx_old.c index f7536d1943f7..248a54bd2386 100644 --- a/trunk/drivers/ide/pdc202xx_old.c +++ b/trunk/drivers/ide/pdc202xx_old.c @@ -258,12 +258,6 @@ static void pdc202xx_dma_lost_irq(ide_drive_t *drive) ide_dma_lost_irq(drive); } -static void pdc202xx_dma_timeout(ide_drive_t *drive) -{ - pdc202xx_reset(drive); - ide_dma_timeout(drive); -} - static int init_chipset_pdc202xx(struct pci_dev *dev) { unsigned long dmabase = pci_resource_start(dev, 4); @@ -336,7 +330,7 @@ static const struct ide_dma_ops pdc20246_dma_ops = { .dma_test_irq = pdc202xx_dma_test_irq, .dma_lost_irq = pdc202xx_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = pdc202xx_dma_timeout, + .dma_clear = pdc202xx_reset, .dma_sff_read_status = ide_dma_sff_read_status, }; @@ -348,7 +342,7 @@ static const struct ide_dma_ops pdc2026x_dma_ops = { .dma_test_irq = pdc202xx_dma_test_irq, .dma_lost_irq = pdc202xx_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = pdc202xx_dma_timeout, + .dma_clear = pdc202xx_reset, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/pmac.c b/trunk/drivers/ide/pmac.c index 2bfcfedaa076..052b9bf1f8fb 100644 --- a/trunk/drivers/ide/pmac.c +++ b/trunk/drivers/ide/pmac.c @@ -404,8 +404,6 @@ kauai_lookup_timing(struct kauai_timing* table, int cycle_time) #define IDE_WAKEUP_DELAY (1*HZ) static int pmac_ide_init_dma(ide_hwif_t *, const struct ide_port_info *); -static void pmac_ide_selectproc(ide_drive_t *drive); -static void pmac_ide_kauai_selectproc(ide_drive_t *drive); #define PMAC_IDE_REG(x) \ ((void __iomem *)((drive)->hwif->io_ports.data_addr + (x))) @@ -415,8 +413,7 @@ static void pmac_ide_kauai_selectproc(ide_drive_t *drive); * timing register when selecting that unit. This version is for * ASICs with a single timing register */ -static void -pmac_ide_selectproc(ide_drive_t *drive) +static void pmac_ide_apply_timings(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; pmac_ide_hwif_t *pmif = @@ -434,8 +431,7 @@ pmac_ide_selectproc(ide_drive_t *drive) * timing register when selecting that unit. This version is for * ASICs with a dual timing register (Kauai) */ -static void -pmac_ide_kauai_selectproc(ide_drive_t *drive) +static void pmac_ide_kauai_apply_timings(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; pmac_ide_hwif_t *pmif = @@ -464,9 +460,25 @@ pmac_ide_do_update_timings(ide_drive_t *drive) if (pmif->kind == controller_sh_ata6 || pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6) - pmac_ide_kauai_selectproc(drive); + pmac_ide_kauai_apply_timings(drive); else - pmac_ide_selectproc(drive); + pmac_ide_apply_timings(drive); +} + +static void pmac_dev_select(ide_drive_t *drive) +{ + pmac_ide_apply_timings(drive); + + writeb(drive->select | ATA_DEVICE_OBS, + (void __iomem *)drive->hwif->io_ports.device_addr); +} + +static void pmac_kauai_dev_select(ide_drive_t *drive) +{ + pmac_ide_kauai_apply_timings(drive); + + writeb(drive->select | ATA_DEVICE_OBS, + (void __iomem *)drive->hwif->io_ports.device_addr); } static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd) @@ -476,17 +488,8 @@ static void pmac_exec_command(ide_hwif_t *hwif, u8 cmd) + IDE_TIMING_CONFIG)); } -static void pmac_set_irq(ide_hwif_t *hwif, int on) +static void pmac_write_devctl(ide_hwif_t *hwif, u8 ctl) { - u8 ctl = ATA_DEVCTL_OBS; - - if (on == 4) { /* hack for SRST */ - ctl |= 4; - on &= ~4; - } - - ctl |= on ? 0 : 2; - writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr); (void)readl((void __iomem *)(hwif->io_ports.data_addr + IDE_TIMING_CONFIG)); @@ -916,10 +919,18 @@ static u8 pmac_ide_cable_detect(ide_hwif_t *hwif) (pmac_ide_hwif_t *)dev_get_drvdata(hwif->gendev.parent); struct device_node *np = pmif->node; const char *cable = of_get_property(np, "cable-type", NULL); + struct device_node *root = of_find_node_by_path("/"); + const char *model = of_get_property(root, "model", NULL); /* Get cable type from device-tree. */ - if (cable && !strncmp(cable, "80-", 3)) - return ATA_CBL_PATA80; + if (cable && !strncmp(cable, "80-", 3)) { + /* Some drives fail to detect 80c cable in PowerBook */ + /* These machine use proprietary short IDE cable anyway */ + if (!strncmp(model, "PowerBook", 9)) + return ATA_CBL_PATA40_SHORT; + else + return ATA_CBL_PATA80; + } /* * G5's seem to have incorrect cable type in device-tree. @@ -954,9 +965,9 @@ static const struct ide_tp_ops pmac_tp_ops = { .exec_command = pmac_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = pmac_write_devctl, - .set_irq = pmac_set_irq, - + .dev_select = pmac_dev_select, .tf_load = ide_tf_load, .tf_read = ide_tf_read, @@ -964,19 +975,24 @@ static const struct ide_tp_ops pmac_tp_ops = { .output_data = ide_output_data, }; -static const struct ide_port_ops pmac_ide_ata6_port_ops = { - .init_dev = pmac_ide_init_dev, - .set_pio_mode = pmac_ide_set_pio_mode, - .set_dma_mode = pmac_ide_set_dma_mode, - .selectproc = pmac_ide_kauai_selectproc, - .cable_detect = pmac_ide_cable_detect, +static const struct ide_tp_ops pmac_ata6_tp_ops = { + .exec_command = pmac_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = pmac_write_devctl, + + .dev_select = pmac_kauai_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, }; static const struct ide_port_ops pmac_ide_ata4_port_ops = { .init_dev = pmac_ide_init_dev, .set_pio_mode = pmac_ide_set_pio_mode, .set_dma_mode = pmac_ide_set_dma_mode, - .selectproc = pmac_ide_selectproc, .cable_detect = pmac_ide_cable_detect, }; @@ -984,7 +1000,6 @@ static const struct ide_port_ops pmac_ide_port_ops = { .init_dev = pmac_ide_init_dev, .set_pio_mode = pmac_ide_set_pio_mode, .set_dma_mode = pmac_ide_set_dma_mode, - .selectproc = pmac_ide_selectproc, }; static const struct ide_dma_ops pmac_dma_ops; @@ -1021,15 +1036,18 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) pmif->broken_dma = pmif->broken_dma_warn = 0; if (of_device_is_compatible(np, "shasta-ata")) { pmif->kind = controller_sh_ata6; - d.port_ops = &pmac_ide_ata6_port_ops; + d.tp_ops = &pmac_ata6_tp_ops; + d.port_ops = &pmac_ide_ata4_port_ops; d.udma_mask = ATA_UDMA6; } else if (of_device_is_compatible(np, "kauai-ata")) { pmif->kind = controller_un_ata6; - d.port_ops = &pmac_ide_ata6_port_ops; + d.tp_ops = &pmac_ata6_tp_ops; + d.port_ops = &pmac_ide_ata4_port_ops; d.udma_mask = ATA_UDMA5; } else if (of_device_is_compatible(np, "K2-UATA")) { pmif->kind = controller_k2_ata6; - d.port_ops = &pmac_ide_ata6_port_ops; + d.tp_ops = &pmac_ata6_tp_ops; + d.port_ops = &pmac_ide_ata4_port_ops; d.udma_mask = ATA_UDMA5; } else if (of_device_is_compatible(np, "keylargo-ata")) { if (strcmp(np->name, "ata-4") == 0) { @@ -1455,7 +1473,7 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) "switching to PIO on Ohare chipset\n", drive->name); pmif->broken_dma_warn = 1; } - goto use_pio_instead; + return 0; } while (cur_len) { unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00; @@ -1463,7 +1481,7 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) if (count++ >= MAX_DCMDS) { printk(KERN_WARNING "%s: DMA table too small\n", drive->name); - goto use_pio_instead; + return 0; } st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE); st_le16(&table->req_count, tc); @@ -1492,9 +1510,6 @@ static int pmac_ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name); -use_pio_instead: - ide_destroy_dmatable(drive); - return 0; /* revert to PIO for this request */ } @@ -1510,10 +1525,8 @@ static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) u8 unit = drive->dn & 1, ata4 = (pmif->kind == controller_kl_ata4); u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); - if (pmac_ide_build_dmatable(drive, cmd) == 0) { - ide_map_sg(drive, cmd); + if (pmac_ide_build_dmatable(drive, cmd) == 0) return 1; - } /* Apple adds 60ns to wrDataSetup on reads */ if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) { @@ -1522,8 +1535,6 @@ static int pmac_ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) (void)readl(PMAC_IDE_REG(IDE_TIMING_CONFIG)); } - drive->waiting_for_dma = 1; - return 0; } @@ -1558,12 +1569,9 @@ pmac_ide_dma_end (ide_drive_t *drive) volatile struct dbdma_regs __iomem *dma = pmif->dma_regs; u32 dstat; - drive->waiting_for_dma = 0; dstat = readl(&dma->status); writel(((RUN|WAKE|DEAD) << 16), &dma->control); - ide_destroy_dmatable(drive); - /* verify good dma status. we don't check for ACTIVE beeing 0. We should... * in theory, but with ATAPI decices doing buffer underruns, that would * cause us to disable DMA, which isn't what we want @@ -1650,7 +1658,6 @@ static const struct ide_dma_ops pmac_dma_ops = { .dma_start = pmac_ide_dma_start, .dma_end = pmac_ide_dma_end, .dma_test_irq = pmac_ide_dma_test_irq, - .dma_timeout = ide_dma_timeout, .dma_lost_irq = pmac_ide_dma_lost_irq, }; diff --git a/trunk/drivers/ide/q40ide.c b/trunk/drivers/ide/q40ide.c index 2a43a2f49633..d007e7f66598 100644 --- a/trunk/drivers/ide/q40ide.c +++ b/trunk/drivers/ide/q40ide.c @@ -99,9 +99,9 @@ static const struct ide_tp_ops q40ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = ide_tf_load, .tf_read = ide_tf_read, diff --git a/trunk/drivers/ide/qd65xx.c b/trunk/drivers/ide/qd65xx.c index 08c4fa35e9b1..c9a134986891 100644 --- a/trunk/drivers/ide/qd65xx.c +++ b/trunk/drivers/ide/qd65xx.c @@ -90,13 +90,15 @@ static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */ * This routine is invoked to prepare for access to a given drive. */ -static void qd65xx_select(ide_drive_t *drive) +static void qd65xx_dev_select(ide_drive_t *drive) { u8 index = (( (QD_TIMREG(drive)) & 0x80 ) >> 7) | (QD_TIMREG(drive) & 0x02); if (timings[index] != QD_TIMING(drive)) outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive)); + + outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); } /* @@ -309,20 +311,33 @@ static void __init qd6580_init_dev(ide_drive_t *drive) drive->drive_data = (drive->dn & 1) ? t2 : t1; } +static const struct ide_tp_ops qd65xx_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = qd65xx_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, +}; + static const struct ide_port_ops qd6500_port_ops = { .init_dev = qd6500_init_dev, .set_pio_mode = qd6500_set_pio_mode, - .selectproc = qd65xx_select, }; static const struct ide_port_ops qd6580_port_ops = { .init_dev = qd6580_init_dev, .set_pio_mode = qd6580_set_pio_mode, - .selectproc = qd65xx_select, }; static const struct ide_port_info qd65xx_port_info __initdata = { .name = DRV_NAME, + .tp_ops = &qd65xx_tp_ops, .chipset = ide_qd65xx, .host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_NO_DMA, diff --git a/trunk/drivers/ide/sc1200.c b/trunk/drivers/ide/sc1200.c index 1c3a82914999..d467478d68da 100644 --- a/trunk/drivers/ide/sc1200.c +++ b/trunk/drivers/ide/sc1200.c @@ -115,8 +115,7 @@ static u8 sc1200_udma_filter(ide_drive_t *drive) if ((mateid[ATA_ID_FIELD_VALID] & 4) && (mateid[ATA_ID_UDMA_MODES] & 7)) goto out; - if ((mateid[ATA_ID_FIELD_VALID] & 2) && - (mateid[ATA_ID_MWDMA_MODES] & 7)) + if (mateid[ATA_ID_MWDMA_MODES] & 7) mask = 0; } out: @@ -183,9 +182,6 @@ static int sc1200_dma_end(ide_drive_t *drive) outb(dma_stat|0x1b, dma_base+2); /* clear the INTR & ERROR bits */ outb(inb(dma_base)&~1, dma_base); /* !! DO THIS HERE !! stop DMA */ - drive->waiting_for_dma = 0; - ide_destroy_dmatable(drive); /* purge DMA mappings */ - return (dma_stat & 7) != 4; /* verify good DMA status */ } @@ -291,7 +287,6 @@ static const struct ide_dma_ops sc1200_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/scc_pata.c b/trunk/drivers/ide/scc_pata.c index 0cc137cfe76d..6d8dbd9c10bc 100644 --- a/trunk/drivers/ide/scc_pata.c +++ b/trunk/drivers/ide/scc_pata.c @@ -148,17 +148,8 @@ static u8 scc_dma_sff_read_status(ide_hwif_t *hwif) return (u8)in_be32((void *)(hwif->dma_base + 4)); } -static void scc_set_irq(ide_hwif_t *hwif, int on) +static void scc_write_devctl(ide_hwif_t *hwif, u8 ctl) { - u8 ctl = ATA_DEVCTL_OBS; - - if (on == 4) { /* hack for SRST */ - ctl |= 4; - on &= ~4; - } - - ctl |= on ? 0 : 2; - out_be32((void *)hwif->io_ports.ctl_addr, ctl); eieio(); in_be32((void *)(hwif->dma_base + 0x01c)); @@ -321,10 +312,8 @@ static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) u8 dma_stat; /* fall back to pio! */ - if (ide_build_dmatable(drive, cmd) == 0) { - ide_map_sg(drive, cmd); + if (ide_build_dmatable(drive, cmd) == 0) return 1; - } /* PRD table */ out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma); @@ -337,7 +326,7 @@ static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) /* clear INTR & ERROR flags */ out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6); - drive->waiting_for_dma = 1; + return 0; } @@ -356,7 +345,6 @@ static int __scc_dma_end(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; u8 dma_stat, dma_cmd; - drive->waiting_for_dma = 0; /* get DMA command mode */ dma_cmd = scc_ide_inb(hwif->dma_base); /* stop DMA */ @@ -365,8 +353,6 @@ static int __scc_dma_end(ide_drive_t *drive) dma_stat = scc_dma_sff_read_status(hwif); /* clear the INTR & ERROR bits */ scc_ide_outb(dma_stat | 6, hwif->dma_base + 4); - /* purge DMA mappings */ - ide_destroy_dmatable(drive); /* verify good DMA status */ wmb(); return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0; @@ -670,10 +656,6 @@ static void scc_tf_load(ide_drive_t *drive, struct ide_cmd *cmd) if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED) HIHI = 0xFF; - if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) - out_be32((void *)io_ports->data_addr, - (tf->hob_data << 8) | tf->data); - if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) scc_ide_outb(tf->hob_feature, io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) @@ -706,18 +688,11 @@ static void scc_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) struct ide_io_ports *io_ports = &drive->hwif->io_ports; struct ide_taskfile *tf = &cmd->tf; - if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { - u16 data = (u16)in_be32((void *)io_ports->data_addr); - - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - /* be sure we're looking at the low order bits */ - scc_ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); + scc_ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE) - tf->feature = scc_ide_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_ERROR) + tf->error = scc_ide_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_NSECT) tf->nsect = scc_ide_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_LBAL) @@ -730,18 +705,18 @@ static void scc_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) tf->device = scc_ide_inb(io_ports->device_addr); if (cmd->tf_flags & IDE_TFLAG_LBA48) { - scc_ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); + scc_ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = scc_ide_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR) + tf->hob_error = scc_ide_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr); + tf->hob_nsect = scc_ide_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = scc_ide_inb(io_ports->lbal_addr); + tf->hob_lbal = scc_ide_inb(io_ports->lbal_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = scc_ide_inb(io_ports->lbam_addr); + tf->hob_lbam = scc_ide_inb(io_ports->lbam_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = scc_ide_inb(io_ports->lbah_addr); + tf->hob_lbah = scc_ide_inb(io_ports->lbah_addr); } } @@ -848,9 +823,9 @@ static const struct ide_tp_ops scc_tp_ops = { .exec_command = scc_exec_command, .read_status = scc_read_status, .read_altstatus = scc_read_altstatus, + .write_devctl = scc_write_devctl, - .set_irq = scc_set_irq, - + .dev_select = ide_dev_select, .tf_load = scc_tf_load, .tf_read = scc_tf_read, @@ -872,7 +847,6 @@ static const struct ide_dma_ops scc_dma_ops = { .dma_end = scc_dma_end, .dma_test_irq = scc_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, - .dma_timeout = ide_dma_timeout, .dma_timer_expiry = ide_dma_sff_timer_expiry, .dma_sff_read_status = scc_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/sgiioc4.c b/trunk/drivers/ide/sgiioc4.c index b12de8346c73..e5d2a48a84de 100644 --- a/trunk/drivers/ide/sgiioc4.c +++ b/trunk/drivers/ide/sgiioc4.c @@ -258,9 +258,6 @@ static int sgiioc4_dma_end(ide_drive_t *drive) } } - drive->waiting_for_dma = 0; - ide_destroy_dmatable(drive); - return dma_stat; } @@ -280,10 +277,12 @@ static void sgiioc4_dma_host_set(ide_drive_t *drive, int on) sgiioc4_clearirq(drive); } -static void -sgiioc4_resetproc(ide_drive_t * drive) +static void sgiioc4_resetproc(ide_drive_t *drive) { + struct ide_cmd *cmd = &drive->hwif->cmd; + sgiioc4_dma_end(drive); + ide_dma_unmap_sg(drive, cmd); sgiioc4_clearirq(drive); } @@ -412,7 +411,6 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4)); writel(dma_direction, (void __iomem *)ioc4_dma_addr); - drive->waiting_for_dma = 1; } /* IOC4 Scatter Gather list Format */ @@ -442,7 +440,7 @@ static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) printk(KERN_WARNING "%s: DMA table too small\n", drive->name); - goto use_pio_instead; + return 0; } else { u32 bcount = 0x10000 - (cur_addr & 0xffff); @@ -477,9 +475,6 @@ static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) return count; } -use_pio_instead: - ide_destroy_dmatable(drive); - return 0; /* revert to PIO for this request */ } @@ -488,11 +483,9 @@ static int sgiioc4_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) int ddir; u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); - if (sgiioc4_build_dmatable(drive, cmd) == 0) { + if (sgiioc4_build_dmatable(drive, cmd) == 0) /* try PIO instead of DMA */ - ide_map_sg(drive, cmd); return 1; - } if (write) /* Writes TO the IOC4 FROM Main Memory */ @@ -510,9 +503,9 @@ static const struct ide_tp_ops sgiioc4_tp_ops = { .exec_command = ide_exec_command, .read_status = sgiioc4_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = ide_tf_load, .tf_read = ide_tf_read, @@ -533,7 +526,6 @@ static const struct ide_dma_ops sgiioc4_dma_ops = { .dma_end = sgiioc4_dma_end, .dma_test_irq = sgiioc4_dma_test_irq, .dma_lost_irq = sgiioc4_dma_lost_irq, - .dma_timeout = ide_dma_timeout, }; static const struct ide_port_info sgiioc4_port_info __devinitconst = { diff --git a/trunk/drivers/ide/siimage.c b/trunk/drivers/ide/siimage.c index 075cb1243b2a..e4973cd1fba9 100644 --- a/trunk/drivers/ide/siimage.c +++ b/trunk/drivers/ide/siimage.c @@ -715,7 +715,6 @@ static const struct ide_dma_ops sil_dma_ops = { .dma_end = ide_dma_end, .dma_test_irq = siimage_dma_test_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_lost_irq = ide_dma_lost_irq, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/sl82c105.c b/trunk/drivers/ide/sl82c105.c index d25137b04e7a..b0a460625335 100644 --- a/trunk/drivers/ide/sl82c105.c +++ b/trunk/drivers/ide/sl82c105.c @@ -61,7 +61,8 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) if (cmd_off == 0) cmd_off = 1; - if (pio > 2 || ata_id_has_iordy(drive->id)) + if ((pio > 2 || ata_id_has_iordy(drive->id)) && + !(pio > 4 && ata_id_is_cfa(drive->id))) iordy = 0x40; return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy; @@ -189,14 +190,13 @@ static void sl82c105_dma_start(ide_drive_t *drive) ide_dma_start(drive); } -static void sl82c105_dma_timeout(ide_drive_t *drive) +static void sl82c105_dma_clear(ide_drive_t *drive) { struct pci_dev *dev = to_pci_dev(drive->hwif->dev); - DBG(("sl82c105_dma_timeout(drive:%s)\n", drive->name)); + DBG(("sl82c105_dma_clear(drive:%s)\n", drive->name)); sl82c105_reset_host(dev); - ide_dma_timeout(drive); } static int sl82c105_dma_end(ide_drive_t *drive) @@ -298,7 +298,7 @@ static const struct ide_dma_ops sl82c105_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = sl82c105_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = sl82c105_dma_timeout, + .dma_clear = sl82c105_dma_clear, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/tc86c001.c b/trunk/drivers/ide/tc86c001.c index 427d4b3c2c63..b4cf42dc8a6f 100644 --- a/trunk/drivers/ide/tc86c001.c +++ b/trunk/drivers/ide/tc86c001.c @@ -187,7 +187,6 @@ static const struct ide_dma_ops tc86c001_dma_ops = { .dma_test_irq = ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = ide_dma_sff_read_status, }; diff --git a/trunk/drivers/ide/trm290.c b/trunk/drivers/ide/trm290.c index ed1496845a93..4b42ca091534 100644 --- a/trunk/drivers/ide/trm290.c +++ b/trunk/drivers/ide/trm290.c @@ -171,54 +171,51 @@ static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma) local_irq_restore(flags); } -static void trm290_selectproc (ide_drive_t *drive) +static void trm290_dev_select(ide_drive_t *drive) { trm290_prepare_drive(drive, !!(drive->dev_flags & IDE_DFLAG_USING_DMA)); + + outb(drive->select | ATA_DEVICE_OBS, drive->hwif->io_ports.device_addr); } -static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) +static int trm290_dma_check(ide_drive_t *drive, struct ide_cmd *cmd) { - ide_hwif_t *hwif = drive->hwif; - unsigned int count, rw; - if (cmd->tf_flags & IDE_TFLAG_WRITE) { #ifdef TRM290_NO_DMA_WRITES /* always use PIO for writes */ - trm290_prepare_drive(drive, 0); /* select PIO xfer */ return 1; #endif - rw = 1; - } else - rw = 2; + } + return 0; +} + +static int trm290_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) +{ + ide_hwif_t *hwif = drive->hwif; + unsigned int count, rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 1 : 2; count = ide_build_dmatable(drive, cmd); - if (count == 0) { - ide_map_sg(drive, cmd); + if (count == 0) /* try PIO instead of DMA */ - trm290_prepare_drive(drive, 0); /* select PIO xfer */ return 1; - } - /* select DMA xfer */ - trm290_prepare_drive(drive, 1); + outl(hwif->dmatable_dma | rw, hwif->dma_base); - drive->waiting_for_dma = 1; /* start DMA */ outw(count * 2 - 1, hwif->dma_base + 2); + return 0; } static void trm290_dma_start(ide_drive_t *drive) { + trm290_prepare_drive(drive, 1); } static int trm290_dma_end(ide_drive_t *drive) { - u16 status; + u16 status = inw(drive->hwif->dma_base + 2); - drive->waiting_for_dma = 0; - /* purge DMA mappings */ - ide_destroy_dmatable(drive); - status = inw(drive->hwif->dma_base + 2); + trm290_prepare_drive(drive, 0); return status != 0x00ff; } @@ -303,8 +300,18 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) #endif } -static const struct ide_port_ops trm290_port_ops = { - .selectproc = trm290_selectproc, +static const struct ide_tp_ops trm290_tp_ops = { + .exec_command = ide_exec_command, + .read_status = ide_read_status, + .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, + + .dev_select = trm290_dev_select, + .tf_load = ide_tf_load, + .tf_read = ide_tf_read, + + .input_data = ide_input_data, + .output_data = ide_output_data, }; static struct ide_dma_ops trm290_dma_ops = { @@ -314,13 +321,13 @@ static struct ide_dma_ops trm290_dma_ops = { .dma_end = trm290_dma_end, .dma_test_irq = trm290_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, - .dma_timeout = ide_dma_timeout, + .dma_check = trm290_dma_check, }; static const struct ide_port_info trm290_chipset __devinitdata = { .name = DRV_NAME, .init_hwif = init_hwif_trm290, - .port_ops = &trm290_port_ops, + .tp_ops = &trm290_tp_ops, .dma_ops = &trm290_dma_ops, .host_flags = IDE_HFLAG_TRM290 | IDE_HFLAG_NO_ATAPI_DMA | diff --git a/trunk/drivers/ide/tx4938ide.c b/trunk/drivers/ide/tx4938ide.c index 657a61890b1c..4cb79c4c2604 100644 --- a/trunk/drivers/ide/tx4938ide.c +++ b/trunk/drivers/ide/tx4938ide.c @@ -92,13 +92,6 @@ static void tx4938ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd) if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED) HIHI = 0xFF; - if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { - u16 data = (tf->hob_data << 8) | tf->data; - - /* no endian swap */ - __raw_writew(data, (void __iomem *)io_ports->data_addr); - } - if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) tx4938ide_outb(tf->hob_feature, io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) @@ -132,20 +125,11 @@ static void tx4938ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) struct ide_io_ports *io_ports = &hwif->io_ports; struct ide_taskfile *tf = &cmd->tf; - if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { - u16 data; - - /* no endian swap */ - data = __raw_readw((void __iomem *)io_ports->data_addr); - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - /* be sure we're looking at the low order bits */ - tx4938ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); + tx4938ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE) - tf->feature = tx4938ide_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_ERROR) + tf->error = tx4938ide_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_NSECT) tf->nsect = tx4938ide_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_LBAL) @@ -158,19 +142,18 @@ static void tx4938ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) tf->device = tx4938ide_inb(io_ports->device_addr); if (cmd->tf_flags & IDE_TFLAG_LBA48) { - tx4938ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); + tx4938ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = - tx4938ide_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR) + tf->hob_error = tx4938ide_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = tx4938ide_inb(io_ports->nsect_addr); + tf->hob_nsect = tx4938ide_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = tx4938ide_inb(io_ports->lbal_addr); + tf->hob_lbal = tx4938ide_inb(io_ports->lbal_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = tx4938ide_inb(io_ports->lbam_addr); + tf->hob_lbam = tx4938ide_inb(io_ports->lbam_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = tx4938ide_inb(io_ports->lbah_addr); + tf->hob_lbah = tx4938ide_inb(io_ports->lbah_addr); } } @@ -204,9 +187,9 @@ static const struct ide_tp_ops tx4938ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = tx4938ide_tf_load, .tf_read = tx4938ide_tf_read, diff --git a/trunk/drivers/ide/tx4939ide.c b/trunk/drivers/ide/tx4939ide.c index e0e0a803dde3..0040a9a3e26e 100644 --- a/trunk/drivers/ide/tx4939ide.c +++ b/trunk/drivers/ide/tx4939ide.c @@ -279,8 +279,6 @@ static int tx4939ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) printk(KERN_ERR "%s: %s\n", drive->name, count ? "DMA table too small" : "empty DMA table?"); - ide_destroy_dmatable(drive); - return 0; /* revert to PIO for this request */ } #else @@ -294,10 +292,8 @@ static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; /* fall back to PIO! */ - if (tx4939ide_build_dmatable(drive, cmd) == 0) { - ide_map_sg(drive, cmd); + if (tx4939ide_build_dmatable(drive, cmd) == 0) return 1; - } /* PRD table */ tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr); @@ -308,8 +304,6 @@ static int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) /* clear INTR & ERROR flags */ tx4939ide_clear_dma_status(base); - drive->waiting_for_dma = 1; - tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ? TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1); @@ -325,8 +319,6 @@ static int tx4939ide_dma_end(ide_drive_t *drive) void __iomem *base = TX4939IDE_BASE(hwif); u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl); - drive->waiting_for_dma = 0; - /* get DMA command mode */ dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd); /* stop DMA */ @@ -335,11 +327,9 @@ static int tx4939ide_dma_end(ide_drive_t *drive) /* read and clear the INTR & ERROR bits */ dma_stat = tx4939ide_clear_dma_status(base); - /* purge DMA mappings */ - ide_destroy_dmatable(drive); - /* verify good DMA status */ wmb(); + /* verify good DMA status */ if ((dma_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) == 0 && (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) == (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) @@ -439,7 +429,7 @@ static void tx4939ide_tf_load_fixup(ide_drive_t *drive) * Fix ATA100 CORE System Control Register. (The write to the * Device/Head register may write wrong data to the System * Control Register) - * While Sys_Ctl is written here, selectproc is not needed. + * While Sys_Ctl is written here, dev_select() is not needed. */ tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl); } @@ -467,13 +457,6 @@ static void tx4939ide_tf_load(ide_drive_t *drive, struct ide_cmd *cmd) if (cmd->ftf_flags & IDE_FTFLAG_FLAGGED) HIHI = 0xFF; - if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { - u16 data = (tf->hob_data << 8) | tf->data; - - /* no endian swap */ - __raw_writew(data, (void __iomem *)io_ports->data_addr); - } - if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) tx4939ide_outb(tf->hob_feature, io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) @@ -509,20 +492,11 @@ static void tx4939ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) struct ide_io_ports *io_ports = &hwif->io_ports; struct ide_taskfile *tf = &cmd->tf; - if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) { - u16 data; - - /* no endian swap */ - data = __raw_readw((void __iomem *)io_ports->data_addr); - tf->data = data & 0xff; - tf->hob_data = (data >> 8) & 0xff; - } - /* be sure we're looking at the low order bits */ - tx4939ide_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr); + tx4939ide_outb(ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_FEATURE) - tf->feature = tx4939ide_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_ERROR) + tf->error = tx4939ide_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_NSECT) tf->nsect = tx4939ide_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_LBAL) @@ -535,19 +509,18 @@ static void tx4939ide_tf_read(ide_drive_t *drive, struct ide_cmd *cmd) tf->device = tx4939ide_inb(io_ports->device_addr); if (cmd->tf_flags & IDE_TFLAG_LBA48) { - tx4939ide_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr); + tx4939ide_outb(ATA_HOB | ATA_DEVCTL_OBS, io_ports->ctl_addr); - if (cmd->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) - tf->hob_feature = - tx4939ide_inb(io_ports->feature_addr); + if (cmd->tf_flags & IDE_TFLAG_IN_HOB_ERROR) + tf->hob_error = tx4939ide_inb(io_ports->feature_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_NSECT) - tf->hob_nsect = tx4939ide_inb(io_ports->nsect_addr); + tf->hob_nsect = tx4939ide_inb(io_ports->nsect_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAL) - tf->hob_lbal = tx4939ide_inb(io_ports->lbal_addr); + tf->hob_lbal = tx4939ide_inb(io_ports->lbal_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAM) - tf->hob_lbam = tx4939ide_inb(io_ports->lbam_addr); + tf->hob_lbam = tx4939ide_inb(io_ports->lbam_addr); if (cmd->tf_flags & IDE_TFLAG_IN_HOB_LBAH) - tf->hob_lbah = tx4939ide_inb(io_ports->lbah_addr); + tf->hob_lbah = tx4939ide_inb(io_ports->lbah_addr); } } @@ -581,9 +554,9 @@ static const struct ide_tp_ops tx4939ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = tx4939ide_tf_load, .tf_read = tx4939ide_tf_read, @@ -605,9 +578,9 @@ static const struct ide_tp_ops tx4939ide_tp_ops = { .exec_command = ide_exec_command, .read_status = ide_read_status, .read_altstatus = ide_read_altstatus, + .write_devctl = ide_write_devctl, - .set_irq = ide_set_irq, - + .dev_select = ide_dev_select, .tf_load = tx4939ide_tf_load, .tf_read = ide_tf_read, @@ -632,7 +605,6 @@ static const struct ide_dma_ops tx4939ide_dma_ops = { .dma_test_irq = tx4939ide_dma_test_irq, .dma_lost_irq = ide_dma_lost_irq, .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_timeout = ide_dma_timeout, .dma_sff_read_status = tx4939ide_dma_sff_read_status, }; diff --git a/trunk/drivers/input/mouse/hgpk.c b/trunk/drivers/input/mouse/hgpk.c index 81e6ebf323e9..55cd0fa68339 100644 --- a/trunk/drivers/input/mouse/hgpk.c +++ b/trunk/drivers/input/mouse/hgpk.c @@ -381,7 +381,7 @@ static void hgpk_disconnect(struct psmouse *psmouse) static void hgpk_recalib_work(struct work_struct *work) { - struct delayed_work *w = container_of(work, struct delayed_work, work); + struct delayed_work *w = to_delayed_work(work); struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq); struct psmouse *psmouse = priv->psmouse; diff --git a/trunk/drivers/isdn/capi/capi.c b/trunk/drivers/isdn/capi/capi.c index 3e468d2cf730..2d8352419c0d 100644 --- a/trunk/drivers/isdn/capi/capi.c +++ b/trunk/drivers/isdn/capi/capi.c @@ -1331,12 +1331,6 @@ static void capinc_tty_send_xchar(struct tty_struct *tty, char ch) #endif } -static int capinc_tty_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return 0; -} - static struct tty_driver *capinc_tty_driver; static const struct tty_operations capinc_ops = { @@ -1358,7 +1352,6 @@ static const struct tty_operations capinc_ops = { .flush_buffer = capinc_tty_flush_buffer, .set_ldisc = capinc_tty_set_ldisc, .send_xchar = capinc_tty_send_xchar, - .read_proc = capinc_tty_read_proc, }; static int capinc_tty_init(void) diff --git a/trunk/drivers/md/Kconfig b/trunk/drivers/md/Kconfig index 2281b5098e95..36e0675be9f7 100644 --- a/trunk/drivers/md/Kconfig +++ b/trunk/drivers/md/Kconfig @@ -121,6 +121,7 @@ config MD_RAID10 config MD_RAID456 tristate "RAID-4/RAID-5/RAID-6 mode" depends on BLK_DEV_MD + select MD_RAID6_PQ select ASYNC_MEMCPY select ASYNC_XOR ---help--- @@ -151,34 +152,8 @@ config MD_RAID456 If unsure, say Y. -config MD_RAID5_RESHAPE - bool "Support adding drives to a raid-5 array" - depends on MD_RAID456 - default y - ---help--- - A RAID-5 set can be expanded by adding extra drives. This - requires "restriping" the array which means (almost) every - block must be written to a different place. - - This option allows such restriping to be done while the array - is online. - - You will need mdadm version 2.4.1 or later to use this - feature safely. During the early stage of reshape there is - a critical section where live data is being over-written. A - crash during this time needs extra care for recovery. The - newer mdadm takes a copy of the data in the critical section - and will restore it, if necessary, after a crash. - - The mdadm usage is e.g. - mdadm --grow /dev/md1 --raid-disks=6 - to grow '/dev/md1' to having 6 disks. - - Note: The array can only be expanded, not contracted. - There should be enough spares already present to make the new - array workable. - - If unsure, say Y. +config MD_RAID6_PQ + tristate config MD_MULTIPATH tristate "Multipath I/O support" diff --git a/trunk/drivers/md/Makefile b/trunk/drivers/md/Makefile index 72880b7e28d9..45cc5951d928 100644 --- a/trunk/drivers/md/Makefile +++ b/trunk/drivers/md/Makefile @@ -2,20 +2,21 @@ # Makefile for the kernel software RAID and LVM drivers. # -dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ +dm-mod-y += dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \ dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o -dm-multipath-objs := dm-path-selector.o dm-mpath.o -dm-snapshot-objs := dm-snap.o dm-exception-store.o dm-snap-transient.o \ +dm-multipath-y += dm-path-selector.o dm-mpath.o +dm-snapshot-y += dm-snap.o dm-exception-store.o dm-snap-transient.o \ dm-snap-persistent.o -dm-mirror-objs := dm-raid1.o -md-mod-objs := md.o bitmap.o -raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \ +dm-mirror-y += dm-raid1.o +md-mod-y += md.o bitmap.o +raid456-y += raid5.o +raid6_pq-y += raid6algos.o raid6recov.o raid6tables.o \ raid6int1.o raid6int2.o raid6int4.o \ raid6int8.o raid6int16.o raid6int32.o \ raid6altivec1.o raid6altivec2.o raid6altivec4.o \ raid6altivec8.o \ raid6mmx.o raid6sse1.o raid6sse2.o -hostprogs-y := mktables +hostprogs-y += mktables # Note: link order is important. All raid personalities # and must come before md.o, as they each initialise @@ -26,6 +27,7 @@ obj-$(CONFIG_MD_LINEAR) += linear.o obj-$(CONFIG_MD_RAID0) += raid0.o obj-$(CONFIG_MD_RAID1) += raid1.o obj-$(CONFIG_MD_RAID10) += raid10.o +obj-$(CONFIG_MD_RAID6_PQ) += raid6_pq.o obj-$(CONFIG_MD_RAID456) += raid456.o obj-$(CONFIG_MD_MULTIPATH) += multipath.o obj-$(CONFIG_MD_FAULTY) += faulty.o diff --git a/trunk/drivers/md/bitmap.c b/trunk/drivers/md/bitmap.c index 719943763391..f8a9f7ab2cb8 100644 --- a/trunk/drivers/md/bitmap.c +++ b/trunk/drivers/md/bitmap.c @@ -16,6 +16,7 @@ * wait if count gets too high, wake when it drops to half. */ +#include #include #include #include @@ -26,8 +27,8 @@ #include #include #include -#include -#include +#include "md.h" +#include "bitmap.h" /* debug macros */ @@ -111,9 +112,10 @@ static int bitmap_checkpage(struct bitmap *bitmap, unsigned long page, int creat unsigned char *mappage; if (page >= bitmap->pages) { - printk(KERN_ALERT - "%s: invalid bitmap page request: %lu (> %lu)\n", - bmname(bitmap), page, bitmap->pages-1); + /* This can happen if bitmap_start_sync goes beyond + * End-of-device while looking for a whole page. + * It is harmless. + */ return -EINVAL; } @@ -265,7 +267,6 @@ static mdk_rdev_t *next_active_rdev(mdk_rdev_t *rdev, mddev_t *mddev) list_for_each_continue_rcu(pos, &mddev->disks) { rdev = list_entry(pos, mdk_rdev_t, same_set); if (rdev->raid_disk >= 0 && - test_bit(In_sync, &rdev->flags) && !test_bit(Faulty, &rdev->flags)) { /* this is a usable devices */ atomic_inc(&rdev->nr_pending); @@ -297,7 +298,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) + size/512 > 0) /* bitmap runs in to metadata */ goto bad_alignment; - if (rdev->data_offset + mddev->size*2 + if (rdev->data_offset + mddev->dev_sectors > rdev->sb_start + bitmap->offset) /* data runs in to bitmap */ goto bad_alignment; @@ -570,7 +571,7 @@ static int bitmap_read_sb(struct bitmap *bitmap) else if (le32_to_cpu(sb->version) < BITMAP_MAJOR_LO || le32_to_cpu(sb->version) > BITMAP_MAJOR_HI) reason = "unrecognized superblock version"; - else if (chunksize < PAGE_SIZE) + else if (chunksize < 512) reason = "bitmap chunksize too small"; else if ((1 << ffz(~chunksize)) != chunksize) reason = "bitmap chunksize not a power of 2"; @@ -1306,6 +1307,9 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto PRINTK(KERN_DEBUG "dec write-behind count %d/%d\n", atomic_read(&bitmap->behind_writes), bitmap->max_write_behind); } + if (bitmap->mddev->degraded) + /* Never clear bits or update events_cleared when degraded */ + success = 0; while (sectors) { int blocks; @@ -1345,8 +1349,8 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto } } -int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, - int degraded) +static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, + int degraded) { bitmap_counter_t *bmc; int rv; @@ -1374,6 +1378,29 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, return rv; } +int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, + int degraded) +{ + /* bitmap_start_sync must always report on multiples of whole + * pages, otherwise resync (which is very PAGE_SIZE based) will + * get confused. + * So call __bitmap_start_sync repeatedly (if needed) until + * At least PAGE_SIZE>>9 blocks are covered. + * Return the 'or' of the result. + */ + int rv = 0; + int blocks1; + + *blocks = 0; + while (*blocks < (PAGE_SIZE>>9)) { + rv |= __bitmap_start_sync(bitmap, offset, + &blocks1, degraded); + offset += blocks1; + *blocks += blocks1; + } + return rv; +} + void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted) { bitmap_counter_t *bmc; @@ -1443,6 +1470,8 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector) wait_event(bitmap->mddev->recovery_wait, atomic_read(&bitmap->mddev->recovery_active) == 0); + bitmap->mddev->curr_resync_completed = bitmap->mddev->curr_resync; + set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags); sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1); s = 0; while (s < sector && s < bitmap->mddev->resync_max_sectors) { diff --git a/trunk/include/linux/raid/bitmap.h b/trunk/drivers/md/bitmap.h similarity index 100% rename from trunk/include/linux/raid/bitmap.h rename to trunk/drivers/md/bitmap.h diff --git a/trunk/drivers/md/dm-bio-list.h b/trunk/drivers/md/dm-bio-list.h index d4509be0fe67..345098b4ca77 100644 --- a/trunk/drivers/md/dm-bio-list.h +++ b/trunk/drivers/md/dm-bio-list.h @@ -52,6 +52,16 @@ static inline void bio_list_add(struct bio_list *bl, struct bio *bio) bl->tail = bio; } +static inline void bio_list_add_head(struct bio_list *bl, struct bio *bio) +{ + bio->bi_next = bl->head; + + bl->head = bio; + + if (!bl->tail) + bl->tail = bio; +} + static inline void bio_list_merge(struct bio_list *bl, struct bio_list *bl2) { if (!bl2->head) diff --git a/trunk/drivers/md/dm-bio-record.h b/trunk/drivers/md/dm-bio-record.h index d3ec217847d6..3a8cfa2645c7 100644 --- a/trunk/drivers/md/dm-bio-record.h +++ b/trunk/drivers/md/dm-bio-record.h @@ -16,30 +16,56 @@ * functions in this file help the target record and restore the * original bio state. */ + +struct dm_bio_vec_details { +#if PAGE_SIZE < 65536 + __u16 bv_len; + __u16 bv_offset; +#else + unsigned bv_len; + unsigned bv_offset; +#endif +}; + struct dm_bio_details { sector_t bi_sector; struct block_device *bi_bdev; unsigned int bi_size; unsigned short bi_idx; unsigned long bi_flags; + struct dm_bio_vec_details bi_io_vec[BIO_MAX_PAGES]; }; static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) { + unsigned i; + bd->bi_sector = bio->bi_sector; bd->bi_bdev = bio->bi_bdev; bd->bi_size = bio->bi_size; bd->bi_idx = bio->bi_idx; bd->bi_flags = bio->bi_flags; + + for (i = 0; i < bio->bi_vcnt; i++) { + bd->bi_io_vec[i].bv_len = bio->bi_io_vec[i].bv_len; + bd->bi_io_vec[i].bv_offset = bio->bi_io_vec[i].bv_offset; + } } static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) { + unsigned i; + bio->bi_sector = bd->bi_sector; bio->bi_bdev = bd->bi_bdev; bio->bi_size = bd->bi_size; bio->bi_idx = bd->bi_idx; bio->bi_flags = bd->bi_flags; + + for (i = 0; i < bio->bi_vcnt; i++) { + bio->bi_io_vec[i].bv_len = bd->bi_io_vec[i].bv_len; + bio->bi_io_vec[i].bv_offset = bd->bi_io_vec[i].bv_offset; + } } #endif diff --git a/trunk/drivers/md/dm-crypt.c b/trunk/drivers/md/dm-crypt.c index bfefd079a955..53394e863c74 100644 --- a/trunk/drivers/md/dm-crypt.c +++ b/trunk/drivers/md/dm-crypt.c @@ -1156,8 +1156,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) crypto_free_ablkcipher(tfm); bad_cipher: /* Must zero key material before freeing */ - memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8)); - kfree(cc); + kzfree(cc); return -EINVAL; } @@ -1183,8 +1182,7 @@ static void crypt_dtr(struct dm_target *ti) dm_put_device(ti, cc->dev); /* Must zero key material before freeing */ - memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8)); - kfree(cc); + kzfree(cc); } static int crypt_map(struct dm_target *ti, struct bio *bio, diff --git a/trunk/drivers/md/dm-exception-store.c b/trunk/drivers/md/dm-exception-store.c index dccbfb0e010f..a2e26c242141 100644 --- a/trunk/drivers/md/dm-exception-store.c +++ b/trunk/drivers/md/dm-exception-store.c @@ -7,6 +7,7 @@ #include "dm-exception-store.h" +#include #include #include #include @@ -14,6 +15,257 @@ #define DM_MSG_PREFIX "snapshot exception stores" +static LIST_HEAD(_exception_store_types); +static DEFINE_SPINLOCK(_lock); + +static struct dm_exception_store_type *__find_exception_store_type(const char *name) +{ + struct dm_exception_store_type *type; + + list_for_each_entry(type, &_exception_store_types, list) + if (!strcmp(name, type->name)) + return type; + + return NULL; +} + +static struct dm_exception_store_type *_get_exception_store_type(const char *name) +{ + struct dm_exception_store_type *type; + + spin_lock(&_lock); + + type = __find_exception_store_type(name); + + if (type && !try_module_get(type->module)) + type = NULL; + + spin_unlock(&_lock); + + return type; +} + +/* + * get_type + * @type_name + * + * Attempt to retrieve the dm_exception_store_type by name. If not already + * available, attempt to load the appropriate module. + * + * Exstore modules are named "dm-exstore-" followed by the 'type_name'. + * Modules may contain multiple types. + * This function will first try the module "dm-exstore-", + * then truncate 'type_name' on the last '-' and try again. + * + * For example, if type_name was "clustered-shared", it would search + * 'dm-exstore-clustered-shared' then 'dm-exstore-clustered'. + * + * 'dm-exception-store-' is too long of a name in my + * opinion, which is why I've chosen to have the files + * containing exception store implementations be 'dm-exstore-'. + * If you want your module to be autoloaded, you will follow this + * naming convention. + * + * Returns: dm_exception_store_type* on success, NULL on failure + */ +static struct dm_exception_store_type *get_type(const char *type_name) +{ + char *p, *type_name_dup; + struct dm_exception_store_type *type; + + type = _get_exception_store_type(type_name); + if (type) + return type; + + type_name_dup = kstrdup(type_name, GFP_KERNEL); + if (!type_name_dup) { + DMERR("No memory left to attempt load for \"%s\"", type_name); + return NULL; + } + + while (request_module("dm-exstore-%s", type_name_dup) || + !(type = _get_exception_store_type(type_name))) { + p = strrchr(type_name_dup, '-'); + if (!p) + break; + p[0] = '\0'; + } + + if (!type) + DMWARN("Module for exstore type \"%s\" not found.", type_name); + + kfree(type_name_dup); + + return type; +} + +static void put_type(struct dm_exception_store_type *type) +{ + spin_lock(&_lock); + module_put(type->module); + spin_unlock(&_lock); +} + +int dm_exception_store_type_register(struct dm_exception_store_type *type) +{ + int r = 0; + + spin_lock(&_lock); + if (!__find_exception_store_type(type->name)) + list_add(&type->list, &_exception_store_types); + else + r = -EEXIST; + spin_unlock(&_lock); + + return r; +} +EXPORT_SYMBOL(dm_exception_store_type_register); + +int dm_exception_store_type_unregister(struct dm_exception_store_type *type) +{ + spin_lock(&_lock); + + if (!__find_exception_store_type(type->name)) { + spin_unlock(&_lock); + return -EINVAL; + } + + list_del(&type->list); + + spin_unlock(&_lock); + + return 0; +} +EXPORT_SYMBOL(dm_exception_store_type_unregister); + +/* + * Round a number up to the nearest 'size' boundary. size must + * be a power of 2. + */ +static ulong round_up(ulong n, ulong size) +{ + size--; + return (n + size) & ~size; +} + +static int set_chunk_size(struct dm_exception_store *store, + const char *chunk_size_arg, char **error) +{ + unsigned long chunk_size_ulong; + char *value; + + chunk_size_ulong = simple_strtoul(chunk_size_arg, &value, 10); + if (*chunk_size_arg == '\0' || *value != '\0') { + *error = "Invalid chunk size"; + return -EINVAL; + } + + if (!chunk_size_ulong) { + store->chunk_size = store->chunk_mask = store->chunk_shift = 0; + return 0; + } + + /* + * Chunk size must be multiple of page size. Silently + * round up if it's not. + */ + chunk_size_ulong = round_up(chunk_size_ulong, PAGE_SIZE >> 9); + + /* Check chunk_size is a power of 2 */ + if (!is_power_of_2(chunk_size_ulong)) { + *error = "Chunk size is not a power of 2"; + return -EINVAL; + } + + /* Validate the chunk size against the device block size */ + if (chunk_size_ulong % (bdev_hardsect_size(store->cow->bdev) >> 9)) { + *error = "Chunk size is not a multiple of device blocksize"; + return -EINVAL; + } + + store->chunk_size = chunk_size_ulong; + store->chunk_mask = chunk_size_ulong - 1; + store->chunk_shift = ffs(chunk_size_ulong) - 1; + + return 0; +} + +int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, + unsigned *args_used, + struct dm_exception_store **store) +{ + int r = 0; + struct dm_exception_store_type *type; + struct dm_exception_store *tmp_store; + char persistent; + + if (argc < 3) { + ti->error = "Insufficient exception store arguments"; + return -EINVAL; + } + + tmp_store = kmalloc(sizeof(*tmp_store), GFP_KERNEL); + if (!tmp_store) { + ti->error = "Exception store allocation failed"; + return -ENOMEM; + } + + persistent = toupper(*argv[1]); + if (persistent != 'P' && persistent != 'N') { + ti->error = "Persistent flag is not P or N"; + return -EINVAL; + } + + type = get_type(argv[1]); + if (!type) { + ti->error = "Exception store type not recognised"; + r = -EINVAL; + goto bad_type; + } + + tmp_store->type = type; + tmp_store->ti = ti; + + r = dm_get_device(ti, argv[0], 0, 0, + FMODE_READ | FMODE_WRITE, &tmp_store->cow); + if (r) { + ti->error = "Cannot get COW device"; + goto bad_cow; + } + + r = set_chunk_size(tmp_store, argv[2], &ti->error); + if (r) + goto bad_cow; + + r = type->ctr(tmp_store, 0, NULL); + if (r) { + ti->error = "Exception store type constructor failed"; + goto bad_ctr; + } + + *args_used = 3; + *store = tmp_store; + return 0; + +bad_ctr: + dm_put_device(ti, tmp_store->cow); +bad_cow: + put_type(type); +bad_type: + kfree(tmp_store); + return r; +} +EXPORT_SYMBOL(dm_exception_store_create); + +void dm_exception_store_destroy(struct dm_exception_store *store) +{ + store->type->dtr(store); + dm_put_device(store->ti, store->cow); + put_type(store->type); + kfree(store); +} +EXPORT_SYMBOL(dm_exception_store_destroy); + int dm_exception_store_init(void) { int r; diff --git a/trunk/drivers/md/dm-exception-store.h b/trunk/drivers/md/dm-exception-store.h index bb9f33d5daa2..0a2e6e7f67b3 100644 --- a/trunk/drivers/md/dm-exception-store.h +++ b/trunk/drivers/md/dm-exception-store.h @@ -37,11 +37,18 @@ struct dm_snap_exception { * Abstraction to handle the meta/layout of exception stores (the * COW device). */ -struct dm_exception_store { +struct dm_exception_store; +struct dm_exception_store_type { + const char *name; + struct module *module; + + int (*ctr) (struct dm_exception_store *store, + unsigned argc, char **argv); + /* * Destroys this object when you've finished with it. */ - void (*destroy) (struct dm_exception_store *store); + void (*dtr) (struct dm_exception_store *store); /* * The target shouldn't read the COW device until this is @@ -72,8 +79,9 @@ struct dm_exception_store { */ void (*drop_snapshot) (struct dm_exception_store *store); - int (*status) (struct dm_exception_store *store, status_type_t status, - char *result, unsigned int maxlen); + unsigned (*status) (struct dm_exception_store *store, + status_type_t status, char *result, + unsigned maxlen); /* * Return how full the snapshot is. @@ -82,7 +90,21 @@ struct dm_exception_store { sector_t *numerator, sector_t *denominator); - struct dm_snapshot *snap; + /* For internal device-mapper use only. */ + struct list_head list; +}; + +struct dm_exception_store { + struct dm_exception_store_type *type; + struct dm_target *ti; + + struct dm_dev *cow; + + /* Size of data blocks saved - must be a power of 2 */ + chunk_t chunk_size; + chunk_t chunk_mask; + chunk_t chunk_shift; + void *context; }; @@ -129,6 +151,28 @@ static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e) # endif +/* + * Return the number of sectors in the device. + */ +static inline sector_t get_dev_size(struct block_device *bdev) +{ + return bdev->bd_inode->i_size >> SECTOR_SHIFT; +} + +static inline chunk_t sector_to_chunk(struct dm_exception_store *store, + sector_t sector) +{ + return (sector & ~store->chunk_mask) >> store->chunk_shift; +} + +int dm_exception_store_type_register(struct dm_exception_store_type *type); +int dm_exception_store_type_unregister(struct dm_exception_store_type *type); + +int dm_exception_store_create(struct dm_target *ti, int argc, char **argv, + unsigned *args_used, + struct dm_exception_store **store); +void dm_exception_store_destroy(struct dm_exception_store *store); + int dm_exception_store_init(void); void dm_exception_store_exit(void); @@ -141,8 +185,4 @@ void dm_persistent_snapshot_exit(void); int dm_transient_snapshot_init(void); void dm_transient_snapshot_exit(void); -int dm_create_persistent(struct dm_exception_store *store); - -int dm_create_transient(struct dm_exception_store *store); - #endif /* _LINUX_DM_EXCEPTION_STORE */ diff --git a/trunk/drivers/md/dm-io.c b/trunk/drivers/md/dm-io.c index 36e2b5e46a6b..e73aabd61cd7 100644 --- a/trunk/drivers/md/dm-io.c +++ b/trunk/drivers/md/dm-io.c @@ -370,16 +370,13 @@ static int sync_io(struct dm_io_client *client, unsigned int num_regions, while (1) { set_current_state(TASK_UNINTERRUPTIBLE); - if (!atomic_read(&io.count) || signal_pending(current)) + if (!atomic_read(&io.count)) break; io_schedule(); } set_current_state(TASK_RUNNING); - if (atomic_read(&io.count)) - return -EINTR; - if (error_bits) *error_bits = io.error_bits; diff --git a/trunk/drivers/md/dm-log.c b/trunk/drivers/md/dm-log.c index 737961f275c1..be233bc4d917 100644 --- a/trunk/drivers/md/dm-log.c +++ b/trunk/drivers/md/dm-log.c @@ -16,40 +16,29 @@ #define DM_MSG_PREFIX "dirty region log" -struct dm_dirty_log_internal { - struct dm_dirty_log_type *type; - - struct list_head list; - long use; -}; - static LIST_HEAD(_log_types); static DEFINE_SPINLOCK(_lock); -static struct dm_dirty_log_internal *__find_dirty_log_type(const char *name) +static struct dm_dirty_log_type *__find_dirty_log_type(const char *name) { - struct dm_dirty_log_internal *log_type; + struct dm_dirty_log_type *log_type; list_for_each_entry(log_type, &_log_types, list) - if (!strcmp(name, log_type->type->name)) + if (!strcmp(name, log_type->name)) return log_type; return NULL; } -static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name) +static struct dm_dirty_log_type *_get_dirty_log_type(const char *name) { - struct dm_dirty_log_internal *log_type; + struct dm_dirty_log_type *log_type; spin_lock(&_lock); log_type = __find_dirty_log_type(name); - if (log_type) { - if (!log_type->use && !try_module_get(log_type->type->module)) - log_type = NULL; - else - log_type->use++; - } + if (log_type && !try_module_get(log_type->module)) + log_type = NULL; spin_unlock(&_lock); @@ -76,14 +65,14 @@ static struct dm_dirty_log_internal *_get_dirty_log_type(const char *name) static struct dm_dirty_log_type *get_type(const char *type_name) { char *p, *type_name_dup; - struct dm_dirty_log_internal *log_type; + struct dm_dirty_log_type *log_type; if (!type_name) return NULL; log_type = _get_dirty_log_type(type_name); if (log_type) - return log_type->type; + return log_type; type_name_dup = kstrdup(type_name, GFP_KERNEL); if (!type_name_dup) { @@ -105,56 +94,33 @@ static struct dm_dirty_log_type *get_type(const char *type_name) kfree(type_name_dup); - return log_type ? log_type->type : NULL; + return log_type; } static void put_type(struct dm_dirty_log_type *type) { - struct dm_dirty_log_internal *log_type; - if (!type) return; spin_lock(&_lock); - log_type = __find_dirty_log_type(type->name); - if (!log_type) + if (!__find_dirty_log_type(type->name)) goto out; - if (!--log_type->use) - module_put(type->module); - - BUG_ON(log_type->use < 0); + module_put(type->module); out: spin_unlock(&_lock); } -static struct dm_dirty_log_internal *_alloc_dirty_log_type(struct dm_dirty_log_type *type) -{ - struct dm_dirty_log_internal *log_type = kzalloc(sizeof(*log_type), - GFP_KERNEL); - - if (log_type) - log_type->type = type; - - return log_type; -} - int dm_dirty_log_type_register(struct dm_dirty_log_type *type) { - struct dm_dirty_log_internal *log_type = _alloc_dirty_log_type(type); int r = 0; - if (!log_type) - return -ENOMEM; - spin_lock(&_lock); if (!__find_dirty_log_type(type->name)) - list_add(&log_type->list, &_log_types); - else { - kfree(log_type); + list_add(&type->list, &_log_types); + else r = -EEXIST; - } spin_unlock(&_lock); return r; @@ -163,25 +129,16 @@ EXPORT_SYMBOL(dm_dirty_log_type_register); int dm_dirty_log_type_unregister(struct dm_dirty_log_type *type) { - struct dm_dirty_log_internal *log_type; - spin_lock(&_lock); - log_type = __find_dirty_log_type(type->name); - if (!log_type) { + if (!__find_dirty_log_type(type->name)) { spin_unlock(&_lock); return -EINVAL; } - if (log_type->use) { - spin_unlock(&_lock); - return -ETXTBSY; - } - - list_del(&log_type->list); + list_del(&type->list); spin_unlock(&_lock); - kfree(log_type); return 0; } diff --git a/trunk/drivers/md/dm-path-selector.c b/trunk/drivers/md/dm-path-selector.c index 96ea226155b1..42c04f04a0c4 100644 --- a/trunk/drivers/md/dm-path-selector.c +++ b/trunk/drivers/md/dm-path-selector.c @@ -17,9 +17,7 @@ struct ps_internal { struct path_selector_type pst; - struct list_head list; - long use; }; #define pst_to_psi(__pst) container_of((__pst), struct ps_internal, pst) @@ -45,12 +43,8 @@ static struct ps_internal *get_path_selector(const char *name) down_read(&_ps_lock); psi = __find_path_selector_type(name); - if (psi) { - if ((psi->use == 0) && !try_module_get(psi->pst.module)) - psi = NULL; - else - psi->use++; - } + if (psi && !try_module_get(psi->pst.module)) + psi = NULL; up_read(&_ps_lock); return psi; @@ -84,11 +78,7 @@ void dm_put_path_selector(struct path_selector_type *pst) if (!psi) goto out; - if (--psi->use == 0) - module_put(psi->pst.module); - - BUG_ON(psi->use < 0); - + module_put(psi->pst.module); out: up_read(&_ps_lock); } @@ -136,11 +126,6 @@ int dm_unregister_path_selector(struct path_selector_type *pst) return -EINVAL; } - if (psi->use) { - up_write(&_ps_lock); - return -ETXTBSY; - } - list_del(&psi->list); up_write(&_ps_lock); diff --git a/trunk/drivers/md/dm-raid1.c b/trunk/drivers/md/dm-raid1.c index 4d6bc101962e..536ef0bef154 100644 --- a/trunk/drivers/md/dm-raid1.c +++ b/trunk/drivers/md/dm-raid1.c @@ -145,6 +145,8 @@ struct dm_raid1_read_record { struct dm_bio_details details; }; +static struct kmem_cache *_dm_raid1_read_record_cache; + /* * Every mirror should look like this one. */ @@ -586,6 +588,9 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) int state; struct bio *bio; struct bio_list sync, nosync, recover, *this_list = NULL; + struct bio_list requeue; + struct dm_dirty_log *log = dm_rh_dirty_log(ms->rh); + region_t region; if (!writes->head) return; @@ -596,10 +601,18 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) bio_list_init(&sync); bio_list_init(&nosync); bio_list_init(&recover); + bio_list_init(&requeue); while ((bio = bio_list_pop(writes))) { - state = dm_rh_get_state(ms->rh, - dm_rh_bio_to_region(ms->rh, bio), 1); + region = dm_rh_bio_to_region(ms->rh, bio); + + if (log->type->is_remote_recovering && + log->type->is_remote_recovering(log, region)) { + bio_list_add(&requeue, bio); + continue; + } + + state = dm_rh_get_state(ms->rh, region, 1); switch (state) { case DM_RH_CLEAN: case DM_RH_DIRTY: @@ -618,6 +631,16 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes) bio_list_add(this_list, bio); } + /* + * Add bios that are delayed due to remote recovery + * back on to the write queue + */ + if (unlikely(requeue.head)) { + spin_lock_irq(&ms->lock); + bio_list_merge(&ms->writes, &requeue); + spin_unlock_irq(&ms->lock); + } + /* * Increment the pending counts for any regions that will * be written to (writes to recover regions are going to @@ -764,9 +787,9 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors, atomic_set(&ms->suspend, 0); atomic_set(&ms->default_mirror, DEFAULT_MIRROR); - len = sizeof(struct dm_raid1_read_record); - ms->read_record_pool = mempool_create_kmalloc_pool(MIN_READ_RECORDS, - len); + ms->read_record_pool = mempool_create_slab_pool(MIN_READ_RECORDS, + _dm_raid1_read_record_cache); + if (!ms->read_record_pool) { ti->error = "Error creating mirror read_record_pool"; kfree(ms); @@ -1279,16 +1302,31 @@ static int __init dm_mirror_init(void) { int r; + _dm_raid1_read_record_cache = KMEM_CACHE(dm_raid1_read_record, 0); + if (!_dm_raid1_read_record_cache) { + DMERR("Can't allocate dm_raid1_read_record cache"); + r = -ENOMEM; + goto bad_cache; + } + r = dm_register_target(&mirror_target); - if (r < 0) + if (r < 0) { DMERR("Failed to register mirror target"); + goto bad_target; + } + + return 0; +bad_target: + kmem_cache_destroy(_dm_raid1_read_record_cache); +bad_cache: return r; } static void __exit dm_mirror_exit(void) { dm_unregister_target(&mirror_target); + kmem_cache_destroy(_dm_raid1_read_record_cache); } /* Module hooks */ diff --git a/trunk/drivers/md/dm-snap-persistent.c b/trunk/drivers/md/dm-snap-persistent.c index 936b34e0959f..e75c6dd76a9a 100644 --- a/trunk/drivers/md/dm-snap-persistent.c +++ b/trunk/drivers/md/dm-snap-persistent.c @@ -6,7 +6,6 @@ */ #include "dm-exception-store.h" -#include "dm-snap.h" #include #include @@ -89,7 +88,7 @@ struct commit_callback { * The top level structure for a persistent exception store. */ struct pstore { - struct dm_snapshot *snap; /* up pointer to my snapshot */ + struct dm_exception_store *store; int version; int valid; uint32_t exceptions_per_area; @@ -141,7 +140,7 @@ static int alloc_area(struct pstore *ps) int r = -ENOMEM; size_t len; - len = ps->snap->chunk_size << SECTOR_SHIFT; + len = ps->store->chunk_size << SECTOR_SHIFT; /* * Allocate the chunk_size block of memory that will hold @@ -163,9 +162,12 @@ static int alloc_area(struct pstore *ps) static void free_area(struct pstore *ps) { - vfree(ps->area); + if (ps->area) + vfree(ps->area); ps->area = NULL; - vfree(ps->zero_area); + + if (ps->zero_area) + vfree(ps->zero_area); ps->zero_area = NULL; } @@ -189,9 +191,9 @@ static void do_metadata(struct work_struct *work) static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata) { struct dm_io_region where = { - .bdev = ps->snap->cow->bdev, - .sector = ps->snap->chunk_size * chunk, - .count = ps->snap->chunk_size, + .bdev = ps->store->cow->bdev, + .sector = ps->store->chunk_size * chunk, + .count = ps->store->chunk_size, }; struct dm_io_request io_req = { .bi_rw = rw, @@ -247,15 +249,15 @@ static int area_io(struct pstore *ps, int rw) static void zero_memory_area(struct pstore *ps) { - memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); + memset(ps->area, 0, ps->store->chunk_size << SECTOR_SHIFT); } static int zero_disk_area(struct pstore *ps, chunk_t area) { struct dm_io_region where = { - .bdev = ps->snap->cow->bdev, - .sector = ps->snap->chunk_size * area_location(ps, area), - .count = ps->snap->chunk_size, + .bdev = ps->store->cow->bdev, + .sector = ps->store->chunk_size * area_location(ps, area), + .count = ps->store->chunk_size, }; struct dm_io_request io_req = { .bi_rw = WRITE, @@ -278,15 +280,15 @@ static int read_header(struct pstore *ps, int *new_snapshot) /* * Use default chunk size (or hardsect_size, if larger) if none supplied */ - if (!ps->snap->chunk_size) { - ps->snap->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS, - bdev_hardsect_size(ps->snap->cow->bdev) >> 9); - ps->snap->chunk_mask = ps->snap->chunk_size - 1; - ps->snap->chunk_shift = ffs(ps->snap->chunk_size) - 1; + if (!ps->store->chunk_size) { + ps->store->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS, + bdev_hardsect_size(ps->store->cow->bdev) >> 9); + ps->store->chunk_mask = ps->store->chunk_size - 1; + ps->store->chunk_shift = ffs(ps->store->chunk_size) - 1; chunk_size_supplied = 0; } - ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap-> + ps->io_client = dm_io_client_create(sectors_to_pages(ps->store-> chunk_size)); if (IS_ERR(ps->io_client)) return PTR_ERR(ps->io_client); @@ -317,22 +319,22 @@ static int read_header(struct pstore *ps, int *new_snapshot) ps->version = le32_to_cpu(dh->version); chunk_size = le32_to_cpu(dh->chunk_size); - if (!chunk_size_supplied || ps->snap->chunk_size == chunk_size) + if (!chunk_size_supplied || ps->store->chunk_size == chunk_size) return 0; DMWARN("chunk size %llu in device metadata overrides " "table chunk size of %llu.", (unsigned long long)chunk_size, - (unsigned long long)ps->snap->chunk_size); + (unsigned long long)ps->store->chunk_size); /* We had a bogus chunk_size. Fix stuff up. */ free_area(ps); - ps->snap->chunk_size = chunk_size; - ps->snap->chunk_mask = chunk_size - 1; - ps->snap->chunk_shift = ffs(chunk_size) - 1; + ps->store->chunk_size = chunk_size; + ps->store->chunk_mask = chunk_size - 1; + ps->store->chunk_shift = ffs(chunk_size) - 1; - r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size), + r = dm_io_client_resize(sectors_to_pages(ps->store->chunk_size), ps->io_client); if (r) return r; @@ -349,13 +351,13 @@ static int write_header(struct pstore *ps) { struct disk_header *dh; - memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT); + memset(ps->area, 0, ps->store->chunk_size << SECTOR_SHIFT); dh = (struct disk_header *) ps->area; dh->magic = cpu_to_le32(SNAP_MAGIC); dh->valid = cpu_to_le32(ps->valid); dh->version = cpu_to_le32(ps->version); - dh->chunk_size = cpu_to_le32(ps->snap->chunk_size); + dh->chunk_size = cpu_to_le32(ps->store->chunk_size); return chunk_io(ps, 0, WRITE, 1); } @@ -474,18 +476,25 @@ static struct pstore *get_info(struct dm_exception_store *store) static void persistent_fraction_full(struct dm_exception_store *store, sector_t *numerator, sector_t *denominator) { - *numerator = get_info(store)->next_free * store->snap->chunk_size; - *denominator = get_dev_size(store->snap->cow->bdev); + *numerator = get_info(store)->next_free * store->chunk_size; + *denominator = get_dev_size(store->cow->bdev); } -static void persistent_destroy(struct dm_exception_store *store) +static void persistent_dtr(struct dm_exception_store *store) { struct pstore *ps = get_info(store); destroy_workqueue(ps->metadata_wq); - dm_io_client_destroy(ps->io_client); - vfree(ps->callbacks); + + /* Created in read_header */ + if (ps->io_client) + dm_io_client_destroy(ps->io_client); free_area(ps); + + /* Allocated in persistent_read_metadata */ + if (ps->callbacks) + vfree(ps->callbacks); + kfree(ps); } @@ -507,7 +516,7 @@ static int persistent_read_metadata(struct dm_exception_store *store, /* * Now we know correct chunk_size, complete the initialisation. */ - ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) / + ps->exceptions_per_area = (ps->store->chunk_size << SECTOR_SHIFT) / sizeof(struct disk_exception); ps->callbacks = dm_vcalloc(ps->exceptions_per_area, sizeof(*ps->callbacks)); @@ -564,10 +573,10 @@ static int persistent_prepare_exception(struct dm_exception_store *store, struct pstore *ps = get_info(store); uint32_t stride; chunk_t next_free; - sector_t size = get_dev_size(store->snap->cow->bdev); + sector_t size = get_dev_size(store->cow->bdev); /* Is there enough room ? */ - if (size < ((ps->next_free + 1) * store->snap->chunk_size)) + if (size < ((ps->next_free + 1) * store->chunk_size)) return -ENOSPC; e->new_chunk = ps->next_free; @@ -656,16 +665,17 @@ static void persistent_drop_snapshot(struct dm_exception_store *store) DMWARN("write header failed"); } -int dm_create_persistent(struct dm_exception_store *store) +static int persistent_ctr(struct dm_exception_store *store, + unsigned argc, char **argv) { struct pstore *ps; /* allocate the pstore */ - ps = kmalloc(sizeof(*ps), GFP_KERNEL); + ps = kzalloc(sizeof(*ps), GFP_KERNEL); if (!ps) return -ENOMEM; - ps->snap = store->snap; + ps->store = store; ps->valid = 1; ps->version = SNAPSHOT_DISK_VERSION; ps->area = NULL; @@ -683,22 +693,77 @@ int dm_create_persistent(struct dm_exception_store *store) return -ENOMEM; } - store->destroy = persistent_destroy; - store->read_metadata = persistent_read_metadata; - store->prepare_exception = persistent_prepare_exception; - store->commit_exception = persistent_commit_exception; - store->drop_snapshot = persistent_drop_snapshot; - store->fraction_full = persistent_fraction_full; store->context = ps; return 0; } +static unsigned persistent_status(struct dm_exception_store *store, + status_type_t status, char *result, + unsigned maxlen) +{ + unsigned sz = 0; + + switch (status) { + case STATUSTYPE_INFO: + break; + case STATUSTYPE_TABLE: + DMEMIT(" %s P %llu", store->cow->name, + (unsigned long long)store->chunk_size); + } + + return sz; +} + +static struct dm_exception_store_type _persistent_type = { + .name = "persistent", + .module = THIS_MODULE, + .ctr = persistent_ctr, + .dtr = persistent_dtr, + .read_metadata = persistent_read_metadata, + .prepare_exception = persistent_prepare_exception, + .commit_exception = persistent_commit_exception, + .drop_snapshot = persistent_drop_snapshot, + .fraction_full = persistent_fraction_full, + .status = persistent_status, +}; + +static struct dm_exception_store_type _persistent_compat_type = { + .name = "P", + .module = THIS_MODULE, + .ctr = persistent_ctr, + .dtr = persistent_dtr, + .read_metadata = persistent_read_metadata, + .prepare_exception = persistent_prepare_exception, + .commit_exception = persistent_commit_exception, + .drop_snapshot = persistent_drop_snapshot, + .fraction_full = persistent_fraction_full, + .status = persistent_status, +}; + int dm_persistent_snapshot_init(void) { - return 0; + int r; + + r = dm_exception_store_type_register(&_persistent_type); + if (r) { + DMERR("Unable to register persistent exception store type"); + return r; + } + + r = dm_exception_store_type_register(&_persistent_compat_type); + if (r) { + DMERR("Unable to register old-style persistent exception " + "store type"); + dm_exception_store_type_unregister(&_persistent_type); + return r; + } + + return r; } void dm_persistent_snapshot_exit(void) { + dm_exception_store_type_unregister(&_persistent_type); + dm_exception_store_type_unregister(&_persistent_compat_type); } diff --git a/trunk/drivers/md/dm-snap-transient.c b/trunk/drivers/md/dm-snap-transient.c index 7f6e2e6dcb0d..cde5aa558e6d 100644 --- a/trunk/drivers/md/dm-snap-transient.c +++ b/trunk/drivers/md/dm-snap-transient.c @@ -6,7 +6,6 @@ */ #include "dm-exception-store.h" -#include "dm-snap.h" #include #include @@ -23,7 +22,7 @@ struct transient_c { sector_t next_free; }; -static void transient_destroy(struct dm_exception_store *store) +static void transient_dtr(struct dm_exception_store *store) { kfree(store->context); } @@ -39,14 +38,14 @@ static int transient_read_metadata(struct dm_exception_store *store, static int transient_prepare_exception(struct dm_exception_store *store, struct dm_snap_exception *e) { - struct transient_c *tc = (struct transient_c *) store->context; - sector_t size = get_dev_size(store->snap->cow->bdev); + struct transient_c *tc = store->context; + sector_t size = get_dev_size(store->cow->bdev); - if (size < (tc->next_free + store->snap->chunk_size)) + if (size < (tc->next_free + store->chunk_size)) return -1; - e->new_chunk = sector_to_chunk(store->snap, tc->next_free); - tc->next_free += store->snap->chunk_size; + e->new_chunk = sector_to_chunk(store, tc->next_free); + tc->next_free += store->chunk_size; return 0; } @@ -64,20 +63,14 @@ static void transient_fraction_full(struct dm_exception_store *store, sector_t *numerator, sector_t *denominator) { *numerator = ((struct transient_c *) store->context)->next_free; - *denominator = get_dev_size(store->snap->cow->bdev); + *denominator = get_dev_size(store->cow->bdev); } -int dm_create_transient(struct dm_exception_store *store) +static int transient_ctr(struct dm_exception_store *store, + unsigned argc, char **argv) { struct transient_c *tc; - store->destroy = transient_destroy; - store->read_metadata = transient_read_metadata; - store->prepare_exception = transient_prepare_exception; - store->commit_exception = transient_commit_exception; - store->drop_snapshot = NULL; - store->fraction_full = transient_fraction_full; - tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL); if (!tc) return -ENOMEM; @@ -88,11 +81,70 @@ int dm_create_transient(struct dm_exception_store *store) return 0; } +static unsigned transient_status(struct dm_exception_store *store, + status_type_t status, char *result, + unsigned maxlen) +{ + unsigned sz = 0; + + switch (status) { + case STATUSTYPE_INFO: + break; + case STATUSTYPE_TABLE: + DMEMIT(" %s N %llu", store->cow->name, + (unsigned long long)store->chunk_size); + } + + return sz; +} + +static struct dm_exception_store_type _transient_type = { + .name = "transient", + .module = THIS_MODULE, + .ctr = transient_ctr, + .dtr = transient_dtr, + .read_metadata = transient_read_metadata, + .prepare_exception = transient_prepare_exception, + .commit_exception = transient_commit_exception, + .fraction_full = transient_fraction_full, + .status = transient_status, +}; + +static struct dm_exception_store_type _transient_compat_type = { + .name = "N", + .module = THIS_MODULE, + .ctr = transient_ctr, + .dtr = transient_dtr, + .read_metadata = transient_read_metadata, + .prepare_exception = transient_prepare_exception, + .commit_exception = transient_commit_exception, + .fraction_full = transient_fraction_full, + .status = transient_status, +}; + int dm_transient_snapshot_init(void) { - return 0; + int r; + + r = dm_exception_store_type_register(&_transient_type); + if (r) { + DMWARN("Unable to register transient exception store type"); + return r; + } + + r = dm_exception_store_type_register(&_transient_compat_type); + if (r) { + DMWARN("Unable to register old-style transient " + "exception store type"); + dm_exception_store_type_unregister(&_transient_type); + return r; + } + + return r; } void dm_transient_snapshot_exit(void) { + dm_exception_store_type_unregister(&_transient_type); + dm_exception_store_type_unregister(&_transient_compat_type); } diff --git a/trunk/drivers/md/dm-snap.c b/trunk/drivers/md/dm-snap.c index 65ff82ff124e..981a0413068f 100644 --- a/trunk/drivers/md/dm-snap.c +++ b/trunk/drivers/md/dm-snap.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include @@ -20,9 +19,9 @@ #include #include #include +#include #include "dm-exception-store.h" -#include "dm-snap.h" #include "dm-bio-list.h" #define DM_MSG_PREFIX "snapshots" @@ -47,9 +46,76 @@ */ #define MIN_IOS 256 +#define DM_TRACKED_CHUNK_HASH_SIZE 16 +#define DM_TRACKED_CHUNK_HASH(x) ((unsigned long)(x) & \ + (DM_TRACKED_CHUNK_HASH_SIZE - 1)) + +struct exception_table { + uint32_t hash_mask; + unsigned hash_shift; + struct list_head *table; +}; + +struct dm_snapshot { + struct rw_semaphore lock; + + struct dm_dev *origin; + + /* List of snapshots per Origin */ + struct list_head list; + + /* You can't use a snapshot if this is 0 (e.g. if full) */ + int valid; + + /* Origin writes don't trigger exceptions until this is set */ + int active; + + mempool_t *pending_pool; + + atomic_t pending_exceptions_count; + + struct exception_table pending; + struct exception_table complete; + + /* + * pe_lock protects all pending_exception operations and access + * as well as the snapshot_bios list. + */ + spinlock_t pe_lock; + + /* The on disk metadata handler */ + struct dm_exception_store *store; + + struct dm_kcopyd_client *kcopyd_client; + + /* Queue of snapshot writes for ksnapd to flush */ + struct bio_list queued_bios; + struct work_struct queued_bios_work; + + /* Chunks with outstanding reads */ + mempool_t *tracked_chunk_pool; + spinlock_t tracked_chunk_lock; + struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE]; +}; + static struct workqueue_struct *ksnapd; static void flush_queued_bios(struct work_struct *work); +static sector_t chunk_to_sector(struct dm_exception_store *store, + chunk_t chunk) +{ + return chunk << store->chunk_shift; +} + +static int bdev_equal(struct block_device *lhs, struct block_device *rhs) +{ + /* + * There is only ever one instance of a particular block + * device so we can compare pointers safely. + */ + return lhs == rhs; +} + struct dm_snap_pending_exception { struct dm_snap_exception e; @@ -476,11 +542,11 @@ static int init_hash_tables(struct dm_snapshot *s) * Calculate based on the size of the original volume or * the COW volume... */ - cow_dev_size = get_dev_size(s->cow->bdev); + cow_dev_size = get_dev_size(s->store->cow->bdev); origin_dev_size = get_dev_size(s->origin->bdev); max_buckets = calc_max_buckets(); - hash_size = min(origin_dev_size, cow_dev_size) >> s->chunk_shift; + hash_size = min(origin_dev_size, cow_dev_size) >> s->store->chunk_shift; hash_size = min(hash_size, max_buckets); hash_size = rounddown_pow_of_two(hash_size); @@ -504,58 +570,6 @@ static int init_hash_tables(struct dm_snapshot *s) return 0; } -/* - * Round a number up to the nearest 'size' boundary. size must - * be a power of 2. - */ -static ulong round_up(ulong n, ulong size) -{ - size--; - return (n + size) & ~size; -} - -static int set_chunk_size(struct dm_snapshot *s, const char *chunk_size_arg, - char **error) -{ - unsigned long chunk_size; - char *value; - - chunk_size = simple_strtoul(chunk_size_arg, &value, 10); - if (*chunk_size_arg == '\0' || *value != '\0') { - *error = "Invalid chunk size"; - return -EINVAL; - } - - if (!chunk_size) { - s->chunk_size = s->chunk_mask = s->chunk_shift = 0; - return 0; - } - - /* - * Chunk size must be multiple of page size. Silently - * round up if it's not. - */ - chunk_size = round_up(chunk_size, PAGE_SIZE >> 9); - - /* Check chunk_size is a power of 2 */ - if (!is_power_of_2(chunk_size)) { - *error = "Chunk size is not a power of 2"; - return -EINVAL; - } - - /* Validate the chunk size against the device block size */ - if (chunk_size % (bdev_hardsect_size(s->cow->bdev) >> 9)) { - *error = "Chunk size is not a multiple of device blocksize"; - return -EINVAL; - } - - s->chunk_size = chunk_size; - s->chunk_mask = chunk_size - 1; - s->chunk_shift = ffs(chunk_size) - 1; - - return 0; -} - /* * Construct a snapshot mapping:

*/ @@ -564,91 +578,68 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) struct dm_snapshot *s; int i; int r = -EINVAL; - char persistent; char *origin_path; - char *cow_path; + struct dm_exception_store *store; + unsigned args_used; if (argc != 4) { ti->error = "requires exactly 4 arguments"; r = -EINVAL; - goto bad1; + goto bad_args; } origin_path = argv[0]; - cow_path = argv[1]; - persistent = toupper(*argv[2]); + argv++; + argc--; - if (persistent != 'P' && persistent != 'N') { - ti->error = "Persistent flag is not P or N"; + r = dm_exception_store_create(ti, argc, argv, &args_used, &store); + if (r) { + ti->error = "Couldn't create exception store"; r = -EINVAL; - goto bad1; + goto bad_args; } + argv += args_used; + argc -= args_used; + s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s == NULL) { + if (!s) { ti->error = "Cannot allocate snapshot context private " "structure"; r = -ENOMEM; - goto bad1; + goto bad_snap; } r = dm_get_device(ti, origin_path, 0, ti->len, FMODE_READ, &s->origin); if (r) { ti->error = "Cannot get origin device"; - goto bad2; - } - - r = dm_get_device(ti, cow_path, 0, 0, - FMODE_READ | FMODE_WRITE, &s->cow); - if (r) { - dm_put_device(ti, s->origin); - ti->error = "Cannot get COW device"; - goto bad2; + goto bad_origin; } - r = set_chunk_size(s, argv[3], &ti->error); - if (r) - goto bad3; - - s->type = persistent; - + s->store = store; s->valid = 1; s->active = 0; atomic_set(&s->pending_exceptions_count, 0); init_rwsem(&s->lock); spin_lock_init(&s->pe_lock); - s->ti = ti; /* Allocate hash table for COW data */ if (init_hash_tables(s)) { ti->error = "Unable to allocate hash table space"; r = -ENOMEM; - goto bad3; - } - - s->store.snap = s; - - if (persistent == 'P') - r = dm_create_persistent(&s->store); - else - r = dm_create_transient(&s->store); - - if (r) { - ti->error = "Couldn't create exception store"; - r = -EINVAL; - goto bad4; + goto bad_hash_tables; } r = dm_kcopyd_client_create(SNAPSHOT_PAGES, &s->kcopyd_client); if (r) { ti->error = "Could not create kcopyd client"; - goto bad5; + goto bad_kcopyd; } s->pending_pool = mempool_create_slab_pool(MIN_IOS, pending_cache); if (!s->pending_pool) { ti->error = "Could not allocate mempool for pending exceptions"; - goto bad6; + goto bad_pending_pool; } s->tracked_chunk_pool = mempool_create_slab_pool(MIN_IOS, @@ -665,7 +656,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) spin_lock_init(&s->tracked_chunk_lock); /* Metadata must only be loaded into one table at once */ - r = s->store.read_metadata(&s->store, dm_add_exception, (void *)s); + r = s->store->type->read_metadata(s->store, dm_add_exception, + (void *)s); if (r < 0) { ti->error = "Failed to read snapshot metadata"; goto bad_load_and_register; @@ -686,34 +678,33 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ti->private = s; - ti->split_io = s->chunk_size; + ti->split_io = s->store->chunk_size; return 0; - bad_load_and_register: +bad_load_and_register: mempool_destroy(s->tracked_chunk_pool); - bad_tracked_chunk_pool: +bad_tracked_chunk_pool: mempool_destroy(s->pending_pool); - bad6: +bad_pending_pool: dm_kcopyd_client_destroy(s->kcopyd_client); - bad5: - s->store.destroy(&s->store); - - bad4: +bad_kcopyd: exit_exception_table(&s->pending, pending_cache); exit_exception_table(&s->complete, exception_cache); - bad3: - dm_put_device(ti, s->cow); +bad_hash_tables: dm_put_device(ti, s->origin); - bad2: +bad_origin: kfree(s); - bad1: +bad_snap: + dm_exception_store_destroy(store); + +bad_args: return r; } @@ -724,8 +715,6 @@ static void __free_exceptions(struct dm_snapshot *s) exit_exception_table(&s->pending, pending_cache); exit_exception_table(&s->complete, exception_cache); - - s->store.destroy(&s->store); } static void snapshot_dtr(struct dm_target *ti) @@ -761,7 +750,8 @@ static void snapshot_dtr(struct dm_target *ti) mempool_destroy(s->pending_pool); dm_put_device(ti, s->origin); - dm_put_device(ti, s->cow); + + dm_exception_store_destroy(s->store); kfree(s); } @@ -820,12 +810,12 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err) else if (err == -ENOMEM) DMERR("Invalidating snapshot: Unable to allocate exception."); - if (s->store.drop_snapshot) - s->store.drop_snapshot(&s->store); + if (s->store->type->drop_snapshot) + s->store->type->drop_snapshot(s->store); s->valid = 0; - dm_table_event(s->ti->table); + dm_table_event(s->store->ti->table); } static void get_pending_exception(struct dm_snap_pending_exception *pe) @@ -943,8 +933,8 @@ static void copy_callback(int read_err, unsigned long write_err, void *context) else /* Update the metadata if we are persistent */ - s->store.commit_exception(&s->store, &pe->e, commit_callback, - pe); + s->store->type->commit_exception(s->store, &pe->e, + commit_callback, pe); } /* @@ -960,11 +950,11 @@ static void start_copy(struct dm_snap_pending_exception *pe) dev_size = get_dev_size(bdev); src.bdev = bdev; - src.sector = chunk_to_sector(s, pe->e.old_chunk); - src.count = min(s->chunk_size, dev_size - src.sector); + src.sector = chunk_to_sector(s->store, pe->e.old_chunk); + src.count = min(s->store->chunk_size, dev_size - src.sector); - dest.bdev = s->cow->bdev; - dest.sector = chunk_to_sector(s, pe->e.new_chunk); + dest.bdev = s->store->cow->bdev; + dest.sector = chunk_to_sector(s->store, pe->e.new_chunk); dest.count = src.count; /* Hand over to kcopyd */ @@ -972,6 +962,17 @@ static void start_copy(struct dm_snap_pending_exception *pe) &src, 1, &dest, 0, copy_callback, pe); } +static struct dm_snap_pending_exception * +__lookup_pending_exception(struct dm_snapshot *s, chunk_t chunk) +{ + struct dm_snap_exception *e = lookup_exception(&s->pending, chunk); + + if (!e) + return NULL; + + return container_of(e, struct dm_snap_pending_exception, e); +} + /* * Looks to see if this snapshot already has a pending exception * for this chunk, otherwise it allocates a new one and inserts @@ -981,40 +982,15 @@ static void start_copy(struct dm_snap_pending_exception *pe) * this. */ static struct dm_snap_pending_exception * -__find_pending_exception(struct dm_snapshot *s, struct bio *bio) +__find_pending_exception(struct dm_snapshot *s, + struct dm_snap_pending_exception *pe, chunk_t chunk) { - struct dm_snap_exception *e; - struct dm_snap_pending_exception *pe; - chunk_t chunk = sector_to_chunk(s, bio->bi_sector); + struct dm_snap_pending_exception *pe2; - /* - * Is there a pending exception for this already ? - */ - e = lookup_exception(&s->pending, chunk); - if (e) { - /* cast the exception to a pending exception */ - pe = container_of(e, struct dm_snap_pending_exception, e); - goto out; - } - - /* - * Create a new pending exception, we don't want - * to hold the lock while we do this. - */ - up_write(&s->lock); - pe = alloc_pending_exception(s); - down_write(&s->lock); - - if (!s->valid) { - free_pending_exception(pe); - return NULL; - } - - e = lookup_exception(&s->pending, chunk); - if (e) { + pe2 = __lookup_pending_exception(s, chunk); + if (pe2) { free_pending_exception(pe); - pe = container_of(e, struct dm_snap_pending_exception, e); - goto out; + return pe2; } pe->e.old_chunk = chunk; @@ -1024,7 +1000,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) atomic_set(&pe->ref_count, 0); pe->started = 0; - if (s->store.prepare_exception(&s->store, &pe->e)) { + if (s->store->type->prepare_exception(s->store, &pe->e)) { free_pending_exception(pe); return NULL; } @@ -1032,17 +1008,18 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio) get_pending_exception(pe); insert_exception(&s->pending, &pe->e); - out: return pe; } static void remap_exception(struct dm_snapshot *s, struct dm_snap_exception *e, struct bio *bio, chunk_t chunk) { - bio->bi_bdev = s->cow->bdev; - bio->bi_sector = chunk_to_sector(s, dm_chunk_number(e->new_chunk) + - (chunk - e->old_chunk)) + - (bio->bi_sector & s->chunk_mask); + bio->bi_bdev = s->store->cow->bdev; + bio->bi_sector = chunk_to_sector(s->store, + dm_chunk_number(e->new_chunk) + + (chunk - e->old_chunk)) + + (bio->bi_sector & + s->store->chunk_mask); } static int snapshot_map(struct dm_target *ti, struct bio *bio, @@ -1054,7 +1031,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, chunk_t chunk; struct dm_snap_pending_exception *pe = NULL; - chunk = sector_to_chunk(s, bio->bi_sector); + chunk = sector_to_chunk(s->store, bio->bi_sector); /* Full snapshots are not usable */ /* To get here the table must be live so s->active is always set. */ @@ -1083,11 +1060,31 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio, * writeable. */ if (bio_rw(bio) == WRITE) { - pe = __find_pending_exception(s, bio); + pe = __lookup_pending_exception(s, chunk); if (!pe) { - __invalidate_snapshot(s, -ENOMEM); - r = -EIO; - goto out_unlock; + up_write(&s->lock); + pe = alloc_pending_exception(s); + down_write(&s->lock); + + if (!s->valid) { + free_pending_exception(pe); + r = -EIO; + goto out_unlock; + } + + e = lookup_exception(&s->complete, chunk); + if (e) { + free_pending_exception(pe); + remap_exception(s, e, bio, chunk); + goto out_unlock; + } + + pe = __find_pending_exception(s, pe, chunk); + if (!pe) { + __invalidate_snapshot(s, -ENOMEM); + r = -EIO; + goto out_unlock; + } } remap_exception(s, &pe->e, bio, chunk); @@ -1137,24 +1134,25 @@ static void snapshot_resume(struct dm_target *ti) static int snapshot_status(struct dm_target *ti, status_type_t type, char *result, unsigned int maxlen) { + unsigned sz = 0; struct dm_snapshot *snap = ti->private; switch (type) { case STATUSTYPE_INFO: if (!snap->valid) - snprintf(result, maxlen, "Invalid"); + DMEMIT("Invalid"); else { - if (snap->store.fraction_full) { + if (snap->store->type->fraction_full) { sector_t numerator, denominator; - snap->store.fraction_full(&snap->store, - &numerator, - &denominator); - snprintf(result, maxlen, "%llu/%llu", - (unsigned long long)numerator, - (unsigned long long)denominator); + snap->store->type->fraction_full(snap->store, + &numerator, + &denominator); + DMEMIT("%llu/%llu", + (unsigned long long)numerator, + (unsigned long long)denominator); } else - snprintf(result, maxlen, "Unknown"); + DMEMIT("Unknown"); } break; @@ -1164,10 +1162,9 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, * to make private copies if the output is to * make sense. */ - snprintf(result, maxlen, "%s %s %c %llu", - snap->origin->name, snap->cow->name, - snap->type, - (unsigned long long)snap->chunk_size); + DMEMIT("%s", snap->origin->name); + snap->store->type->status(snap->store, type, result + sz, + maxlen - sz); break; } @@ -1196,14 +1193,14 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) goto next_snapshot; /* Nothing to do if writing beyond end of snapshot */ - if (bio->bi_sector >= dm_table_get_size(snap->ti->table)) + if (bio->bi_sector >= dm_table_get_size(snap->store->ti->table)) goto next_snapshot; /* * Remember, different snapshots can have * different chunk sizes. */ - chunk = sector_to_chunk(snap, bio->bi_sector); + chunk = sector_to_chunk(snap->store, bio->bi_sector); /* * Check exception table to see if block @@ -1217,10 +1214,28 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio) if (e) goto next_snapshot; - pe = __find_pending_exception(snap, bio); + pe = __lookup_pending_exception(snap, chunk); if (!pe) { - __invalidate_snapshot(snap, -ENOMEM); - goto next_snapshot; + up_write(&snap->lock); + pe = alloc_pending_exception(snap); + down_write(&snap->lock); + + if (!snap->valid) { + free_pending_exception(pe); + goto next_snapshot; + } + + e = lookup_exception(&snap->complete, chunk); + if (e) { + free_pending_exception(pe); + goto next_snapshot; + } + + pe = __find_pending_exception(snap, pe, chunk); + if (!pe) { + __invalidate_snapshot(snap, -ENOMEM); + goto next_snapshot; + } } if (!primary_pe) { @@ -1360,7 +1375,8 @@ static void origin_resume(struct dm_target *ti) o = __lookup_origin(dev->bdev); if (o) list_for_each_entry (snap, &o->snapshots, list) - chunk_size = min_not_zero(chunk_size, snap->chunk_size); + chunk_size = min_not_zero(chunk_size, + snap->store->chunk_size); up_read(&_origins_lock); ti->split_io = chunk_size; diff --git a/trunk/drivers/md/dm-snap.h b/trunk/drivers/md/dm-snap.h deleted file mode 100644 index d9e62b43cf85..000000000000 --- a/trunk/drivers/md/dm-snap.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2001-2002 Sistina Software (UK) Limited. - * - * This file is released under the GPL. - */ - -#ifndef DM_SNAPSHOT_H -#define DM_SNAPSHOT_H - -#include -#include "dm-exception-store.h" -#include "dm-bio-list.h" -#include -#include - -struct exception_table { - uint32_t hash_mask; - unsigned hash_shift; - struct list_head *table; -}; - -#define DM_TRACKED_CHUNK_HASH_SIZE 16 -#define DM_TRACKED_CHUNK_HASH(x) ((unsigned long)(x) & \ - (DM_TRACKED_CHUNK_HASH_SIZE - 1)) - -struct dm_snapshot { - struct rw_semaphore lock; - struct dm_target *ti; - - struct dm_dev *origin; - struct dm_dev *cow; - - /* List of snapshots per Origin */ - struct list_head list; - - /* Size of data blocks saved - must be a power of 2 */ - chunk_t chunk_size; - chunk_t chunk_mask; - chunk_t chunk_shift; - - /* You can't use a snapshot if this is 0 (e.g. if full) */ - int valid; - - /* Origin writes don't trigger exceptions until this is set */ - int active; - - /* Used for display of table */ - char type; - - mempool_t *pending_pool; - - atomic_t pending_exceptions_count; - - struct exception_table pending; - struct exception_table complete; - - /* - * pe_lock protects all pending_exception operations and access - * as well as the snapshot_bios list. - */ - spinlock_t pe_lock; - - /* The on disk metadata handler */ - struct dm_exception_store store; - - struct dm_kcopyd_client *kcopyd_client; - - /* Queue of snapshot writes for ksnapd to flush */ - struct bio_list queued_bios; - struct work_struct queued_bios_work; - - /* Chunks with outstanding reads */ - mempool_t *tracked_chunk_pool; - spinlock_t tracked_chunk_lock; - struct hlist_head tracked_chunk_hash[DM_TRACKED_CHUNK_HASH_SIZE]; -}; - -/* - * Return the number of sectors in the device. - */ -static inline sector_t get_dev_size(struct block_device *bdev) -{ - return bdev->bd_inode->i_size >> SECTOR_SHIFT; -} - -static inline chunk_t sector_to_chunk(struct dm_snapshot *s, sector_t sector) -{ - return (sector & ~s->chunk_mask) >> s->chunk_shift; -} - -static inline sector_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk) -{ - return chunk << s->chunk_shift; -} - -static inline int bdev_equal(struct block_device *lhs, struct block_device *rhs) -{ - /* - * There is only ever one instance of a particular block - * device so we can compare pointers safely. - */ - return lhs == rhs; -} - -#endif diff --git a/trunk/drivers/md/dm-table.c b/trunk/drivers/md/dm-table.c index 2fd66c30f7f8..e8361b191b9b 100644 --- a/trunk/drivers/md/dm-table.c +++ b/trunk/drivers/md/dm-table.c @@ -399,28 +399,30 @@ static int check_device_area(struct dm_dev_internal *dd, sector_t start, } /* - * This upgrades the mode on an already open dm_dev. Being + * This upgrades the mode on an already open dm_dev, being * careful to leave things as they were if we fail to reopen the - * device. + * device and not to touch the existing bdev field in case + * it is accessed concurrently inside dm_table_any_congested(). */ static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode, struct mapped_device *md) { int r; - struct dm_dev_internal dd_copy; - dev_t dev = dd->dm_dev.bdev->bd_dev; + struct dm_dev_internal dd_new, dd_old; - dd_copy = *dd; + dd_new = dd_old = *dd; + + dd_new.dm_dev.mode |= new_mode; + dd_new.dm_dev.bdev = NULL; + + r = open_dev(&dd_new, dd->dm_dev.bdev->bd_dev, md); + if (r) + return r; dd->dm_dev.mode |= new_mode; - dd->dm_dev.bdev = NULL; - r = open_dev(dd, dev, md); - if (!r) - close_dev(&dd_copy, md); - else - *dd = dd_copy; + close_dev(&dd_old, md); - return r; + return 0; } /* diff --git a/trunk/drivers/md/dm-target.c b/trunk/drivers/md/dm-target.c index 7decf10006e4..04feccf2a997 100644 --- a/trunk/drivers/md/dm-target.c +++ b/trunk/drivers/md/dm-target.c @@ -14,45 +14,34 @@ #define DM_MSG_PREFIX "target" -struct tt_internal { - struct target_type tt; - - struct list_head list; - long use; -}; - static LIST_HEAD(_targets); static DECLARE_RWSEM(_lock); #define DM_MOD_NAME_SIZE 32 -static inline struct tt_internal *__find_target_type(const char *name) +static inline struct target_type *__find_target_type(const char *name) { - struct tt_internal *ti; + struct target_type *tt; - list_for_each_entry (ti, &_targets, list) - if (!strcmp(name, ti->tt.name)) - return ti; + list_for_each_entry(tt, &_targets, list) + if (!strcmp(name, tt->name)) + return tt; return NULL; } -static struct tt_internal *get_target_type(const char *name) +static struct target_type *get_target_type(const char *name) { - struct tt_internal *ti; + struct target_type *tt; down_read(&_lock); - ti = __find_target_type(name); - if (ti) { - if ((ti->use == 0) && !try_module_get(ti->tt.module)) - ti = NULL; - else - ti->use++; - } + tt = __find_target_type(name); + if (tt && !try_module_get(tt->module)) + tt = NULL; up_read(&_lock); - return ti; + return tt; } static void load_module(const char *name) @@ -62,92 +51,59 @@ static void load_module(const char *name) struct target_type *dm_get_target_type(const char *name) { - struct tt_internal *ti = get_target_type(name); + struct target_type *tt = get_target_type(name); - if (!ti) { + if (!tt) { load_module(name); - ti = get_target_type(name); + tt = get_target_type(name); } - return ti ? &ti->tt : NULL; + return tt; } -void dm_put_target_type(struct target_type *t) +void dm_put_target_type(struct target_type *tt) { - struct tt_internal *ti = (struct tt_internal *) t; - down_read(&_lock); - if (--ti->use == 0) - module_put(ti->tt.module); - - BUG_ON(ti->use < 0); + module_put(tt->module); up_read(&_lock); - - return; -} - -static struct tt_internal *alloc_target(struct target_type *t) -{ - struct tt_internal *ti = kzalloc(sizeof(*ti), GFP_KERNEL); - - if (ti) - ti->tt = *t; - - return ti; } - int dm_target_iterate(void (*iter_func)(struct target_type *tt, void *param), void *param) { - struct tt_internal *ti; + struct target_type *tt; down_read(&_lock); - list_for_each_entry (ti, &_targets, list) - iter_func(&ti->tt, param); + list_for_each_entry(tt, &_targets, list) + iter_func(tt, param); up_read(&_lock); return 0; } -int dm_register_target(struct target_type *t) +int dm_register_target(struct target_type *tt) { int rv = 0; - struct tt_internal *ti = alloc_target(t); - - if (!ti) - return -ENOMEM; down_write(&_lock); - if (__find_target_type(t->name)) + if (__find_target_type(tt->name)) rv = -EEXIST; else - list_add(&ti->list, &_targets); + list_add(&tt->list, &_targets); up_write(&_lock); - if (rv) - kfree(ti); return rv; } -void dm_unregister_target(struct target_type *t) +void dm_unregister_target(struct target_type *tt) { - struct tt_internal *ti; - down_write(&_lock); - if (!(ti = __find_target_type(t->name))) { - DMCRIT("Unregistering unrecognised target: %s", t->name); - BUG(); - } - - if (ti->use) { - DMCRIT("Attempt to unregister target still in use: %s", - t->name); + if (!__find_target_type(tt->name)) { + DMCRIT("Unregistering unrecognised target: %s", tt->name); BUG(); } - list_del(&ti->list); - kfree(ti); + list_del(&tt->list); up_write(&_lock); } @@ -156,17 +112,17 @@ void dm_unregister_target(struct target_type *t) * io-err: always fails an io, useful for bringing * up LVs that have holes in them. */ -static int io_err_ctr(struct dm_target *ti, unsigned int argc, char **args) +static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args) { return 0; } -static void io_err_dtr(struct dm_target *ti) +static void io_err_dtr(struct dm_target *tt) { /* empty */ } -static int io_err_map(struct dm_target *ti, struct bio *bio, +static int io_err_map(struct dm_target *tt, struct bio *bio, union map_info *map_context) { return -EIO; diff --git a/trunk/drivers/md/dm.c b/trunk/drivers/md/dm.c index 8d40f27cce89..788ba96a6256 100644 --- a/trunk/drivers/md/dm.c +++ b/trunk/drivers/md/dm.c @@ -99,19 +99,9 @@ union map_info *dm_get_mapinfo(struct bio *bio) /* * Work processed by per-device workqueue. */ -struct dm_wq_req { - enum { - DM_WQ_FLUSH_DEFERRED, - } type; - struct work_struct work; - struct mapped_device *md; - void *context; -}; - struct mapped_device { struct rw_semaphore io_lock; struct mutex suspend_lock; - spinlock_t pushback_lock; rwlock_t map_lock; atomic_t holders; atomic_t open_count; @@ -129,8 +119,9 @@ struct mapped_device { */ atomic_t pending; wait_queue_head_t wait; + struct work_struct work; struct bio_list deferred; - struct bio_list pushback; + spinlock_t deferred_lock; /* * Processing queue (flush/barriers) @@ -453,7 +444,9 @@ static int queue_io(struct mapped_device *md, struct bio *bio) return 1; } + spin_lock_irq(&md->deferred_lock); bio_list_add(&md->deferred, bio); + spin_unlock_irq(&md->deferred_lock); up_write(&md->io_lock); return 0; /* deferred successfully */ @@ -537,16 +530,14 @@ static void dec_pending(struct dm_io *io, int error) if (io->error == DM_ENDIO_REQUEUE) { /* * Target requested pushing back the I/O. - * This must be handled before the sleeper on - * suspend queue merges the pushback list. */ - spin_lock_irqsave(&md->pushback_lock, flags); + spin_lock_irqsave(&md->deferred_lock, flags); if (__noflush_suspending(md)) - bio_list_add(&md->pushback, io->bio); + bio_list_add(&md->deferred, io->bio); else /* noflush suspend was interrupted. */ io->error = -EIO; - spin_unlock_irqrestore(&md->pushback_lock, flags); + spin_unlock_irqrestore(&md->deferred_lock, flags); } end_io_acct(io); @@ -834,20 +825,22 @@ static int __clone_and_map(struct clone_info *ci) } /* - * Split the bio into several clones. + * Split the bio into several clones and submit it to targets. */ -static int __split_bio(struct mapped_device *md, struct bio *bio) +static void __split_and_process_bio(struct mapped_device *md, struct bio *bio) { struct clone_info ci; int error = 0; ci.map = dm_get_table(md); - if (unlikely(!ci.map)) - return -EIO; + if (unlikely(!ci.map)) { + bio_io_error(bio); + return; + } if (unlikely(bio_barrier(bio) && !dm_table_barrier_ok(ci.map))) { dm_table_put(ci.map); bio_endio(bio, -EOPNOTSUPP); - return 0; + return; } ci.md = md; ci.bio = bio; @@ -867,8 +860,6 @@ static int __split_bio(struct mapped_device *md, struct bio *bio) /* drop the extra reference count */ dec_pending(ci.io, error); dm_table_put(ci.map); - - return 0; } /*----------------------------------------------------------------- * CRUD END @@ -959,8 +950,9 @@ static int dm_request(struct request_queue *q, struct bio *bio) down_read(&md->io_lock); } - r = __split_bio(md, bio); + __split_and_process_bio(md, bio); up_read(&md->io_lock); + return 0; out_req: if (r < 0) @@ -1074,6 +1066,8 @@ static int next_free_minor(int *minor) static struct block_device_operations dm_blk_dops; +static void dm_wq_work(struct work_struct *work); + /* * Allocate and initialise a blank device with a given minor. */ @@ -1101,7 +1095,7 @@ static struct mapped_device *alloc_dev(int minor) init_rwsem(&md->io_lock); mutex_init(&md->suspend_lock); - spin_lock_init(&md->pushback_lock); + spin_lock_init(&md->deferred_lock); rwlock_init(&md->map_lock); atomic_set(&md->holders, 1); atomic_set(&md->open_count, 0); @@ -1118,6 +1112,7 @@ static struct mapped_device *alloc_dev(int minor) md->queue->backing_dev_info.congested_fn = dm_any_congested; md->queue->backing_dev_info.congested_data = md; blk_queue_make_request(md->queue, dm_request); + blk_queue_ordered(md->queue, QUEUE_ORDERED_DRAIN, NULL); blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); md->queue->unplug_fn = dm_unplug_all; blk_queue_merge_bvec(md->queue, dm_merge_bvec); @@ -1140,6 +1135,7 @@ static struct mapped_device *alloc_dev(int minor) atomic_set(&md->pending, 0); init_waitqueue_head(&md->wait); + INIT_WORK(&md->work, dm_wq_work); init_waitqueue_head(&md->eventq); md->disk->major = _major; @@ -1379,18 +1375,24 @@ void dm_put(struct mapped_device *md) } EXPORT_SYMBOL_GPL(dm_put); -static int dm_wait_for_completion(struct mapped_device *md) +static int dm_wait_for_completion(struct mapped_device *md, int interruptible) { int r = 0; + DECLARE_WAITQUEUE(wait, current); + + dm_unplug_all(md->queue); + + add_wait_queue(&md->wait, &wait); while (1) { - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(interruptible); smp_mb(); if (!atomic_read(&md->pending)) break; - if (signal_pending(current)) { + if (interruptible == TASK_INTERRUPTIBLE && + signal_pending(current)) { r = -EINTR; break; } @@ -1399,67 +1401,40 @@ static int dm_wait_for_completion(struct mapped_device *md) } set_current_state(TASK_RUNNING); + remove_wait_queue(&md->wait, &wait); + return r; } /* * Process the deferred bios */ -static void __flush_deferred_io(struct mapped_device *md) +static void dm_wq_work(struct work_struct *work) { + struct mapped_device *md = container_of(work, struct mapped_device, + work); struct bio *c; - while ((c = bio_list_pop(&md->deferred))) { - if (__split_bio(md, c)) - bio_io_error(c); - } - - clear_bit(DMF_BLOCK_IO, &md->flags); -} + down_write(&md->io_lock); -static void __merge_pushback_list(struct mapped_device *md) -{ - unsigned long flags; +next_bio: + spin_lock_irq(&md->deferred_lock); + c = bio_list_pop(&md->deferred); + spin_unlock_irq(&md->deferred_lock); - spin_lock_irqsave(&md->pushback_lock, flags); - clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); - bio_list_merge_head(&md->deferred, &md->pushback); - bio_list_init(&md->pushback); - spin_unlock_irqrestore(&md->pushback_lock, flags); -} + if (c) { + __split_and_process_bio(md, c); + goto next_bio; + } -static void dm_wq_work(struct work_struct *work) -{ - struct dm_wq_req *req = container_of(work, struct dm_wq_req, work); - struct mapped_device *md = req->md; + clear_bit(DMF_BLOCK_IO, &md->flags); - down_write(&md->io_lock); - switch (req->type) { - case DM_WQ_FLUSH_DEFERRED: - __flush_deferred_io(md); - break; - default: - DMERR("dm_wq_work: unrecognised work type %d", req->type); - BUG(); - } up_write(&md->io_lock); } -static void dm_wq_queue(struct mapped_device *md, int type, void *context, - struct dm_wq_req *req) -{ - req->type = type; - req->md = md; - req->context = context; - INIT_WORK(&req->work, dm_wq_work); - queue_work(md->wq, &req->work); -} - -static void dm_queue_flush(struct mapped_device *md, int type, void *context) +static void dm_queue_flush(struct mapped_device *md) { - struct dm_wq_req req; - - dm_wq_queue(md, type, context, &req); + queue_work(md->wq, &md->work); flush_workqueue(md->wq); } @@ -1534,7 +1509,6 @@ static void unlock_fs(struct mapped_device *md) int dm_suspend(struct mapped_device *md, unsigned suspend_flags) { struct dm_table *map = NULL; - DECLARE_WAITQUEUE(wait, current); int r = 0; int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0; int noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG ? 1 : 0; @@ -1584,28 +1558,22 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags) down_write(&md->io_lock); set_bit(DMF_BLOCK_IO, &md->flags); - add_wait_queue(&md->wait, &wait); up_write(&md->io_lock); - /* unplug */ - if (map) - dm_table_unplug_all(map); - /* * Wait for the already-mapped ios to complete. */ - r = dm_wait_for_completion(md); + r = dm_wait_for_completion(md, TASK_INTERRUPTIBLE); down_write(&md->io_lock); - remove_wait_queue(&md->wait, &wait); if (noflush) - __merge_pushback_list(md); + clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags); up_write(&md->io_lock); /* were we interrupted ? */ if (r < 0) { - dm_queue_flush(md, DM_WQ_FLUSH_DEFERRED, NULL); + dm_queue_flush(md); unlock_fs(md); goto out; /* pushback list is already flushed, so skip flush */ @@ -1645,7 +1613,7 @@ int dm_resume(struct mapped_device *md) if (r) goto out; - dm_queue_flush(md, DM_WQ_FLUSH_DEFERRED, NULL); + dm_queue_flush(md); unlock_fs(md); diff --git a/trunk/drivers/md/dm.h b/trunk/drivers/md/dm.h index 20194e000c5a..b48397c0abbd 100644 --- a/trunk/drivers/md/dm.h +++ b/trunk/drivers/md/dm.h @@ -60,7 +60,7 @@ int dm_table_barrier_ok(struct dm_table *t); int dm_target_init(void); void dm_target_exit(void); struct target_type *dm_get_target_type(const char *name); -void dm_put_target_type(struct target_type *t); +void dm_put_target_type(struct target_type *tt); int dm_target_iterate(void (*iter_func)(struct target_type *tt, void *param), void *param); diff --git a/trunk/drivers/md/faulty.c b/trunk/drivers/md/faulty.c index 86d9adf90e79..8695809b24b0 100644 --- a/trunk/drivers/md/faulty.c +++ b/trunk/drivers/md/faulty.c @@ -62,7 +62,10 @@ #define ModeShift 5 #define MaxFault 50 -#include +#include +#include +#include "md.h" +#include static void faulty_fail(struct bio *bio, int error) @@ -280,6 +283,17 @@ static int reconfig(mddev_t *mddev, int layout, int chunk_size) return 0; } +static sector_t faulty_size(mddev_t *mddev, sector_t sectors, int raid_disks) +{ + WARN_ONCE(raid_disks, + "%s does not support generic reshape\n", __func__); + + if (sectors == 0) + return mddev->dev_sectors; + + return sectors; +} + static int run(mddev_t *mddev) { mdk_rdev_t *rdev; @@ -298,7 +312,7 @@ static int run(mddev_t *mddev) list_for_each_entry(rdev, &mddev->disks, same_set) conf->rdev = rdev; - mddev->array_sectors = mddev->size * 2; + md_set_array_sectors(mddev, faulty_size(mddev, 0, 0)); mddev->private = conf; reconfig(mddev, mddev->layout, -1); @@ -325,6 +339,7 @@ static struct mdk_personality faulty_personality = .stop = stop, .status = status, .reconfig = reconfig, + .size = faulty_size, }; static int __init raid_init(void) diff --git a/trunk/drivers/md/linear.c b/trunk/drivers/md/linear.c index 09658b218474..7a36e38393a1 100644 --- a/trunk/drivers/md/linear.c +++ b/trunk/drivers/md/linear.c @@ -16,7 +16,11 @@ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include +#include +#include +#include "md.h" +#include "linear.h" /* * find which device holds a particular offset @@ -97,6 +101,16 @@ static int linear_congested(void *data, int bits) return ret; } +static sector_t linear_size(mddev_t *mddev, sector_t sectors, int raid_disks) +{ + linear_conf_t *conf = mddev_to_conf(mddev); + + WARN_ONCE(sectors || raid_disks, + "%s does not support generic reshape\n", __func__); + + return conf->array_sectors; +} + static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) { linear_conf_t *conf; @@ -135,8 +149,8 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) mddev->queue->max_sectors > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); - disk->num_sectors = rdev->size * 2; - conf->array_sectors += rdev->size * 2; + disk->num_sectors = rdev->sectors; + conf->array_sectors += rdev->sectors; cnt++; } @@ -249,7 +263,7 @@ static int linear_run (mddev_t *mddev) if (!conf) return 1; mddev->private = conf; - mddev->array_sectors = conf->array_sectors; + md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); mddev->queue->unplug_fn = linear_unplug; @@ -283,7 +297,7 @@ static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev) newconf->prev = mddev_to_conf(mddev); mddev->private = newconf; mddev->raid_disks++; - mddev->array_sectors = newconf->array_sectors; + md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); set_capacity(mddev->gendisk, mddev->array_sectors); return 0; } @@ -381,6 +395,7 @@ static struct mdk_personality linear_personality = .stop = linear_stop, .status = linear_status, .hot_add_disk = linear_add, + .size = linear_size, }; static int __init linear_init (void) diff --git a/trunk/include/linux/raid/linear.h b/trunk/drivers/md/linear.h similarity index 95% rename from trunk/include/linux/raid/linear.h rename to trunk/drivers/md/linear.h index f38b9c586afb..bf8179587f95 100644 --- a/trunk/include/linux/raid/linear.h +++ b/trunk/drivers/md/linear.h @@ -1,8 +1,6 @@ #ifndef _LINEAR_H #define _LINEAR_H -#include - struct dev_info { mdk_rdev_t *rdev; sector_t num_sectors; diff --git a/trunk/drivers/md/md.c b/trunk/drivers/md/md.c index a307f87eb90e..ed5727c089a9 100644 --- a/trunk/drivers/md/md.c +++ b/trunk/drivers/md/md.c @@ -33,9 +33,9 @@ */ #include -#include -#include +#include #include +#include #include /* for invalidate_bdev */ #include #include @@ -45,11 +45,10 @@ #include #include #include - -#define MAJOR_NR MD_MAJOR - -/* 63 partitions with the alternate major number (mdp) */ -#define MdpMinorShift 6 +#include +#include +#include "md.h" +#include "bitmap.h" #define DEBUG 0 #define dprintk(x...) ((void)(DEBUG && printk(x))) @@ -202,12 +201,68 @@ static DEFINE_SPINLOCK(all_mddevs_lock); ) -static int md_fail_request(struct request_queue *q, struct bio *bio) +/* Rather than calling directly into the personality make_request function, + * IO requests come here first so that we can check if the device is + * being suspended pending a reconfiguration. + * We hold a refcount over the call to ->make_request. By the time that + * call has finished, the bio has been linked into some internal structure + * and so is visible to ->quiesce(), so we don't need the refcount any more. + */ +static int md_make_request(struct request_queue *q, struct bio *bio) { - bio_io_error(bio); - return 0; + mddev_t *mddev = q->queuedata; + int rv; + if (mddev == NULL || mddev->pers == NULL) { + bio_io_error(bio); + return 0; + } + rcu_read_lock(); + if (mddev->suspended) { + DEFINE_WAIT(__wait); + for (;;) { + prepare_to_wait(&mddev->sb_wait, &__wait, + TASK_UNINTERRUPTIBLE); + if (!mddev->suspended) + break; + rcu_read_unlock(); + schedule(); + rcu_read_lock(); + } + finish_wait(&mddev->sb_wait, &__wait); + } + atomic_inc(&mddev->active_io); + rcu_read_unlock(); + rv = mddev->pers->make_request(q, bio); + if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended) + wake_up(&mddev->sb_wait); + + return rv; +} + +static void mddev_suspend(mddev_t *mddev) +{ + BUG_ON(mddev->suspended); + mddev->suspended = 1; + synchronize_rcu(); + wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0); + mddev->pers->quiesce(mddev, 1); + md_unregister_thread(mddev->thread); + mddev->thread = NULL; + /* we now know that no code is executing in the personality module, + * except possibly the tail end of a ->bi_end_io function, but that + * is certain to complete before the module has a chance to get + * unloaded + */ +} + +static void mddev_resume(mddev_t *mddev) +{ + mddev->suspended = 0; + wake_up(&mddev->sb_wait); + mddev->pers->quiesce(mddev, 0); } + static inline mddev_t *mddev_get(mddev_t *mddev) { atomic_inc(&mddev->active); @@ -310,6 +365,7 @@ static mddev_t * mddev_find(dev_t unit) init_timer(&new->safemode_timer); atomic_set(&new->active, 1); atomic_set(&new->openers, 0); + atomic_set(&new->active_io, 0); spin_lock_init(&new->write_lock); init_waitqueue_head(&new->sb_wait); init_waitqueue_head(&new->recovery_wait); @@ -326,6 +382,11 @@ static inline int mddev_lock(mddev_t * mddev) return mutex_lock_interruptible(&mddev->reconfig_mutex); } +static inline int mddev_is_locked(mddev_t *mddev) +{ + return mutex_is_locked(&mddev->reconfig_mutex); +} + static inline int mddev_trylock(mddev_t * mddev) { return mutex_trylock(&mddev->reconfig_mutex); @@ -409,7 +470,7 @@ static void free_disk_sb(mdk_rdev_t * rdev) rdev->sb_loaded = 0; rdev->sb_page = NULL; rdev->sb_start = 0; - rdev->size = 0; + rdev->sectors = 0; } } @@ -775,9 +836,9 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version else ret = 0; } - rdev->size = calc_num_sectors(rdev, sb->chunk_size) / 2; + rdev->sectors = calc_num_sectors(rdev, sb->chunk_size); - if (rdev->size < sb->size && sb->level > 1) + if (rdev->sectors < sb->size * 2 && sb->level > 1) /* "this cannot possibly happen" ... */ ret = -EINVAL; @@ -812,7 +873,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->clevel[0] = 0; mddev->layout = sb->layout; mddev->raid_disks = sb->raid_disks; - mddev->size = sb->size; + mddev->dev_sectors = sb->size * 2; mddev->events = ev1; mddev->bitmap_offset = 0; mddev->default_bitmap_offset = MD_SB_BYTES >> 9; @@ -926,7 +987,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->ctime = mddev->ctime; sb->level = mddev->level; - sb->size = mddev->size; + sb->size = mddev->dev_sectors / 2; sb->raid_disks = mddev->raid_disks; sb->md_minor = mddev->md_minor; sb->not_persistent = 0; @@ -1024,7 +1085,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) static unsigned long long super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors) { - if (num_sectors && num_sectors < rdev->mddev->size * 2) + if (num_sectors && num_sectors < rdev->mddev->dev_sectors) return 0; /* component must fit device */ if (rdev->mddev->bitmap_offset) return 0; /* can't move bitmap */ @@ -1180,16 +1241,17 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) ret = 0; } if (minor_version) - rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2; + rdev->sectors = (rdev->bdev->bd_inode->i_size >> 9) - + le64_to_cpu(sb->data_offset); else - rdev->size = rdev->sb_start / 2; - if (rdev->size < le64_to_cpu(sb->data_size)/2) + rdev->sectors = rdev->sb_start; + if (rdev->sectors < le64_to_cpu(sb->data_size)) return -EINVAL; - rdev->size = le64_to_cpu(sb->data_size)/2; + rdev->sectors = le64_to_cpu(sb->data_size); if (le32_to_cpu(sb->chunksize)) - rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1); + rdev->sectors &= ~((sector_t)le32_to_cpu(sb->chunksize) - 1); - if (le64_to_cpu(sb->size) > rdev->size*2) + if (le64_to_cpu(sb->size) > rdev->sectors) return -EINVAL; return ret; } @@ -1216,7 +1278,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) mddev->clevel[0] = 0; mddev->layout = le32_to_cpu(sb->layout); mddev->raid_disks = le32_to_cpu(sb->raid_disks); - mddev->size = le64_to_cpu(sb->size)/2; + mddev->dev_sectors = le64_to_cpu(sb->size); mddev->events = ev1; mddev->bitmap_offset = 0; mddev->default_bitmap_offset = 1024 >> 9; @@ -1312,7 +1374,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors)); sb->raid_disks = cpu_to_le32(mddev->raid_disks); - sb->size = cpu_to_le64(mddev->size<<1); + sb->size = cpu_to_le64(mddev->dev_sectors); if (mddev->bitmap && mddev->bitmap_file == NULL) { sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); @@ -1320,10 +1382,15 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) } if (rdev->raid_disk >= 0 && - !test_bit(In_sync, &rdev->flags) && - rdev->recovery_offset > 0) { - sb->feature_map |= cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET); - sb->recovery_offset = cpu_to_le64(rdev->recovery_offset); + !test_bit(In_sync, &rdev->flags)) { + if (mddev->curr_resync_completed > rdev->recovery_offset) + rdev->recovery_offset = mddev->curr_resync_completed; + if (rdev->recovery_offset > 0) { + sb->feature_map |= + cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET); + sb->recovery_offset = + cpu_to_le64(rdev->recovery_offset); + } } if (mddev->reshape_position != MaxSector) { @@ -1365,7 +1432,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors) { struct mdp_superblock_1 *sb; sector_t max_sectors; - if (num_sectors && num_sectors < rdev->mddev->size * 2) + if (num_sectors && num_sectors < rdev->mddev->dev_sectors) return 0; /* component must fit device */ if (rdev->sb_start < rdev->data_offset) { /* minor versions 1 and 2; superblock before data */ @@ -1381,7 +1448,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors) sector_t sb_start; sb_start = (rdev->bdev->bd_inode->i_size >> 9) - 8*2; sb_start &= ~(sector_t)(4*2 - 1); - max_sectors = rdev->size * 2 + sb_start - rdev->sb_start; + max_sectors = rdev->sectors + sb_start - rdev->sb_start; if (!num_sectors || num_sectors > max_sectors) num_sectors = max_sectors; rdev->sb_start = sb_start; @@ -1433,6 +1500,38 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) static LIST_HEAD(pending_raid_disks); +static void md_integrity_check(mdk_rdev_t *rdev, mddev_t *mddev) +{ + struct mdk_personality *pers = mddev->pers; + struct gendisk *disk = mddev->gendisk; + struct blk_integrity *bi_rdev = bdev_get_integrity(rdev->bdev); + struct blk_integrity *bi_mddev = blk_get_integrity(disk); + + /* Data integrity passthrough not supported on RAID 4, 5 and 6 */ + if (pers && pers->level >= 4 && pers->level <= 6) + return; + + /* If rdev is integrity capable, register profile for mddev */ + if (!bi_mddev && bi_rdev) { + if (blk_integrity_register(disk, bi_rdev)) + printk(KERN_ERR "%s: %s Could not register integrity!\n", + __func__, disk->disk_name); + else + printk(KERN_NOTICE "Enabling data integrity on %s\n", + disk->disk_name); + return; + } + + /* Check that mddev and rdev have matching profiles */ + if (blk_integrity_compare(disk, rdev->bdev->bd_disk) < 0) { + printk(KERN_ERR "%s: %s/%s integrity mismatch!\n", __func__, + disk->disk_name, rdev->bdev->bd_disk->disk_name); + printk(KERN_NOTICE "Disabling data integrity on %s\n", + disk->disk_name); + blk_integrity_unregister(disk); + } +} + static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) { char b[BDEVNAME_SIZE]; @@ -1449,8 +1548,9 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) if (find_rdev(mddev, rdev->bdev->bd_dev)) return -EEXIST; - /* make sure rdev->size exceeds mddev->size */ - if (rdev->size && (mddev->size == 0 || rdev->size < mddev->size)) { + /* make sure rdev->sectors exceeds mddev->dev_sectors */ + if (rdev->sectors && (mddev->dev_sectors == 0 || + rdev->sectors < mddev->dev_sectors)) { if (mddev->pers) { /* Cannot change size, so fail * If mddev->level <= 0, then we don't care @@ -1459,7 +1559,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) if (mddev->level > 0) return -ENOSPC; } else - mddev->size = rdev->size; + mddev->dev_sectors = rdev->sectors; } /* Verify rdev->desc_nr is unique. @@ -1503,6 +1603,8 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) /* May as well allow recovery to be retried once */ mddev->recovery_disabled = 0; + + md_integrity_check(rdev, mddev); return 0; fail: @@ -1713,8 +1815,8 @@ static void print_sb_1(struct mdp_superblock_1 *sb) static void print_rdev(mdk_rdev_t *rdev, int major_version) { char b[BDEVNAME_SIZE]; - printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n", - bdevname(rdev->bdev,b), (unsigned long long)rdev->size, + printk(KERN_INFO "md: rdev %s, Sect:%08llu F:%d S:%d DN:%u\n", + bdevname(rdev->bdev, b), (unsigned long long)rdev->sectors, test_bit(Faulty, &rdev->flags), test_bit(In_sync, &rdev->flags), rdev->desc_nr); if (rdev->sb_loaded) { @@ -2153,7 +2255,7 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len) return -EINVAL; if (rdev->mddev->pers && rdev->raid_disk >= 0) return -EBUSY; - if (rdev->size && rdev->mddev->external) + if (rdev->sectors && rdev->mddev->external) /* Must set offset before size, so overlap checks * can be sane */ return -EBUSY; @@ -2167,7 +2269,7 @@ __ATTR(offset, S_IRUGO|S_IWUSR, offset_show, offset_store); static ssize_t rdev_size_show(mdk_rdev_t *rdev, char *page) { - return sprintf(page, "%llu\n", (unsigned long long)rdev->size); + return sprintf(page, "%llu\n", (unsigned long long)rdev->sectors / 2); } static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2) @@ -2180,34 +2282,52 @@ static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2) return 1; } +static int strict_blocks_to_sectors(const char *buf, sector_t *sectors) +{ + unsigned long long blocks; + sector_t new; + + if (strict_strtoull(buf, 10, &blocks) < 0) + return -EINVAL; + + if (blocks & 1ULL << (8 * sizeof(blocks) - 1)) + return -EINVAL; /* sector conversion overflow */ + + new = blocks * 2; + if (new != blocks * 2) + return -EINVAL; /* unsigned long long to sector_t overflow */ + + *sectors = new; + return 0; +} + static ssize_t rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) { - unsigned long long size; - unsigned long long oldsize = rdev->size; mddev_t *my_mddev = rdev->mddev; + sector_t oldsectors = rdev->sectors; + sector_t sectors; - if (strict_strtoull(buf, 10, &size) < 0) + if (strict_blocks_to_sectors(buf, §ors) < 0) return -EINVAL; if (my_mddev->pers && rdev->raid_disk >= 0) { if (my_mddev->persistent) { - size = super_types[my_mddev->major_version]. - rdev_size_change(rdev, size * 2); - if (!size) + sectors = super_types[my_mddev->major_version]. + rdev_size_change(rdev, sectors); + if (!sectors) return -EBUSY; - } else if (!size) { - size = (rdev->bdev->bd_inode->i_size >> 10); - size -= rdev->data_offset/2; - } + } else if (!sectors) + sectors = (rdev->bdev->bd_inode->i_size >> 9) - + rdev->data_offset; } - if (size < my_mddev->size) + if (sectors < my_mddev->dev_sectors) return -EINVAL; /* component must fit device */ - rdev->size = size; - if (size > oldsize && my_mddev->external) { + rdev->sectors = sectors; + if (sectors > oldsectors && my_mddev->external) { /* need to check that all other rdevs with the same ->bdev * do not overlap. We need to unlock the mddev to avoid - * a deadlock. We have already changed rdev->size, and if + * a deadlock. We have already changed rdev->sectors, and if * we have to change it back, we will have the lock again. */ mddev_t *mddev; @@ -2223,9 +2343,9 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) if (test_bit(AllReserved, &rdev2->flags) || (rdev->bdev == rdev2->bdev && rdev != rdev2 && - overlaps(rdev->data_offset, rdev->size * 2, + overlaps(rdev->data_offset, rdev->sectors, rdev2->data_offset, - rdev2->size * 2))) { + rdev2->sectors))) { overlap = 1; break; } @@ -2239,11 +2359,11 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) if (overlap) { /* Someone else could have slipped in a size * change here, but doing so is just silly. - * We put oldsize back because we *know* it is + * We put oldsectors back because we *know* it is * safe, and trust userspace not to race with * itself */ - rdev->size = oldsize; + rdev->sectors = oldsectors; return -EBUSY; } } @@ -2547,18 +2667,101 @@ level_show(mddev_t *mddev, char *page) static ssize_t level_store(mddev_t *mddev, const char *buf, size_t len) { + char level[16]; ssize_t rv = len; - if (mddev->pers) + struct mdk_personality *pers; + void *priv; + + if (mddev->pers == NULL) { + if (len == 0) + return 0; + if (len >= sizeof(mddev->clevel)) + return -ENOSPC; + strncpy(mddev->clevel, buf, len); + if (mddev->clevel[len-1] == '\n') + len--; + mddev->clevel[len] = 0; + mddev->level = LEVEL_NONE; + return rv; + } + + /* request to change the personality. Need to ensure: + * - array is not engaged in resync/recovery/reshape + * - old personality can be suspended + * - new personality will access other array. + */ + + if (mddev->sync_thread || mddev->reshape_position != MaxSector) return -EBUSY; - if (len == 0) - return 0; - if (len >= sizeof(mddev->clevel)) - return -ENOSPC; - strncpy(mddev->clevel, buf, len); - if (mddev->clevel[len-1] == '\n') + + if (!mddev->pers->quiesce) { + printk(KERN_WARNING "md: %s: %s does not support online personality change\n", + mdname(mddev), mddev->pers->name); + return -EINVAL; + } + + /* Now find the new personality */ + if (len == 0 || len >= sizeof(level)) + return -EINVAL; + strncpy(level, buf, len); + if (level[len-1] == '\n') len--; - mddev->clevel[len] = 0; - mddev->level = LEVEL_NONE; + level[len] = 0; + + request_module("md-%s", level); + spin_lock(&pers_lock); + pers = find_pers(LEVEL_NONE, level); + if (!pers || !try_module_get(pers->owner)) { + spin_unlock(&pers_lock); + printk(KERN_WARNING "md: personality %s not loaded\n", level); + return -EINVAL; + } + spin_unlock(&pers_lock); + + if (pers == mddev->pers) { + /* Nothing to do! */ + module_put(pers->owner); + return rv; + } + if (!pers->takeover) { + module_put(pers->owner); + printk(KERN_WARNING "md: %s: %s does not support personality takeover\n", + mdname(mddev), level); + return -EINVAL; + } + + /* ->takeover must set new_* and/or delta_disks + * if it succeeds, and may set them when it fails. + */ + priv = pers->takeover(mddev); + if (IS_ERR(priv)) { + mddev->new_level = mddev->level; + mddev->new_layout = mddev->layout; + mddev->new_chunk = mddev->chunk_size; + mddev->raid_disks -= mddev->delta_disks; + mddev->delta_disks = 0; + module_put(pers->owner); + printk(KERN_WARNING "md: %s: %s would not accept array\n", + mdname(mddev), level); + return PTR_ERR(priv); + } + + /* Looks like we have a winner */ + mddev_suspend(mddev); + mddev->pers->stop(mddev); + module_put(mddev->pers->owner); + mddev->pers = pers; + mddev->private = priv; + strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); + mddev->level = mddev->new_level; + mddev->layout = mddev->new_layout; + mddev->chunk_size = mddev->new_chunk; + mddev->delta_disks = 0; + pers->run(mddev); + mddev_resume(mddev); + set_bit(MD_CHANGE_DEVS, &mddev->flags); + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + md_wakeup_thread(mddev->thread); return rv; } @@ -2586,12 +2789,18 @@ layout_store(mddev_t *mddev, const char *buf, size_t len) if (!*buf || (*e && *e != '\n')) return -EINVAL; - if (mddev->pers) - return -EBUSY; - if (mddev->reshape_position != MaxSector) + if (mddev->pers) { + int err; + if (mddev->pers->reconfig == NULL) + return -EBUSY; + err = mddev->pers->reconfig(mddev, n, -1); + if (err) + return err; + } else { mddev->new_layout = n; - else - mddev->layout = n; + if (mddev->reshape_position == MaxSector) + mddev->layout = n; + } return len; } static struct md_sysfs_entry md_layout = @@ -2648,19 +2857,24 @@ chunk_size_show(mddev_t *mddev, char *page) static ssize_t chunk_size_store(mddev_t *mddev, const char *buf, size_t len) { - /* can only set chunk_size if array is not yet active */ char *e; unsigned long n = simple_strtoul(buf, &e, 10); if (!*buf || (*e && *e != '\n')) return -EINVAL; - if (mddev->pers) - return -EBUSY; - else if (mddev->reshape_position != MaxSector) + if (mddev->pers) { + int err; + if (mddev->pers->reconfig == NULL) + return -EBUSY; + err = mddev->pers->reconfig(mddev, -1, n); + if (err) + return err; + } else { mddev->new_chunk = n; - else - mddev->chunk_size = n; + if (mddev->reshape_position == MaxSector) + mddev->chunk_size = n; + } return len; } static struct md_sysfs_entry md_chunk_size = @@ -2669,6 +2883,8 @@ __ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store); static ssize_t resync_start_show(mddev_t *mddev, char *page) { + if (mddev->recovery_cp == MaxSector) + return sprintf(page, "none\n"); return sprintf(page, "%llu\n", (unsigned long long)mddev->recovery_cp); } @@ -2766,7 +2982,7 @@ array_state_show(mddev_t *mddev, char *page) else { if (list_empty(&mddev->disks) && mddev->raid_disks == 0 && - mddev->size == 0) + mddev->dev_sectors == 0) st = clear; else st = inactive; @@ -2973,7 +3189,8 @@ __ATTR(bitmap_set_bits, S_IWUSR, null_show, bitmap_store); static ssize_t size_show(mddev_t *mddev, char *page) { - return sprintf(page, "%llu\n", (unsigned long long)mddev->size); + return sprintf(page, "%llu\n", + (unsigned long long)mddev->dev_sectors / 2); } static int update_size(mddev_t *mddev, sector_t num_sectors); @@ -2985,20 +3202,18 @@ size_store(mddev_t *mddev, const char *buf, size_t len) * not increase it (except from 0). * If array is active, we can try an on-line resize */ - char *e; - int err = 0; - unsigned long long size = simple_strtoull(buf, &e, 10); - if (!*buf || *buf == '\n' || - (*e && *e != '\n')) - return -EINVAL; + sector_t sectors; + int err = strict_blocks_to_sectors(buf, §ors); + if (err < 0) + return err; if (mddev->pers) { - err = update_size(mddev, size * 2); + err = update_size(mddev, sectors); md_update_sb(mddev, 1); } else { - if (mddev->size == 0 || - mddev->size > size) - mddev->size = size; + if (mddev->dev_sectors == 0 || + mddev->dev_sectors > sectors) + mddev->dev_sectors = sectors; else err = -ENOSPC; } @@ -3251,6 +3466,8 @@ static ssize_t sync_speed_show(mddev_t *mddev, char *page) { unsigned long resync, dt, db; + if (mddev->curr_resync == 0) + return sprintf(page, "none\n"); resync = mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active); dt = (jiffies - mddev->resync_mark) / HZ; if (!dt) dt++; @@ -3263,15 +3480,15 @@ static struct md_sysfs_entry md_sync_speed = __ATTR_RO(sync_speed); static ssize_t sync_completed_show(mddev_t *mddev, char *page) { - unsigned long max_blocks, resync; + unsigned long max_sectors, resync; if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) - max_blocks = mddev->resync_max_sectors; + max_sectors = mddev->resync_max_sectors; else - max_blocks = mddev->size << 1; + max_sectors = mddev->dev_sectors; resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active)); - return sprintf(page, "%lu / %lu\n", resync, max_blocks); + return sprintf(page, "%lu / %lu\n", resync, max_sectors); } static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed); @@ -3431,6 +3648,57 @@ static struct md_sysfs_entry md_reshape_position = __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show, reshape_position_store); +static ssize_t +array_size_show(mddev_t *mddev, char *page) +{ + if (mddev->external_size) + return sprintf(page, "%llu\n", + (unsigned long long)mddev->array_sectors/2); + else + return sprintf(page, "default\n"); +} + +static ssize_t +array_size_store(mddev_t *mddev, const char *buf, size_t len) +{ + sector_t sectors; + + if (strncmp(buf, "default", 7) == 0) { + if (mddev->pers) + sectors = mddev->pers->size(mddev, 0, 0); + else + sectors = mddev->array_sectors; + + mddev->external_size = 0; + } else { + if (strict_blocks_to_sectors(buf, §ors) < 0) + return -EINVAL; + if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) + return -EINVAL; + + mddev->external_size = 1; + } + + mddev->array_sectors = sectors; + set_capacity(mddev->gendisk, mddev->array_sectors); + if (mddev->pers) { + struct block_device *bdev = bdget_disk(mddev->gendisk, 0); + + if (bdev) { + mutex_lock(&bdev->bd_inode->i_mutex); + i_size_write(bdev->bd_inode, + (loff_t)mddev->array_sectors << 9); + mutex_unlock(&bdev->bd_inode->i_mutex); + bdput(bdev); + } + } + + return len; +} + +static struct md_sysfs_entry md_array_size = +__ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show, + array_size_store); static struct attribute *md_default_attrs[] = { &md_level.attr, @@ -3444,6 +3712,7 @@ static struct attribute *md_default_attrs[] = { &md_safe_delay.attr, &md_array_state.attr, &md_reshape_position.attr, + &md_array_size.attr, NULL, }; @@ -3602,10 +3871,12 @@ static int md_alloc(dev_t dev, char *name) mddev_put(mddev); return -ENOMEM; } + mddev->queue->queuedata = mddev; + /* Can be unlocked because the queue is new: no concurrency */ queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue); - blk_queue_make_request(mddev->queue, md_fail_request); + blk_queue_make_request(mddev->queue, md_make_request); disk = alloc_disk(1 << shift); if (!disk) { @@ -3731,13 +4002,13 @@ static int do_md_run(mddev_t * mddev) list_for_each_entry(rdev, &mddev->disks, same_set) { if (test_bit(Faulty, &rdev->flags)) continue; - if (rdev->size < chunk_size / 1024) { + if (rdev->sectors < chunk_size / 512) { printk(KERN_WARNING "md: Dev %s smaller than chunk_size:" - " %lluk < %dk\n", + " %llu < %d\n", bdevname(rdev->bdev,b), - (unsigned long long)rdev->size, - chunk_size / 1024); + (unsigned long long)rdev->sectors, + chunk_size / 512); return -EINVAL; } } @@ -3761,11 +4032,11 @@ static int do_md_run(mddev_t * mddev) /* perform some consistency tests on the device. * We don't want the data to overlap the metadata, - * Internal Bitmap issues has handled elsewhere. + * Internal Bitmap issues have been handled elsewhere. */ if (rdev->data_offset < rdev->sb_start) { - if (mddev->size && - rdev->data_offset + mddev->size*2 + if (mddev->dev_sectors && + rdev->data_offset + mddev->dev_sectors > rdev->sb_start) { printk("md: %s: data overlaps metadata\n", mdname(mddev)); @@ -3801,9 +4072,16 @@ static int do_md_run(mddev_t * mddev) } mddev->pers = pers; spin_unlock(&pers_lock); - mddev->level = pers->level; + if (mddev->level != pers->level) { + mddev->level = pers->level; + mddev->new_level = pers->level; + } strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); + if (pers->level >= 4 && pers->level <= 6) + /* Cannot support integrity (yet) */ + blk_integrity_unregister(mddev->gendisk); + if (mddev->reshape_position != MaxSector && pers->start_reshape == NULL) { /* This personality cannot handle reshaping... */ @@ -3843,7 +4121,9 @@ static int do_md_run(mddev_t * mddev) } mddev->recovery = 0; - mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ + /* may be over-ridden by personality */ + mddev->resync_max_sectors = mddev->dev_sectors; + mddev->barriers_work = 1; mddev->ok_start_degraded = start_dirty_degraded; @@ -3853,7 +4133,17 @@ static int do_md_run(mddev_t * mddev) err = mddev->pers->run(mddev); if (err) printk(KERN_ERR "md: pers->run() failed ...\n"); - else if (mddev->pers->sync_request) { + else if (mddev->pers->size(mddev, 0, 0) < mddev->array_sectors) { + WARN_ONCE(!mddev->external_size, "%s: default size too small," + " but 'external_size' not in effect?\n", __func__); + printk(KERN_ERR + "md: invalid array_size %llu > default size %llu\n", + (unsigned long long)mddev->array_sectors / 2, + (unsigned long long)mddev->pers->size(mddev, 0, 0) / 2); + err = -EINVAL; + mddev->pers->stop(mddev); + } + if (err == 0 && mddev->pers->sync_request) { err = bitmap_create(mddev); if (err) { printk(KERN_ERR "%s: failed to create bitmap (%d)\n", @@ -3899,16 +4189,6 @@ static int do_md_run(mddev_t * mddev) set_capacity(disk, mddev->array_sectors); - /* If we call blk_queue_make_request here, it will - * re-initialise max_sectors etc which may have been - * refined inside -> run. So just set the bits we need to set. - * Most initialisation happended when we called - * blk_queue_make_request(..., md_fail_request) - * earlier. - */ - mddev->queue->queuedata = mddev; - mddev->queue->make_request_fn = mddev->pers->make_request; - /* If there is a partially-recovered drive we need to * start recovery here. If we leave it to md_check_recovery, * it will remove the drives and not do the right thing @@ -4038,7 +4318,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) md_super_wait(mddev); if (mddev->ro) set_disk_ro(disk, 0); - blk_queue_make_request(mddev->queue, md_fail_request); + mddev->pers->stop(mddev); mddev->queue->merge_bvec_fn = NULL; mddev->queue->unplug_fn = NULL; @@ -4095,7 +4375,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) export_array(mddev); mddev->array_sectors = 0; - mddev->size = 0; + mddev->external_size = 0; + mddev->dev_sectors = 0; mddev->raid_disks = 0; mddev->recovery_cp = 0; mddev->resync_min = 0; @@ -4135,6 +4416,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) printk(KERN_INFO "md: %s switched to read-only mode.\n", mdname(mddev)); err = 0; + blk_integrity_unregister(disk); md_new_event(mddev); sysfs_notify_dirent(mddev->sysfs_state); out: @@ -4300,8 +4582,8 @@ static int get_array_info(mddev_t * mddev, void __user * arg) info.patch_version = MD_PATCHLEVEL_VERSION; info.ctime = mddev->ctime; info.level = mddev->level; - info.size = mddev->size; - if (info.size != mddev->size) /* overflow */ + info.size = mddev->dev_sectors / 2; + if (info.size != mddev->dev_sectors / 2) /* overflow */ info.size = -1; info.nr_disks = nr; info.raid_disks = mddev->raid_disks; @@ -4480,6 +4762,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) clear_bit(In_sync, &rdev->flags); /* just to be sure */ if (info->state & (1<flags); + else + clear_bit(WriteMostly, &rdev->flags); rdev->raid_disk = -1; err = bind_rdev_to_array(rdev, mddev); @@ -4543,7 +4827,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) rdev->sb_start = rdev->bdev->bd_inode->i_size / 512; } else rdev->sb_start = calc_dev_sboffset(rdev->bdev); - rdev->size = calc_num_sectors(rdev, mddev->chunk_size) / 2; + rdev->sectors = calc_num_sectors(rdev, mddev->chunk_size); err = bind_rdev_to_array(rdev, mddev); if (err) { @@ -4613,7 +4897,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) else rdev->sb_start = rdev->bdev->bd_inode->i_size / 512; - rdev->size = calc_num_sectors(rdev, mddev->chunk_size) / 2; + rdev->sectors = calc_num_sectors(rdev, mddev->chunk_size); if (test_bit(Faulty, &rdev->flags)) { printk(KERN_WARNING @@ -4749,7 +5033,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) mddev->level = info->level; mddev->clevel[0] = 0; - mddev->size = info->size; + mddev->dev_sectors = 2 * (sector_t)info->size; mddev->raid_disks = info->raid_disks; /* don't set md_minor, it is determined by which /dev/md* was * openned @@ -4788,6 +5072,17 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) return 0; } +void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors) +{ + WARN(!mddev_is_locked(mddev), "%s: unlocked mddev!\n", __func__); + + if (mddev->external_size) + return; + + mddev->array_sectors = array_sectors; +} +EXPORT_SYMBOL(md_set_array_sectors); + static int update_size(mddev_t *mddev, sector_t num_sectors) { mdk_rdev_t *rdev; @@ -4814,8 +5109,7 @@ static int update_size(mddev_t *mddev, sector_t num_sectors) */ return -EBUSY; list_for_each_entry(rdev, &mddev->disks, same_set) { - sector_t avail; - avail = rdev->size * 2; + sector_t avail = rdev->sectors; if (fit && (num_sectors == 0 || num_sectors > avail)) num_sectors = avail; @@ -4887,12 +5181,18 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) ) return -EINVAL; /* Check there is only one change */ - if (info->size >= 0 && mddev->size != info->size) cnt++; - if (mddev->raid_disks != info->raid_disks) cnt++; - if (mddev->layout != info->layout) cnt++; - if ((state ^ info->state) & (1< 1) return -EINVAL; + if (info->size >= 0 && mddev->dev_sectors / 2 != info->size) + cnt++; + if (mddev->raid_disks != info->raid_disks) + cnt++; + if (mddev->layout != info->layout) + cnt++; + if ((state ^ info->state) & (1< 1) + return -EINVAL; if (mddev->layout != info->layout) { /* Change layout @@ -4904,7 +5204,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info) else return mddev->pers->reconfig(mddev, info->layout, -1); } - if (info->size >= 0 && mddev->size != info->size) + if (info->size >= 0 && mddev->dev_sectors / 2 != info->size) rv = update_size(mddev, (sector_t)info->size * 2); if (mddev->raid_disks != info->raid_disks) @@ -5331,6 +5631,8 @@ mdk_thread_t *md_register_thread(void (*run) (mddev_t *), mddev_t *mddev, void md_unregister_thread(mdk_thread_t *thread) { + if (!thread) + return; dprintk("interrupting MD-thread pid %d\n", task_pid_nr(thread->tsk)); kthread_stop(thread->tsk); @@ -5404,7 +5706,7 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev) if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) max_blocks = mddev->resync_max_sectors >> 1; else - max_blocks = mddev->size; + max_blocks = mddev->dev_sectors / 2; /* * Should not happen. @@ -5537,7 +5839,7 @@ struct mdstat_info { static int md_seq_show(struct seq_file *seq, void *v) { mddev_t *mddev = v; - sector_t size; + sector_t sectors; mdk_rdev_t *rdev; struct mdstat_info *mi = seq->private; struct bitmap *bitmap; @@ -5573,7 +5875,7 @@ static int md_seq_show(struct seq_file *seq, void *v) seq_printf(seq, " %s", mddev->pers->name); } - size = 0; + sectors = 0; list_for_each_entry(rdev, &mddev->disks, same_set) { char b[BDEVNAME_SIZE]; seq_printf(seq, " %s[%d]", @@ -5585,7 +5887,7 @@ static int md_seq_show(struct seq_file *seq, void *v) continue; } else if (rdev->raid_disk < 0) seq_printf(seq, "(S)"); /* spare */ - size += rdev->size; + sectors += rdev->sectors; } if (!list_empty(&mddev->disks)) { @@ -5595,7 +5897,7 @@ static int md_seq_show(struct seq_file *seq, void *v) mddev->array_sectors / 2); else seq_printf(seq, "\n %llu blocks", - (unsigned long long)size); + (unsigned long long)sectors / 2); } if (mddev->persistent) { if (mddev->major_version != 0 || @@ -5722,19 +6024,19 @@ int unregister_md_personality(struct mdk_personality *p) return 0; } -static int is_mddev_idle(mddev_t *mddev) +static int is_mddev_idle(mddev_t *mddev, int init) { mdk_rdev_t * rdev; int idle; - long curr_events; + int curr_events; idle = 1; rcu_read_lock(); rdev_for_each_rcu(rdev, mddev) { struct gendisk *disk = rdev->bdev->bd_contains->bd_disk; - curr_events = part_stat_read(&disk->part0, sectors[0]) + - part_stat_read(&disk->part0, sectors[1]) - - atomic_read(&disk->sync_io); + curr_events = (int)part_stat_read(&disk->part0, sectors[0]) + + (int)part_stat_read(&disk->part0, sectors[1]) - + atomic_read(&disk->sync_io); /* sync IO will cause sync_io to increase before the disk_stats * as sync_io is counted when a request starts, and * disk_stats is counted when it completes. @@ -5757,7 +6059,7 @@ static int is_mddev_idle(mddev_t *mddev) * always make curr_events less than last_events. * */ - if (curr_events - rdev->last_events > 4096) { + if (init || curr_events - rdev->last_events > 64) { rdev->last_events = curr_events; idle = 0; } @@ -5980,10 +6282,10 @@ void md_do_sync(mddev_t *mddev) j = mddev->recovery_cp; } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) - max_sectors = mddev->size << 1; + max_sectors = mddev->dev_sectors; else { /* recovery follows the physical size of devices */ - max_sectors = mddev->size << 1; + max_sectors = mddev->dev_sectors; j = MaxSector; list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0 && @@ -6000,7 +6302,7 @@ void md_do_sync(mddev_t *mddev) "(but not more than %d KB/sec) for %s.\n", speed_max(mddev), desc); - is_mddev_idle(mddev); /* this also initializes IO event counters */ + is_mddev_idle(mddev, 1); /* this initializes IO event counters */ io_sectors = 0; for (m = 0; m < SYNC_MARKS; m++) { @@ -6040,6 +6342,18 @@ void md_do_sync(mddev_t *mddev) } if (kthread_should_stop()) goto interrupted; + + if (mddev->curr_resync > mddev->curr_resync_completed && + (mddev->curr_resync - mddev->curr_resync_completed) + > (max_sectors >> 4)) { + /* time to update curr_resync_completed */ + blk_unplug(mddev->queue); + wait_event(mddev->recovery_wait, + atomic_read(&mddev->recovery_active) == 0); + mddev->curr_resync_completed = + mddev->curr_resync; + set_bit(MD_CHANGE_CLEAN, &mddev->flags); + } sectors = mddev->pers->sync_request(mddev, j, &skipped, currspeed < speed_min(mddev)); if (sectors == 0) { @@ -6102,7 +6416,7 @@ void md_do_sync(mddev_t *mddev) if (currspeed > speed_min(mddev)) { if ((currspeed > speed_max(mddev)) || - !is_mddev_idle(mddev)) { + !is_mddev_idle(mddev, 0)) { msleep(500); goto repeat; } @@ -6173,6 +6487,8 @@ static int remove_and_add_spares(mddev_t *mddev) mdk_rdev_t *rdev; int spares = 0; + mddev->curr_resync_completed = 0; + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0 && !test_bit(Blocked, &rdev->flags) && @@ -6327,6 +6643,9 @@ void md_check_recovery(mddev_t *mddev) sysfs_notify(&mddev->kobj, NULL, "degraded"); } + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + mddev->pers->finish_reshape) + mddev->pers->finish_reshape(mddev); md_update_sb(mddev, 1); /* if array is no-longer degraded, then any saved_raid_disk @@ -6470,13 +6789,13 @@ static void md_geninit(void) static int __init md_init(void) { - if (register_blkdev(MAJOR_NR, "md")) + if (register_blkdev(MD_MAJOR, "md")) return -1; if ((mdp_major=register_blkdev(0, "mdp"))<=0) { - unregister_blkdev(MAJOR_NR, "md"); + unregister_blkdev(MD_MAJOR, "md"); return -1; } - blk_register_region(MKDEV(MAJOR_NR, 0), 1UL< 2drive raid5 + * ndrive raid5 -> degraded n+1drive raid6 with special layout + * If the takeover succeeds, a new 'private' structure is returned. + * This needs to be installed and then ->run used to activate the + * array. + */ + void *(*takeover) (mddev_t *mddev); }; @@ -400,3 +411,26 @@ static inline void safe_put_page(struct page *p) #endif /* CONFIG_BLOCK */ #endif + +extern int register_md_personality(struct mdk_personality *p); +extern int unregister_md_personality(struct mdk_personality *p); +extern mdk_thread_t * md_register_thread(void (*run) (mddev_t *mddev), + mddev_t *mddev, const char *name); +extern void md_unregister_thread(mdk_thread_t *thread); +extern void md_wakeup_thread(mdk_thread_t *thread); +extern void md_check_recovery(mddev_t *mddev); +extern void md_write_start(mddev_t *mddev, struct bio *bi); +extern void md_write_end(mddev_t *mddev); +extern void md_done_sync(mddev_t *mddev, int blocks, int ok); +extern void md_error(mddev_t *mddev, mdk_rdev_t *rdev); + +extern void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, + sector_t sector, int size, struct page *page); +extern void md_super_wait(mddev_t *mddev); +extern int sync_page_io(struct block_device *bdev, sector_t sector, int size, + struct page *page, int rw); +extern void md_do_sync(mddev_t *mddev); +extern void md_new_event(mddev_t *mddev); +extern int md_allow_write(mddev_t *mddev); +extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev); +extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); diff --git a/trunk/drivers/md/mktables.c b/trunk/drivers/md/mktables.c index b61d5767aae7..3b1500843bba 100644 --- a/trunk/drivers/md/mktables.c +++ b/trunk/drivers/md/mktables.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) uint8_t v; uint8_t exptbl[256], invtbl[256]; - printf("#include \"raid6.h\"\n"); + printf("#include \n"); /* Compute multiplication table */ printf("\nconst u8 __attribute__((aligned(256)))\n" @@ -76,6 +76,9 @@ int main(int argc, char *argv[]) printf("\t},\n"); } printf("};\n"); + printf("#ifdef __KERNEL__\n"); + printf("EXPORT_SYMBOL(raid6_gfmul);\n"); + printf("#endif\n"); /* Compute power-of-2 table (exponent) */ v = 1; @@ -92,6 +95,9 @@ int main(int argc, char *argv[]) } } printf("};\n"); + printf("#ifdef __KERNEL__\n"); + printf("EXPORT_SYMBOL(raid6_gfexp);\n"); + printf("#endif\n"); /* Compute inverse table x^-1 == x^254 */ printf("\nconst u8 __attribute__((aligned(256)))\n" @@ -104,6 +110,9 @@ int main(int argc, char *argv[]) } } printf("};\n"); + printf("#ifdef __KERNEL__\n"); + printf("EXPORT_SYMBOL(raid6_gfinv);\n"); + printf("#endif\n"); /* Compute inv(2^x + 1) (exponent-xor-inverse) table */ printf("\nconst u8 __attribute__((aligned(256)))\n" @@ -115,6 +124,9 @@ int main(int argc, char *argv[]) (j == 7) ? '\n' : ' '); } printf("};\n"); + printf("#ifdef __KERNEL__\n"); + printf("EXPORT_SYMBOL(raid6_gfexi);\n"); + printf("#endif\n"); return 0; } diff --git a/trunk/drivers/md/multipath.c b/trunk/drivers/md/multipath.c index f6d08f241671..41ced0cbe823 100644 --- a/trunk/drivers/md/multipath.c +++ b/trunk/drivers/md/multipath.c @@ -19,7 +19,11 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include +#include +#include +#include "md.h" +#include "multipath.h" #define MAX_WORK_PER_DISK 128 @@ -402,6 +406,14 @@ static void multipathd (mddev_t *mddev) spin_unlock_irqrestore(&conf->device_lock, flags); } +static sector_t multipath_size(mddev_t *mddev, sector_t sectors, int raid_disks) +{ + WARN_ONCE(sectors || raid_disks, + "%s does not support generic reshape\n", __func__); + + return mddev->dev_sectors; +} + static int multipath_run (mddev_t *mddev) { multipath_conf_t *conf; @@ -498,7 +510,7 @@ static int multipath_run (mddev_t *mddev) /* * Ok, everything is just fine now */ - mddev->array_sectors = mddev->size * 2; + md_set_array_sectors(mddev, multipath_size(mddev, 0, 0)); mddev->queue->unplug_fn = multipath_unplug; mddev->queue->backing_dev_info.congested_fn = multipath_congested; @@ -543,6 +555,7 @@ static struct mdk_personality multipath_personality = .error_handler = multipath_error, .hot_add_disk = multipath_add_disk, .hot_remove_disk= multipath_remove_disk, + .size = multipath_size, }; static int __init multipath_init (void) diff --git a/trunk/include/linux/raid/multipath.h b/trunk/drivers/md/multipath.h similarity index 96% rename from trunk/include/linux/raid/multipath.h rename to trunk/drivers/md/multipath.h index 6f53fc177a47..6fa70b400cda 100644 --- a/trunk/include/linux/raid/multipath.h +++ b/trunk/drivers/md/multipath.h @@ -1,8 +1,6 @@ #ifndef _MULTIPATH_H #define _MULTIPATH_H -#include - struct multipath_info { mdk_rdev_t *rdev; }; diff --git a/trunk/drivers/md/raid0.c b/trunk/drivers/md/raid0.c index c605ba805586..c08d7559be55 100644 --- a/trunk/drivers/md/raid0.c +++ b/trunk/drivers/md/raid0.c @@ -18,7 +18,10 @@ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include +#include +#include "md.h" +#include "raid0.h" static void raid0_unplug(struct request_queue *q) { @@ -73,16 +76,15 @@ static int create_strip_zones (mddev_t *mddev) list_for_each_entry(rdev2, &mddev->disks, same_set) { printk(KERN_INFO "raid0: comparing %s(%llu)", bdevname(rdev1->bdev,b), - (unsigned long long)rdev1->size); + (unsigned long long)rdev1->sectors); printk(KERN_INFO " with %s(%llu)\n", bdevname(rdev2->bdev,b), - (unsigned long long)rdev2->size); + (unsigned long long)rdev2->sectors); if (rdev2 == rdev1) { printk(KERN_INFO "raid0: END\n"); break; } - if (rdev2->size == rdev1->size) - { + if (rdev2->sectors == rdev1->sectors) { /* * Not unique, don't count it as a new * group @@ -145,7 +147,7 @@ static int create_strip_zones (mddev_t *mddev) mddev->queue->max_sectors > (PAGE_SIZE>>9)) blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9); - if (!smallest || (rdev1->size size)) + if (!smallest || (rdev1->sectors < smallest->sectors)) smallest = rdev1; cnt++; } @@ -155,10 +157,10 @@ static int create_strip_zones (mddev_t *mddev) goto abort; } zone->nb_dev = cnt; - zone->sectors = smallest->size * cnt * 2; + zone->sectors = smallest->sectors * cnt; zone->zone_start = 0; - current_start = smallest->size * 2; + current_start = smallest->sectors; curr_zone_start = zone->sectors; /* now do the other zones */ @@ -177,29 +179,29 @@ static int create_strip_zones (mddev_t *mddev) rdev = conf->strip_zone[0].dev[j]; printk(KERN_INFO "raid0: checking %s ...", bdevname(rdev->bdev, b)); - if (rdev->size > current_start / 2) { - printk(KERN_INFO " contained as device %d\n", - c); - zone->dev[c] = rdev; - c++; - if (!smallest || (rdev->size size)) { - smallest = rdev; - printk(KERN_INFO " (%llu) is smallest!.\n", - (unsigned long long)rdev->size); - } - } else + if (rdev->sectors <= current_start) { printk(KERN_INFO " nope.\n"); + continue; + } + printk(KERN_INFO " contained as device %d\n", c); + zone->dev[c] = rdev; + c++; + if (!smallest || rdev->sectors < smallest->sectors) { + smallest = rdev; + printk(KERN_INFO " (%llu) is smallest!.\n", + (unsigned long long)rdev->sectors); + } } zone->nb_dev = c; - zone->sectors = (smallest->size * 2 - current_start) * c; + zone->sectors = (smallest->sectors - current_start) * c; printk(KERN_INFO "raid0: zone->nb_dev: %d, sectors: %llu\n", zone->nb_dev, (unsigned long long)zone->sectors); zone->zone_start = curr_zone_start; curr_zone_start += zone->sectors; - current_start = smallest->size * 2; + current_start = smallest->sectors; printk(KERN_INFO "raid0: current zone start: %llu\n", (unsigned long long)current_start); } @@ -261,12 +263,25 @@ static int raid0_mergeable_bvec(struct request_queue *q, return max; } +static sector_t raid0_size(mddev_t *mddev, sector_t sectors, int raid_disks) +{ + sector_t array_sectors = 0; + mdk_rdev_t *rdev; + + WARN_ONCE(sectors || raid_disks, + "%s does not support generic reshape\n", __func__); + + list_for_each_entry(rdev, &mddev->disks, same_set) + array_sectors += rdev->sectors; + + return array_sectors; +} + static int raid0_run (mddev_t *mddev) { unsigned cur=0, i=0, nb_zone; s64 sectors; raid0_conf_t *conf; - mdk_rdev_t *rdev; if (mddev->chunk_size == 0) { printk(KERN_ERR "md/raid0: non-zero chunk size required.\n"); @@ -291,16 +306,14 @@ static int raid0_run (mddev_t *mddev) goto out_free_conf; /* calculate array device size */ - mddev->array_sectors = 0; - list_for_each_entry(rdev, &mddev->disks, same_set) - mddev->array_sectors += rdev->size * 2; + md_set_array_sectors(mddev, raid0_size(mddev, 0, 0)); printk(KERN_INFO "raid0 : md_size is %llu sectors.\n", (unsigned long long)mddev->array_sectors); printk(KERN_INFO "raid0 : conf->spacing is %llu sectors.\n", (unsigned long long)conf->spacing); { - sector_t s = mddev->array_sectors; + sector_t s = raid0_size(mddev, 0, 0); sector_t space = conf->spacing; int round; conf->sector_shift = 0; @@ -509,6 +522,7 @@ static struct mdk_personality raid0_personality= .run = raid0_run, .stop = raid0_stop, .status = raid0_status, + .size = raid0_size, }; static int __init raid0_init (void) diff --git a/trunk/include/linux/raid/raid0.h b/trunk/drivers/md/raid0.h similarity index 96% rename from trunk/include/linux/raid/raid0.h rename to trunk/drivers/md/raid0.h index fd42aa87c391..824b12eb1d4f 100644 --- a/trunk/include/linux/raid/raid0.h +++ b/trunk/drivers/md/raid0.h @@ -1,8 +1,6 @@ #ifndef _RAID0_H #define _RAID0_H -#include - struct strip_zone { sector_t zone_start; /* Zone offset in md_dev (in sectors) */ diff --git a/trunk/drivers/md/raid1.c b/trunk/drivers/md/raid1.c index e2466425d9ca..b4f4badc0068 100644 --- a/trunk/drivers/md/raid1.c +++ b/trunk/drivers/md/raid1.c @@ -31,10 +31,13 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "dm-bio-list.h" #include -#include -#include +#include +#include +#include "md.h" +#include "dm-bio-list.h" +#include "raid1.h" +#include "bitmap.h" #define DEBUG 0 #if DEBUG @@ -1723,7 +1726,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i return 0; } - max_sector = mddev->size << 1; + max_sector = mddev->dev_sectors; if (sector_nr >= max_sector) { /* If we aborted, we need to abort the * sync on the 'current' bitmap chunk (there will @@ -1919,6 +1922,14 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i return nr_sectors; } +static sector_t raid1_size(mddev_t *mddev, sector_t sectors, int raid_disks) +{ + if (sectors) + return sectors; + + return mddev->dev_sectors; +} + static int run(mddev_t *mddev) { conf_t *conf; @@ -2048,7 +2059,7 @@ static int run(mddev_t *mddev) /* * Ok, everything is just fine now */ - mddev->array_sectors = mddev->size * 2; + md_set_array_sectors(mddev, raid1_size(mddev, 0, 0)); mddev->queue->unplug_fn = raid1_unplug; mddev->queue->backing_dev_info.congested_fn = raid1_congested; @@ -2089,6 +2100,9 @@ static int stop(mddev_t *mddev) /* need to kick something here to make sure I/O goes? */ } + raise_barrier(conf); + lower_barrier(conf); + md_unregister_thread(mddev->thread); mddev->thread = NULL; blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ @@ -2110,15 +2124,17 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors) * any io in the removed space completes, but it hardly seems * worth it. */ - mddev->array_sectors = sectors; + md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0)); + if (mddev->array_sectors > raid1_size(mddev, sectors, 0)) + return -EINVAL; set_capacity(mddev->gendisk, mddev->array_sectors); mddev->changed = 1; - if (mddev->array_sectors / 2 > mddev->size && + if (sectors > mddev->dev_sectors && mddev->recovery_cp == MaxSector) { - mddev->recovery_cp = mddev->size << 1; + mddev->recovery_cp = mddev->dev_sectors; set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); } - mddev->size = mddev->array_sectors / 2; + mddev->dev_sectors = sectors; mddev->resync_max_sectors = sectors; return 0; } @@ -2264,6 +2280,7 @@ static struct mdk_personality raid1_personality = .spare_active = raid1_spare_active, .sync_request = sync_request, .resize = raid1_resize, + .size = raid1_size, .check_reshape = raid1_reshape, .quiesce = raid1_quiesce, }; diff --git a/trunk/include/linux/raid/raid1.h b/trunk/drivers/md/raid1.h similarity index 99% rename from trunk/include/linux/raid/raid1.h rename to trunk/drivers/md/raid1.h index 0a9ba7c3302e..1620eea3d57c 100644 --- a/trunk/include/linux/raid/raid1.h +++ b/trunk/drivers/md/raid1.h @@ -1,8 +1,6 @@ #ifndef _RAID1_H #define _RAID1_H -#include - typedef struct mirror_info mirror_info_t; struct mirror_info { diff --git a/trunk/drivers/md/raid10.c b/trunk/drivers/md/raid10.c index 7301631abe04..e293d92641ac 100644 --- a/trunk/drivers/md/raid10.c +++ b/trunk/drivers/md/raid10.c @@ -18,10 +18,13 @@ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "dm-bio-list.h" #include -#include -#include +#include +#include +#include "md.h" +#include "dm-bio-list.h" +#include "raid10.h" +#include "bitmap.h" /* * RAID10 provides a combination of RAID0 and RAID1 functionality. @@ -1695,7 +1698,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i return 0; skipped: - max_sector = mddev->size << 1; + max_sector = mddev->dev_sectors; if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) max_sector = mddev->resync_max_sectors; if (sector_nr >= max_sector) { @@ -2020,6 +2023,25 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i goto skipped; } +static sector_t +raid10_size(mddev_t *mddev, sector_t sectors, int raid_disks) +{ + sector_t size; + conf_t *conf = mddev_to_conf(mddev); + + if (!raid_disks) + raid_disks = mddev->raid_disks; + if (!sectors) + sectors = mddev->dev_sectors; + + size = sectors >> conf->chunk_shift; + sector_div(size, conf->far_copies); + size = size * raid_disks; + sector_div(size, conf->near_copies); + + return size << conf->chunk_shift; +} + static int run(mddev_t *mddev) { conf_t *conf; @@ -2076,7 +2098,7 @@ static int run(mddev_t *mddev) conf->far_offset = fo; conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; conf->chunk_shift = ffz(~mddev->chunk_size) - 9; - size = mddev->size >> (conf->chunk_shift-1); + size = mddev->dev_sectors >> conf->chunk_shift; sector_div(size, fc); size = size * conf->raid_disks; sector_div(size, nc); @@ -2089,7 +2111,7 @@ static int run(mddev_t *mddev) */ stride += conf->raid_disks - 1; sector_div(stride, conf->raid_disks); - mddev->size = stride << (conf->chunk_shift-1); + mddev->dev_sectors = stride << conf->chunk_shift; if (fo) stride = 1; @@ -2171,8 +2193,8 @@ static int run(mddev_t *mddev) /* * Ok, everything is just fine now */ - mddev->array_sectors = size << conf->chunk_shift; - mddev->resync_max_sectors = size << conf->chunk_shift; + md_set_array_sectors(mddev, raid10_size(mddev, 0, 0)); + mddev->resync_max_sectors = raid10_size(mddev, 0, 0); mddev->queue->unplug_fn = raid10_unplug; mddev->queue->backing_dev_info.congested_fn = raid10_congested; @@ -2208,6 +2230,9 @@ static int stop(mddev_t *mddev) { conf_t *conf = mddev_to_conf(mddev); + raise_barrier(conf, 0); + lower_barrier(conf); + md_unregister_thread(mddev->thread); mddev->thread = NULL; blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ @@ -2255,6 +2280,7 @@ static struct mdk_personality raid10_personality = .spare_active = raid10_spare_active, .sync_request = sync_request, .quiesce = raid10_quiesce, + .size = raid10_size, }; static int __init raid_init(void) diff --git a/trunk/include/linux/raid/raid10.h b/trunk/drivers/md/raid10.h similarity index 99% rename from trunk/include/linux/raid/raid10.h rename to trunk/drivers/md/raid10.h index e9091cfeb286..244dbe507a54 100644 --- a/trunk/include/linux/raid/raid10.h +++ b/trunk/drivers/md/raid10.h @@ -1,8 +1,6 @@ #ifndef _RAID10_H #define _RAID10_H -#include - typedef struct mirror_info mirror_info_t; struct mirror_info { diff --git a/trunk/drivers/md/raid5.c b/trunk/drivers/md/raid5.c index a5ba080d303b..3bbc6d647044 100644 --- a/trunk/drivers/md/raid5.c +++ b/trunk/drivers/md/raid5.c @@ -43,11 +43,14 @@ * miss any bits. */ +#include #include -#include "raid6.h" - -#include +#include #include +#include +#include "md.h" +#include "raid5.h" +#include "bitmap.h" /* * Stripe cache @@ -91,11 +94,6 @@ #define printk_rl(args...) ((void) (printk_ratelimit() && printk(args))) -#if !RAID6_USE_EMPTY_ZERO_PAGE -/* In .bss so it's zeroed */ -const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); -#endif - /* * We maintain a biased count of active stripes in the bottom 16 bits of * bi_phys_segments, and a count of processed stripes in the upper 16 bits @@ -130,12 +128,42 @@ static inline void raid5_set_bi_hw_segments(struct bio *bio, unsigned int cnt) bio->bi_phys_segments = raid5_bi_phys_segments(bio) || (cnt << 16); } +/* Find first data disk in a raid6 stripe */ +static inline int raid6_d0(struct stripe_head *sh) +{ + if (sh->ddf_layout) + /* ddf always start from first device */ + return 0; + /* md starts just after Q block */ + if (sh->qd_idx == sh->disks - 1) + return 0; + else + return sh->qd_idx + 1; +} static inline int raid6_next_disk(int disk, int raid_disks) { disk++; return (disk < raid_disks) ? disk : 0; } +/* When walking through the disks in a raid5, starting at raid6_d0, + * We need to map each disk to a 'slot', where the data disks are slot + * 0 .. raid_disks-3, the parity disk is raid_disks-2 and the Q disk + * is raid_disks-1. This help does that mapping. + */ +static int raid6_idx_to_slot(int idx, struct stripe_head *sh, + int *count, int syndrome_disks) +{ + int slot; + + if (idx == sh->pd_idx) + return syndrome_disks; + if (idx == sh->qd_idx) + return syndrome_disks + 1; + slot = (*count)++; + return slot; +} + static void return_io(struct bio *return_bi) { struct bio *bi = return_bi; @@ -193,6 +221,7 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) } } } + static void release_stripe(struct stripe_head *sh) { raid5_conf_t *conf = sh->raid_conf; @@ -270,9 +299,11 @@ static int grow_buffers(struct stripe_head *sh, int num) return 0; } -static void raid5_build_block(struct stripe_head *sh, int i); +static void raid5_build_block(struct stripe_head *sh, int i, int previous); +static void stripe_set_idx(sector_t stripe, raid5_conf_t *conf, int previous, + struct stripe_head *sh); -static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int disks) +static void init_stripe(struct stripe_head *sh, sector_t sector, int previous) { raid5_conf_t *conf = sh->raid_conf; int i; @@ -287,11 +318,12 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int remove_hash(sh); + sh->generation = conf->generation - previous; + sh->disks = previous ? conf->previous_raid_disks : conf->raid_disks; sh->sector = sector; - sh->pd_idx = pd_idx; + stripe_set_idx(sector, conf, previous, sh); sh->state = 0; - sh->disks = disks; for (i = sh->disks; i--; ) { struct r5dev *dev = &sh->dev[i]; @@ -305,12 +337,13 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int BUG(); } dev->flags = 0; - raid5_build_block(sh, i); + raid5_build_block(sh, i, previous); } insert_hash(conf, sh); } -static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, int disks) +static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, + short generation) { struct stripe_head *sh; struct hlist_node *hn; @@ -318,7 +351,7 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, in CHECK_DEVLOCK(); pr_debug("__find_stripe, sector %llu\n", (unsigned long long)sector); hlist_for_each_entry(sh, hn, stripe_hash(conf, sector), hash) - if (sh->sector == sector && sh->disks == disks) + if (sh->sector == sector && sh->generation == generation) return sh; pr_debug("__stripe %llu not in cache\n", (unsigned long long)sector); return NULL; @@ -327,8 +360,9 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, in static void unplug_slaves(mddev_t *mddev); static void raid5_unplug_device(struct request_queue *q); -static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int disks, - int pd_idx, int noblock) +static struct stripe_head * +get_active_stripe(raid5_conf_t *conf, sector_t sector, + int previous, int noblock) { struct stripe_head *sh; @@ -340,7 +374,7 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector wait_event_lock_irq(conf->wait_for_stripe, conf->quiesce == 0, conf->device_lock, /* nothing */); - sh = __find_stripe(conf, sector, disks); + sh = __find_stripe(conf, sector, conf->generation - previous); if (!sh) { if (!conf->inactive_blocked) sh = get_free_stripe(conf); @@ -358,10 +392,11 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector ); conf->inactive_blocked = 0; } else - init_stripe(sh, sector, pd_idx, disks); + init_stripe(sh, sector, previous); } else { if (atomic_read(&sh->count)) { - BUG_ON(!list_empty(&sh->lru)); + BUG_ON(!list_empty(&sh->lru) + && !test_bit(STRIPE_EXPANDING, &sh->state)); } else { if (!test_bit(STRIPE_HANDLE, &sh->state)) atomic_inc(&conf->active_stripes); @@ -895,8 +930,10 @@ static int grow_stripes(raid5_conf_t *conf, int num) struct kmem_cache *sc; int devs = conf->raid_disks; - sprintf(conf->cache_name[0], "raid5-%s", mdname(conf->mddev)); - sprintf(conf->cache_name[1], "raid5-%s-alt", mdname(conf->mddev)); + sprintf(conf->cache_name[0], + "raid%d-%s", conf->level, mdname(conf->mddev)); + sprintf(conf->cache_name[1], + "raid%d-%s-alt", conf->level, mdname(conf->mddev)); conf->active_name = 0; sc = kmem_cache_create(conf->cache_name[conf->active_name], sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev), @@ -911,7 +948,6 @@ static int grow_stripes(raid5_conf_t *conf, int num) return 0; } -#ifdef CONFIG_MD_RAID5_RESHAPE static int resize_stripes(raid5_conf_t *conf, int newsize) { /* Make all the stripes able to hold 'newsize' devices. @@ -1036,7 +1072,6 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) conf->pool_size = newsize; return err; } -#endif static int drop_one_stripe(raid5_conf_t *conf) { @@ -1066,7 +1101,7 @@ static void shrink_stripes(raid5_conf_t *conf) static void raid5_end_read_request(struct bio * bi, int error) { - struct stripe_head *sh = bi->bi_private; + struct stripe_head *sh = bi->bi_private; raid5_conf_t *conf = sh->raid_conf; int disks = sh->disks, i; int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); @@ -1148,7 +1183,7 @@ static void raid5_end_read_request(struct bio * bi, int error) static void raid5_end_write_request(struct bio *bi, int error) { - struct stripe_head *sh = bi->bi_private; + struct stripe_head *sh = bi->bi_private; raid5_conf_t *conf = sh->raid_conf; int disks = sh->disks, i; int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); @@ -1176,9 +1211,9 @@ static void raid5_end_write_request(struct bio *bi, int error) } -static sector_t compute_blocknr(struct stripe_head *sh, int i); +static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous); -static void raid5_build_block(struct stripe_head *sh, int i) +static void raid5_build_block(struct stripe_head *sh, int i, int previous) { struct r5dev *dev = &sh->dev[i]; @@ -1194,7 +1229,7 @@ static void raid5_build_block(struct stripe_head *sh, int i) dev->req.bi_private = sh; dev->flags = 0; - dev->sector = compute_blocknr(sh, i); + dev->sector = compute_blocknr(sh, i, previous); } static void error(mddev_t *mddev, mdk_rdev_t *rdev) @@ -1227,15 +1262,23 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) * Input: a 'big' sector number, * Output: index of the data and parity disk, and the sector # in them. */ -static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, - unsigned int data_disks, unsigned int * dd_idx, - unsigned int * pd_idx, raid5_conf_t *conf) +static sector_t raid5_compute_sector(raid5_conf_t *conf, sector_t r_sector, + int previous, int *dd_idx, + struct stripe_head *sh) { long stripe; unsigned long chunk_number; unsigned int chunk_offset; + int pd_idx, qd_idx; + int ddf_layout = 0; sector_t new_sector; - int sectors_per_chunk = conf->chunk_size >> 9; + int algorithm = previous ? conf->prev_algo + : conf->algorithm; + int sectors_per_chunk = previous ? (conf->prev_chunk >> 9) + : (conf->chunk_size >> 9); + int raid_disks = previous ? conf->previous_raid_disks + : conf->raid_disks; + int data_disks = raid_disks - conf->max_degraded; /* First compute the information on this sector */ @@ -1259,68 +1302,170 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, /* * Select the parity disk based on the user selected algorithm. */ + pd_idx = qd_idx = ~0; switch(conf->level) { case 4: - *pd_idx = data_disks; + pd_idx = data_disks; break; case 5: - switch (conf->algorithm) { + switch (algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: - *pd_idx = data_disks - stripe % raid_disks; - if (*dd_idx >= *pd_idx) + pd_idx = data_disks - stripe % raid_disks; + if (*dd_idx >= pd_idx) (*dd_idx)++; break; case ALGORITHM_RIGHT_ASYMMETRIC: - *pd_idx = stripe % raid_disks; - if (*dd_idx >= *pd_idx) + pd_idx = stripe % raid_disks; + if (*dd_idx >= pd_idx) (*dd_idx)++; break; case ALGORITHM_LEFT_SYMMETRIC: - *pd_idx = data_disks - stripe % raid_disks; - *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; + pd_idx = data_disks - stripe % raid_disks; + *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; break; case ALGORITHM_RIGHT_SYMMETRIC: - *pd_idx = stripe % raid_disks; - *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; + pd_idx = stripe % raid_disks; + *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; + break; + case ALGORITHM_PARITY_0: + pd_idx = 0; + (*dd_idx)++; + break; + case ALGORITHM_PARITY_N: + pd_idx = data_disks; break; default: printk(KERN_ERR "raid5: unsupported algorithm %d\n", - conf->algorithm); + algorithm); + BUG(); } break; case 6: - /**** FIX THIS ****/ - switch (conf->algorithm) { + switch (algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: - *pd_idx = raid_disks - 1 - (stripe % raid_disks); - if (*pd_idx == raid_disks-1) - (*dd_idx)++; /* Q D D D P */ - else if (*dd_idx >= *pd_idx) + pd_idx = raid_disks - 1 - (stripe % raid_disks); + qd_idx = pd_idx + 1; + if (pd_idx == raid_disks-1) { + (*dd_idx)++; /* Q D D D P */ + qd_idx = 0; + } else if (*dd_idx >= pd_idx) (*dd_idx) += 2; /* D D P Q D */ break; case ALGORITHM_RIGHT_ASYMMETRIC: - *pd_idx = stripe % raid_disks; - if (*pd_idx == raid_disks-1) - (*dd_idx)++; /* Q D D D P */ - else if (*dd_idx >= *pd_idx) + pd_idx = stripe % raid_disks; + qd_idx = pd_idx + 1; + if (pd_idx == raid_disks-1) { + (*dd_idx)++; /* Q D D D P */ + qd_idx = 0; + } else if (*dd_idx >= pd_idx) (*dd_idx) += 2; /* D D P Q D */ break; case ALGORITHM_LEFT_SYMMETRIC: - *pd_idx = raid_disks - 1 - (stripe % raid_disks); - *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; + pd_idx = raid_disks - 1 - (stripe % raid_disks); + qd_idx = (pd_idx + 1) % raid_disks; + *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks; break; case ALGORITHM_RIGHT_SYMMETRIC: - *pd_idx = stripe % raid_disks; - *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks; + pd_idx = stripe % raid_disks; + qd_idx = (pd_idx + 1) % raid_disks; + *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks; + break; + + case ALGORITHM_PARITY_0: + pd_idx = 0; + qd_idx = 1; + (*dd_idx) += 2; + break; + case ALGORITHM_PARITY_N: + pd_idx = data_disks; + qd_idx = data_disks + 1; break; + + case ALGORITHM_ROTATING_ZERO_RESTART: + /* Exactly the same as RIGHT_ASYMMETRIC, but or + * of blocks for computing Q is different. + */ + pd_idx = stripe % raid_disks; + qd_idx = pd_idx + 1; + if (pd_idx == raid_disks-1) { + (*dd_idx)++; /* Q D D D P */ + qd_idx = 0; + } else if (*dd_idx >= pd_idx) + (*dd_idx) += 2; /* D D P Q D */ + ddf_layout = 1; + break; + + case ALGORITHM_ROTATING_N_RESTART: + /* Same a left_asymmetric, by first stripe is + * D D D P Q rather than + * Q D D D P + */ + pd_idx = raid_disks - 1 - ((stripe + 1) % raid_disks); + qd_idx = pd_idx + 1; + if (pd_idx == raid_disks-1) { + (*dd_idx)++; /* Q D D D P */ + qd_idx = 0; + } else if (*dd_idx >= pd_idx) + (*dd_idx) += 2; /* D D P Q D */ + ddf_layout = 1; + break; + + case ALGORITHM_ROTATING_N_CONTINUE: + /* Same as left_symmetric but Q is before P */ + pd_idx = raid_disks - 1 - (stripe % raid_disks); + qd_idx = (pd_idx + raid_disks - 1) % raid_disks; + *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks; + ddf_layout = 1; + break; + + case ALGORITHM_LEFT_ASYMMETRIC_6: + /* RAID5 left_asymmetric, with Q on last device */ + pd_idx = data_disks - stripe % (raid_disks-1); + if (*dd_idx >= pd_idx) + (*dd_idx)++; + qd_idx = raid_disks - 1; + break; + + case ALGORITHM_RIGHT_ASYMMETRIC_6: + pd_idx = stripe % (raid_disks-1); + if (*dd_idx >= pd_idx) + (*dd_idx)++; + qd_idx = raid_disks - 1; + break; + + case ALGORITHM_LEFT_SYMMETRIC_6: + pd_idx = data_disks - stripe % (raid_disks-1); + *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1); + qd_idx = raid_disks - 1; + break; + + case ALGORITHM_RIGHT_SYMMETRIC_6: + pd_idx = stripe % (raid_disks-1); + *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1); + qd_idx = raid_disks - 1; + break; + + case ALGORITHM_PARITY_0_6: + pd_idx = 0; + (*dd_idx)++; + qd_idx = raid_disks - 1; + break; + + default: printk(KERN_CRIT "raid6: unsupported algorithm %d\n", - conf->algorithm); + algorithm); + BUG(); } break; } + if (sh) { + sh->pd_idx = pd_idx; + sh->qd_idx = qd_idx; + sh->ddf_layout = ddf_layout; + } /* * Finally, compute the new sector number */ @@ -1329,17 +1474,21 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks, } -static sector_t compute_blocknr(struct stripe_head *sh, int i) +static sector_t compute_blocknr(struct stripe_head *sh, int i, int previous) { raid5_conf_t *conf = sh->raid_conf; int raid_disks = sh->disks; int data_disks = raid_disks - conf->max_degraded; sector_t new_sector = sh->sector, check; - int sectors_per_chunk = conf->chunk_size >> 9; + int sectors_per_chunk = previous ? (conf->prev_chunk >> 9) + : (conf->chunk_size >> 9); + int algorithm = previous ? conf->prev_algo + : conf->algorithm; sector_t stripe; int chunk_offset; - int chunk_number, dummy1, dummy2, dd_idx = i; + int chunk_number, dummy1, dd_idx = i; sector_t r_sector; + struct stripe_head sh2; chunk_offset = sector_div(new_sector, sectors_per_chunk); @@ -1351,7 +1500,7 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) switch(conf->level) { case 4: break; case 5: - switch (conf->algorithm) { + switch (algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: case ALGORITHM_RIGHT_ASYMMETRIC: if (i > sh->pd_idx) @@ -1363,19 +1512,27 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) i += raid_disks; i -= (sh->pd_idx + 1); break; + case ALGORITHM_PARITY_0: + i -= 1; + break; + case ALGORITHM_PARITY_N: + break; default: printk(KERN_ERR "raid5: unsupported algorithm %d\n", - conf->algorithm); + algorithm); + BUG(); } break; case 6: - if (i == raid6_next_disk(sh->pd_idx, raid_disks)) + if (i == sh->qd_idx) return 0; /* It is the Q disk */ - switch (conf->algorithm) { + switch (algorithm) { case ALGORITHM_LEFT_ASYMMETRIC: case ALGORITHM_RIGHT_ASYMMETRIC: - if (sh->pd_idx == raid_disks-1) - i--; /* Q D D D P */ + case ALGORITHM_ROTATING_ZERO_RESTART: + case ALGORITHM_ROTATING_N_RESTART: + if (sh->pd_idx == raid_disks-1) + i--; /* Q D D D P */ else if (i > sh->pd_idx) i -= 2; /* D D P Q D */ break; @@ -1390,9 +1547,35 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) i -= (sh->pd_idx + 2); } break; + case ALGORITHM_PARITY_0: + i -= 2; + break; + case ALGORITHM_PARITY_N: + break; + case ALGORITHM_ROTATING_N_CONTINUE: + if (sh->pd_idx == 0) + i--; /* P D D D Q */ + else if (i > sh->pd_idx) + i -= 2; /* D D Q P D */ + break; + case ALGORITHM_LEFT_ASYMMETRIC_6: + case ALGORITHM_RIGHT_ASYMMETRIC_6: + if (i > sh->pd_idx) + i--; + break; + case ALGORITHM_LEFT_SYMMETRIC_6: + case ALGORITHM_RIGHT_SYMMETRIC_6: + if (i < sh->pd_idx) + i += data_disks + 1; + i -= (sh->pd_idx + 1); + break; + case ALGORITHM_PARITY_0_6: + i -= 1; + break; default: printk(KERN_CRIT "raid6: unsupported algorithm %d\n", - conf->algorithm); + algorithm); + BUG(); } break; } @@ -1400,8 +1583,10 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i) chunk_number = stripe * data_disks + i; r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset; - check = raid5_compute_sector(r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf); - if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { + check = raid5_compute_sector(conf, r_sector, + previous, &dummy1, &sh2); + if (check != sh->sector || dummy1 != dd_idx || sh2.pd_idx != sh->pd_idx + || sh2.qd_idx != sh->qd_idx) { printk(KERN_ERR "compute_blocknr: map not correct\n"); return 0; } @@ -1468,14 +1653,16 @@ static void copy_data(int frombio, struct bio *bio, static void compute_parity6(struct stripe_head *sh, int method) { - raid6_conf_t *conf = sh->raid_conf; - int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = sh->disks, count; + raid5_conf_t *conf = sh->raid_conf; + int i, pd_idx, qd_idx, d0_idx, disks = sh->disks, count; + int syndrome_disks = sh->ddf_layout ? disks : (disks - 2); struct bio *chosen; /**** FIX THIS: This could be very bad if disks is close to 256 ****/ - void *ptrs[disks]; + void *ptrs[syndrome_disks+2]; - qd_idx = raid6_next_disk(pd_idx, disks); - d0_idx = raid6_next_disk(qd_idx, disks); + pd_idx = sh->pd_idx; + qd_idx = sh->qd_idx; + d0_idx = raid6_d0(sh); pr_debug("compute_parity, stripe %llu, method %d\n", (unsigned long long)sh->sector, method); @@ -1513,24 +1700,29 @@ static void compute_parity6(struct stripe_head *sh, int method) set_bit(R5_UPTODATE, &sh->dev[i].flags); } -// switch(method) { -// case RECONSTRUCT_WRITE: -// case CHECK_PARITY: -// case UPDATE_PARITY: - /* Note that unlike RAID-5, the ordering of the disks matters greatly. */ - /* FIX: Is this ordering of drives even remotely optimal? */ - count = 0; - i = d0_idx; - do { - ptrs[count++] = page_address(sh->dev[i].page); - if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags)) - printk("block %d/%d not uptodate on parity calc\n", i,count); - i = raid6_next_disk(i, disks); - } while ( i != d0_idx ); -// break; -// } - - raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs); + /* Note that unlike RAID-5, the ordering of the disks matters greatly.*/ + + for (i = 0; i < disks; i++) + ptrs[i] = (void *)raid6_empty_zero_page; + + count = 0; + i = d0_idx; + do { + int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks); + + ptrs[slot] = page_address(sh->dev[i].page); + if (slot < syndrome_disks && + !test_bit(R5_UPTODATE, &sh->dev[i].flags)) { + printk(KERN_ERR "block %d/%d not uptodate " + "on parity calc\n", i, count); + BUG(); + } + + i = raid6_next_disk(i, disks); + } while (i != d0_idx); + BUG_ON(count != syndrome_disks); + + raid6_call.gen_syndrome(syndrome_disks+2, STRIPE_SIZE, ptrs); switch(method) { case RECONSTRUCT_WRITE: @@ -1552,8 +1744,7 @@ static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero) { int i, count, disks = sh->disks; void *ptr[MAX_XOR_BLOCKS], *dest, *p; - int pd_idx = sh->pd_idx; - int qd_idx = raid6_next_disk(pd_idx, disks); + int qd_idx = sh->qd_idx; pr_debug("compute_block_1, stripe %llu, idx %d\n", (unsigned long long)sh->sector, dd_idx); @@ -1589,63 +1780,65 @@ static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero) static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) { int i, count, disks = sh->disks; - int pd_idx = sh->pd_idx; - int qd_idx = raid6_next_disk(pd_idx, disks); - int d0_idx = raid6_next_disk(qd_idx, disks); - int faila, failb; + int syndrome_disks = sh->ddf_layout ? disks : disks-2; + int d0_idx = raid6_d0(sh); + int faila = -1, failb = -1; + /**** FIX THIS: This could be very bad if disks is close to 256 ****/ + void *ptrs[syndrome_disks+2]; - /* faila and failb are disk numbers relative to d0_idx */ - /* pd_idx become disks-2 and qd_idx become disks-1 */ - faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx; - failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx; + for (i = 0; i < disks ; i++) + ptrs[i] = (void *)raid6_empty_zero_page; + count = 0; + i = d0_idx; + do { + int slot = raid6_idx_to_slot(i, sh, &count, syndrome_disks); + + ptrs[slot] = page_address(sh->dev[i].page); + + if (i == dd_idx1) + faila = slot; + if (i == dd_idx2) + failb = slot; + i = raid6_next_disk(i, disks); + } while (i != d0_idx); + BUG_ON(count != syndrome_disks); BUG_ON(faila == failb); if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; } pr_debug("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n", - (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb); + (unsigned long long)sh->sector, dd_idx1, dd_idx2, + faila, failb); - if ( failb == disks-1 ) { + if (failb == syndrome_disks+1) { /* Q disk is one of the missing disks */ - if ( faila == disks-2 ) { + if (faila == syndrome_disks) { /* Missing P+Q, just recompute */ compute_parity6(sh, UPDATE_PARITY); return; } else { /* We're missing D+Q; recompute D from P */ - compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0); + compute_block_1(sh, ((dd_idx1 == sh->qd_idx) ? + dd_idx2 : dd_idx1), + 0); compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */ return; } } - /* We're missing D+P or D+D; build pointer table */ - { - /**** FIX THIS: This could be very bad if disks is close to 256 ****/ - void *ptrs[disks]; - - count = 0; - i = d0_idx; - do { - ptrs[count++] = page_address(sh->dev[i].page); - i = raid6_next_disk(i, disks); - if (i != dd_idx1 && i != dd_idx2 && - !test_bit(R5_UPTODATE, &sh->dev[i].flags)) - printk("compute_2 with missing block %d/%d\n", count, i); - } while ( i != d0_idx ); - - if ( failb == disks-2 ) { - /* We're missing D+P. */ - raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs); - } else { - /* We're missing D+D. */ - raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs); - } - - /* Both the above update both missing blocks */ - set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags); - set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags); + /* We're missing D+P or D+D; */ + if (failb == syndrome_disks) { + /* We're missing D+P. */ + raid6_datap_recov(syndrome_disks+2, STRIPE_SIZE, faila, ptrs); + } else { + /* We're missing D+D. */ + raid6_2data_recov(syndrome_disks+2, STRIPE_SIZE, faila, failb, + ptrs); } + + /* Both the above update both missing blocks */ + set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags); + set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags); } static void @@ -1800,17 +1993,21 @@ static int page_is_zero(struct page *p) memcmp(a, a+4, STRIPE_SIZE-4)==0); } -static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks) +static void stripe_set_idx(sector_t stripe, raid5_conf_t *conf, int previous, + struct stripe_head *sh) { - int sectors_per_chunk = conf->chunk_size >> 9; - int pd_idx, dd_idx; + int sectors_per_chunk = + previous ? (conf->prev_chunk >> 9) + : (conf->chunk_size >> 9); + int dd_idx; int chunk_offset = sector_div(stripe, sectors_per_chunk); + int disks = previous ? conf->previous_raid_disks : conf->raid_disks; - raid5_compute_sector(stripe * (disks - conf->max_degraded) + raid5_compute_sector(conf, + stripe * (disks - conf->max_degraded) *sectors_per_chunk + chunk_offset, - disks, disks - conf->max_degraded, - &dd_idx, &pd_idx, conf); - return pd_idx; + previous, + &dd_idx, sh); } static void @@ -2181,7 +2378,7 @@ static void handle_stripe_dirtying6(raid5_conf_t *conf, struct r6_state *r6s, int disks) { int rcw = 0, must_compute = 0, pd_idx = sh->pd_idx, i; - int qd_idx = r6s->qd_idx; + int qd_idx = sh->qd_idx; for (i = disks; i--; ) { struct r5dev *dev = &sh->dev[i]; /* Would I have to read this buffer for reconstruct_write */ @@ -2371,7 +2568,7 @@ static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh, int update_p = 0, update_q = 0; struct r5dev *dev; int pd_idx = sh->pd_idx; - int qd_idx = r6s->qd_idx; + int qd_idx = sh->qd_idx; set_bit(STRIPE_HANDLE, &sh->state); @@ -2467,17 +2664,14 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, struct dma_async_tx_descriptor *tx = NULL; clear_bit(STRIPE_EXPAND_SOURCE, &sh->state); for (i = 0; i < sh->disks; i++) - if (i != sh->pd_idx && (!r6s || i != r6s->qd_idx)) { - int dd_idx, pd_idx, j; + if (i != sh->pd_idx && i != sh->qd_idx) { + int dd_idx, j; struct stripe_head *sh2; - sector_t bn = compute_blocknr(sh, i); - sector_t s = raid5_compute_sector(bn, conf->raid_disks, - conf->raid_disks - - conf->max_degraded, &dd_idx, - &pd_idx, conf); - sh2 = get_active_stripe(conf, s, conf->raid_disks, - pd_idx, 1); + sector_t bn = compute_blocknr(sh, i, 1); + sector_t s = raid5_compute_sector(conf, bn, 0, + &dd_idx, NULL); + sh2 = get_active_stripe(conf, s, 0, 1); if (sh2 == NULL) /* so far only the early blocks of this stripe * have been requested. When later blocks @@ -2500,8 +2694,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags); for (j = 0; j < conf->raid_disks; j++) if (j != sh2->pd_idx && - (!r6s || j != raid6_next_disk(sh2->pd_idx, - sh2->disks)) && + (!r6s || j != sh2->qd_idx) && !test_bit(R5_Expanded, &sh2->dev[j].flags)) break; if (j == conf->raid_disks) { @@ -2750,6 +2943,23 @@ static bool handle_stripe5(struct stripe_head *sh) /* Finish reconstruct operations initiated by the expansion process */ if (sh->reconstruct_state == reconstruct_state_result) { + struct stripe_head *sh2 + = get_active_stripe(conf, sh->sector, 1, 1); + if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) { + /* sh cannot be written until sh2 has been read. + * so arrange for sh to be delayed a little + */ + set_bit(STRIPE_DELAYED, &sh->state); + set_bit(STRIPE_HANDLE, &sh->state); + if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, + &sh2->state)) + atomic_inc(&conf->preread_active_stripes); + release_stripe(sh2); + goto unlock; + } + if (sh2) + release_stripe(sh2); + sh->reconstruct_state = reconstruct_state_idle; clear_bit(STRIPE_EXPANDING, &sh->state); for (i = conf->raid_disks; i--; ) { @@ -2763,8 +2973,7 @@ static bool handle_stripe5(struct stripe_head *sh) !sh->reconstruct_state) { /* Need to write out all blocks after computing parity */ sh->disks = conf->raid_disks; - sh->pd_idx = stripe_to_pdidx(sh->sector, conf, - conf->raid_disks); + stripe_set_idx(sh->sector, conf, 0, sh); schedule_reconstruction5(sh, &s, 1, 1); } else if (s.expanded && !sh->reconstruct_state && s.locked == 0) { clear_bit(STRIPE_EXPAND_READY, &sh->state); @@ -2796,20 +3005,19 @@ static bool handle_stripe5(struct stripe_head *sh) static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page) { - raid6_conf_t *conf = sh->raid_conf; + raid5_conf_t *conf = sh->raid_conf; int disks = sh->disks; struct bio *return_bi = NULL; - int i, pd_idx = sh->pd_idx; + int i, pd_idx = sh->pd_idx, qd_idx = sh->qd_idx; struct stripe_head_state s; struct r6_state r6s; struct r5dev *dev, *pdev, *qdev; mdk_rdev_t *blocked_rdev = NULL; - r6s.qd_idx = raid6_next_disk(pd_idx, disks); pr_debug("handling stripe %llu, state=%#lx cnt=%d, " "pd_idx=%d, qd_idx=%d\n", (unsigned long long)sh->sector, sh->state, - atomic_read(&sh->count), pd_idx, r6s.qd_idx); + atomic_read(&sh->count), pd_idx, qd_idx); memset(&s, 0, sizeof(s)); spin_lock(&sh->lock); @@ -2920,9 +3128,9 @@ static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page) pdev = &sh->dev[pd_idx]; r6s.p_failed = (s.failed >= 1 && r6s.failed_num[0] == pd_idx) || (s.failed >= 2 && r6s.failed_num[1] == pd_idx); - qdev = &sh->dev[r6s.qd_idx]; - r6s.q_failed = (s.failed >= 1 && r6s.failed_num[0] == r6s.qd_idx) - || (s.failed >= 2 && r6s.failed_num[1] == r6s.qd_idx); + qdev = &sh->dev[qd_idx]; + r6s.q_failed = (s.failed >= 1 && r6s.failed_num[0] == qd_idx) + || (s.failed >= 2 && r6s.failed_num[1] == qd_idx); if ( s.written && ( r6s.p_failed || ((test_bit(R5_Insync, &pdev->flags) @@ -2980,10 +3188,26 @@ static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page) } if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state)) { + struct stripe_head *sh2 + = get_active_stripe(conf, sh->sector, 1, 1); + if (sh2 && test_bit(STRIPE_EXPAND_SOURCE, &sh2->state)) { + /* sh cannot be written until sh2 has been read. + * so arrange for sh to be delayed a little + */ + set_bit(STRIPE_DELAYED, &sh->state); + set_bit(STRIPE_HANDLE, &sh->state); + if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, + &sh2->state)) + atomic_inc(&conf->preread_active_stripes); + release_stripe(sh2); + goto unlock; + } + if (sh2) + release_stripe(sh2); + /* Need to write out all blocks after computing P&Q */ sh->disks = conf->raid_disks; - sh->pd_idx = stripe_to_pdidx(sh->sector, conf, - conf->raid_disks); + stripe_set_idx(sh->sector, conf, 0, sh); compute_parity6(sh, RECONSTRUCT_WRITE); for (i = conf->raid_disks ; i-- ; ) { set_bit(R5_LOCKED, &sh->dev[i].flags); @@ -3134,6 +3358,8 @@ static int raid5_mergeable_bvec(struct request_queue *q, if ((bvm->bi_rw & 1) == WRITE) return biovec->bv_len; /* always allow writes to be mergeable */ + if (mddev->new_chunk < mddev->chunk_size) + chunk_sectors = mddev->new_chunk >> 9; max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; if (max < 0) max = 0; if (max <= biovec->bv_len && bio_sectors == 0) @@ -3149,6 +3375,8 @@ static int in_chunk_boundary(mddev_t *mddev, struct bio *bio) unsigned int chunk_sectors = mddev->chunk_size >> 9; unsigned int bio_sectors = bio->bi_size >> 9; + if (mddev->new_chunk < mddev->chunk_size) + chunk_sectors = mddev->new_chunk >> 9; return chunk_sectors >= ((sector & (chunk_sectors - 1)) + bio_sectors); } @@ -3255,9 +3483,7 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio) { mddev_t *mddev = q->queuedata; raid5_conf_t *conf = mddev_to_conf(mddev); - const unsigned int raid_disks = conf->raid_disks; - const unsigned int data_disks = raid_disks - conf->max_degraded; - unsigned int dd_idx, pd_idx; + unsigned int dd_idx; struct bio* align_bi; mdk_rdev_t *rdev; @@ -3266,7 +3492,7 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio) return 0; } /* - * use bio_clone to make a copy of the bio + * use bio_clone to make a copy of the bio */ align_bi = bio_clone(raid_bio, GFP_NOIO); if (!align_bi) @@ -3280,12 +3506,9 @@ static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio) /* * compute position */ - align_bi->bi_sector = raid5_compute_sector(raid_bio->bi_sector, - raid_disks, - data_disks, - &dd_idx, - &pd_idx, - conf); + align_bi->bi_sector = raid5_compute_sector(conf, raid_bio->bi_sector, + 0, + &dd_idx, NULL); rcu_read_lock(); rdev = rcu_dereference(conf->disks[dd_idx].rdev); @@ -3377,7 +3600,7 @@ static int make_request(struct request_queue *q, struct bio * bi) { mddev_t *mddev = q->queuedata; raid5_conf_t *conf = mddev_to_conf(mddev); - unsigned int dd_idx, pd_idx; + int dd_idx; sector_t new_sector; sector_t logical_sector, last_sector; struct stripe_head *sh; @@ -3400,7 +3623,7 @@ static int make_request(struct request_queue *q, struct bio * bi) if (rw == READ && mddev->reshape_position == MaxSector && chunk_aligned_read(q,bi)) - return 0; + return 0; logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); last_sector = bi->bi_sector + (bi->bi_size>>9); @@ -3410,26 +3633,31 @@ static int make_request(struct request_queue *q, struct bio * bi) for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { DEFINE_WAIT(w); int disks, data_disks; + int previous; retry: + previous = 0; + disks = conf->raid_disks; prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE); - if (likely(conf->expand_progress == MaxSector)) - disks = conf->raid_disks; - else { - /* spinlock is needed as expand_progress may be + if (unlikely(conf->reshape_progress != MaxSector)) { + /* spinlock is needed as reshape_progress may be * 64bit on a 32bit platform, and so it might be * possible to see a half-updated value - * Ofcourse expand_progress could change after + * Ofcourse reshape_progress could change after * the lock is dropped, so once we get a reference * to the stripe that we think it is, we will have * to check again. */ spin_lock_irq(&conf->device_lock); - disks = conf->raid_disks; - if (logical_sector >= conf->expand_progress) + if (mddev->delta_disks < 0 + ? logical_sector < conf->reshape_progress + : logical_sector >= conf->reshape_progress) { disks = conf->previous_raid_disks; - else { - if (logical_sector >= conf->expand_lo) { + previous = 1; + } else { + if (mddev->delta_disks < 0 + ? logical_sector < conf->reshape_safe + : logical_sector >= conf->reshape_safe) { spin_unlock_irq(&conf->device_lock); schedule(); goto retry; @@ -3439,15 +3667,17 @@ static int make_request(struct request_queue *q, struct bio * bi) } data_disks = disks - conf->max_degraded; - new_sector = raid5_compute_sector(logical_sector, disks, data_disks, - &dd_idx, &pd_idx, conf); + new_sector = raid5_compute_sector(conf, logical_sector, + previous, + &dd_idx, NULL); pr_debug("raid5: make_request, sector %llu logical %llu\n", (unsigned long long)new_sector, (unsigned long long)logical_sector); - sh = get_active_stripe(conf, new_sector, disks, pd_idx, (bi->bi_rw&RWA_MASK)); + sh = get_active_stripe(conf, new_sector, previous, + (bi->bi_rw&RWA_MASK)); if (sh) { - if (unlikely(conf->expand_progress != MaxSector)) { + if (unlikely(previous)) { /* expansion might have moved on while waiting for a * stripe, so we must do the range check again. * Expansion could still move past after this @@ -3458,8 +3688,9 @@ static int make_request(struct request_queue *q, struct bio * bi) */ int must_retry = 0; spin_lock_irq(&conf->device_lock); - if (logical_sector < conf->expand_progress && - disks == conf->previous_raid_disks) + if (mddev->delta_disks < 0 + ? logical_sector >= conf->reshape_progress + : logical_sector < conf->reshape_progress) /* mismatch, need to try again */ must_retry = 1; spin_unlock_irq(&conf->device_lock); @@ -3514,6 +3745,8 @@ static int make_request(struct request_queue *q, struct bio * bi) return 0; } +static sector_t raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks); + static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped) { /* reshaping is quite different to recovery/resync so it is @@ -3527,61 +3760,118 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped */ raid5_conf_t *conf = (raid5_conf_t *) mddev->private; struct stripe_head *sh; - int pd_idx; sector_t first_sector, last_sector; int raid_disks = conf->previous_raid_disks; int data_disks = raid_disks - conf->max_degraded; int new_data_disks = conf->raid_disks - conf->max_degraded; int i; int dd_idx; - sector_t writepos, safepos, gap; - - if (sector_nr == 0 && - conf->expand_progress != 0) { - /* restarting in the middle, skip the initial sectors */ - sector_nr = conf->expand_progress; + sector_t writepos, readpos, safepos; + sector_t stripe_addr; + int reshape_sectors; + struct list_head stripes; + + if (sector_nr == 0) { + /* If restarting in the middle, skip the initial sectors */ + if (mddev->delta_disks < 0 && + conf->reshape_progress < raid5_size(mddev, 0, 0)) { + sector_nr = raid5_size(mddev, 0, 0) + - conf->reshape_progress; + } else if (mddev->delta_disks > 0 && + conf->reshape_progress > 0) + sector_nr = conf->reshape_progress; sector_div(sector_nr, new_data_disks); - *skipped = 1; - return sector_nr; + if (sector_nr) { + *skipped = 1; + return sector_nr; + } } + /* We need to process a full chunk at a time. + * If old and new chunk sizes differ, we need to process the + * largest of these + */ + if (mddev->new_chunk > mddev->chunk_size) + reshape_sectors = mddev->new_chunk / 512; + else + reshape_sectors = mddev->chunk_size / 512; + /* we update the metadata when there is more than 3Meg * in the block range (that is rather arbitrary, should * probably be time based) or when the data about to be * copied would over-write the source of the data at * the front of the range. - * i.e. one new_stripe forward from expand_progress new_maps - * to after where expand_lo old_maps to + * i.e. one new_stripe along from reshape_progress new_maps + * to after where reshape_safe old_maps to */ - writepos = conf->expand_progress + - conf->chunk_size/512*(new_data_disks); + writepos = conf->reshape_progress; sector_div(writepos, new_data_disks); - safepos = conf->expand_lo; + readpos = conf->reshape_progress; + sector_div(readpos, data_disks); + safepos = conf->reshape_safe; sector_div(safepos, data_disks); - gap = conf->expand_progress - conf->expand_lo; + if (mddev->delta_disks < 0) { + writepos -= reshape_sectors; + readpos += reshape_sectors; + safepos += reshape_sectors; + } else { + writepos += reshape_sectors; + readpos -= reshape_sectors; + safepos -= reshape_sectors; + } - if (writepos >= safepos || - gap > (new_data_disks)*3000*2 /*3Meg*/) { + /* 'writepos' is the most advanced device address we might write. + * 'readpos' is the least advanced device address we might read. + * 'safepos' is the least address recorded in the metadata as having + * been reshaped. + * If 'readpos' is behind 'writepos', then there is no way that we can + * ensure safety in the face of a crash - that must be done by userspace + * making a backup of the data. So in that case there is no particular + * rush to update metadata. + * Otherwise if 'safepos' is behind 'writepos', then we really need to + * update the metadata to advance 'safepos' to match 'readpos' so that + * we can be safe in the event of a crash. + * So we insist on updating metadata if safepos is behind writepos and + * readpos is beyond writepos. + * In any case, update the metadata every 10 seconds. + * Maybe that number should be configurable, but I'm not sure it is + * worth it.... maybe it could be a multiple of safemode_delay??? + */ + if ((mddev->delta_disks < 0 + ? (safepos > writepos && readpos < writepos) + : (safepos < writepos && readpos > writepos)) || + time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) { /* Cannot proceed until we've updated the superblock... */ wait_event(conf->wait_for_overlap, atomic_read(&conf->reshape_stripes)==0); - mddev->reshape_position = conf->expand_progress; + mddev->reshape_position = conf->reshape_progress; + conf->reshape_checkpoint = jiffies; set_bit(MD_CHANGE_DEVS, &mddev->flags); md_wakeup_thread(mddev->thread); wait_event(mddev->sb_wait, mddev->flags == 0 || kthread_should_stop()); spin_lock_irq(&conf->device_lock); - conf->expand_lo = mddev->reshape_position; + conf->reshape_safe = mddev->reshape_position; spin_unlock_irq(&conf->device_lock); wake_up(&conf->wait_for_overlap); } - for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) { + if (mddev->delta_disks < 0) { + BUG_ON(conf->reshape_progress == 0); + stripe_addr = writepos; + BUG_ON((mddev->dev_sectors & + ~((sector_t)reshape_sectors - 1)) + - reshape_sectors - stripe_addr + != sector_nr); + } else { + BUG_ON(writepos != sector_nr + reshape_sectors); + stripe_addr = sector_nr; + } + INIT_LIST_HEAD(&stripes); + for (i = 0; i < reshape_sectors; i += STRIPE_SECTORS) { int j; int skipped = 0; - pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks); - sh = get_active_stripe(conf, sector_nr+i, - conf->raid_disks, pd_idx, 0); + sh = get_active_stripe(conf, stripe_addr+i, 0, 0); set_bit(STRIPE_EXPANDING, &sh->state); atomic_inc(&conf->reshape_stripes); /* If any of this stripe is beyond the end of the old @@ -3592,10 +3882,10 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped if (j == sh->pd_idx) continue; if (conf->level == 6 && - j == raid6_next_disk(sh->pd_idx, sh->disks)) + j == sh->qd_idx) continue; - s = compute_blocknr(sh, j); - if (s < mddev->array_sectors) { + s = compute_blocknr(sh, j, 0); + if (s < raid5_size(mddev, 0, 0)) { skipped = 1; continue; } @@ -3607,10 +3897,13 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped set_bit(STRIPE_EXPAND_READY, &sh->state); set_bit(STRIPE_HANDLE, &sh->state); } - release_stripe(sh); + list_add(&sh->lru, &stripes); } spin_lock_irq(&conf->device_lock); - conf->expand_progress = (sector_nr + i) * new_data_disks; + if (mddev->delta_disks < 0) + conf->reshape_progress -= reshape_sectors * new_data_disks; + else + conf->reshape_progress += reshape_sectors * new_data_disks; spin_unlock_irq(&conf->device_lock); /* Ok, those stripe are ready. We can start scheduling * reads on the source stripes. @@ -3618,46 +3911,50 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped * block on the destination stripes. */ first_sector = - raid5_compute_sector(sector_nr*(new_data_disks), - raid_disks, data_disks, - &dd_idx, &pd_idx, conf); + raid5_compute_sector(conf, stripe_addr*(new_data_disks), + 1, &dd_idx, NULL); last_sector = - raid5_compute_sector((sector_nr+conf->chunk_size/512) - *(new_data_disks) -1, - raid_disks, data_disks, - &dd_idx, &pd_idx, conf); - if (last_sector >= (mddev->size<<1)) - last_sector = (mddev->size<<1)-1; + raid5_compute_sector(conf, ((stripe_addr+conf->chunk_size/512) + *(new_data_disks) - 1), + 1, &dd_idx, NULL); + if (last_sector >= mddev->dev_sectors) + last_sector = mddev->dev_sectors - 1; while (first_sector <= last_sector) { - pd_idx = stripe_to_pdidx(first_sector, conf, - conf->previous_raid_disks); - sh = get_active_stripe(conf, first_sector, - conf->previous_raid_disks, pd_idx, 0); + sh = get_active_stripe(conf, first_sector, 1, 0); set_bit(STRIPE_EXPAND_SOURCE, &sh->state); set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); first_sector += STRIPE_SECTORS; } + /* Now that the sources are clearly marked, we can release + * the destination stripes + */ + while (!list_empty(&stripes)) { + sh = list_entry(stripes.next, struct stripe_head, lru); + list_del_init(&sh->lru); + release_stripe(sh); + } /* If this takes us to the resync_max point where we have to pause, * then we need to write out the superblock. */ - sector_nr += conf->chunk_size>>9; + sector_nr += reshape_sectors; if (sector_nr >= mddev->resync_max) { /* Cannot proceed until we've updated the superblock... */ wait_event(conf->wait_for_overlap, atomic_read(&conf->reshape_stripes) == 0); - mddev->reshape_position = conf->expand_progress; + mddev->reshape_position = conf->reshape_progress; + conf->reshape_checkpoint = jiffies; set_bit(MD_CHANGE_DEVS, &mddev->flags); md_wakeup_thread(mddev->thread); wait_event(mddev->sb_wait, !test_bit(MD_CHANGE_DEVS, &mddev->flags) || kthread_should_stop()); spin_lock_irq(&conf->device_lock); - conf->expand_lo = mddev->reshape_position; + conf->reshape_safe = mddev->reshape_position; spin_unlock_irq(&conf->device_lock); wake_up(&conf->wait_for_overlap); } - return conf->chunk_size>>9; + return reshape_sectors; } /* FIXME go_faster isn't used */ @@ -3665,9 +3962,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski { raid5_conf_t *conf = (raid5_conf_t *) mddev->private; struct stripe_head *sh; - int pd_idx; - int raid_disks = conf->raid_disks; - sector_t max_sector = mddev->size << 1; + sector_t max_sector = mddev->dev_sectors; int sync_blocks; int still_degraded = 0; int i; @@ -3675,6 +3970,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski if (sector_nr >= max_sector) { /* just being told to finish up .. nothing much to do */ unplug_slaves(mddev); + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { end_reshape(conf); return 0; @@ -3705,7 +4001,7 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski */ if (mddev->degraded >= conf->max_degraded && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { - sector_t rv = (mddev->size << 1) - sector_nr; + sector_t rv = mddev->dev_sectors - sector_nr; *skipped = 1; return rv; } @@ -3721,10 +4017,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski bitmap_cond_end_sync(mddev->bitmap, sector_nr); - pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks); - sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1); + sh = get_active_stripe(conf, sector_nr, 0, 1); if (sh == NULL) { - sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0); + sh = get_active_stripe(conf, sector_nr, 0, 0); /* make sure we don't swamp the stripe cache if someone else * is trying to get access */ @@ -3766,19 +4061,15 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio) * it will be only one 'dd_idx' and only need one call to raid5_compute_sector. */ struct stripe_head *sh; - int dd_idx, pd_idx; + int dd_idx; sector_t sector, logical_sector, last_sector; int scnt = 0; int remaining; int handled = 0; logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); - sector = raid5_compute_sector( logical_sector, - conf->raid_disks, - conf->raid_disks - conf->max_degraded, - &dd_idx, - &pd_idx, - conf); + sector = raid5_compute_sector(conf, logical_sector, + 0, &dd_idx, NULL); last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9); for (; logical_sector < last_sector; @@ -3790,7 +4081,7 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio) /* already done this stripe */ continue; - sh = get_active_stripe(conf, sector, conf->raid_disks, pd_idx, 1); + sh = get_active_stripe(conf, sector, 0, 1); if (!sh) { /* failed to get a stripe - must wait */ @@ -3992,89 +4283,69 @@ static struct attribute_group raid5_attrs_group = { .attrs = raid5_attrs, }; -static int run(mddev_t *mddev) +static sector_t +raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + + if (!sectors) + sectors = mddev->dev_sectors; + if (!raid_disks) { + /* size is defined by the smallest of previous and new size */ + if (conf->raid_disks < conf->previous_raid_disks) + raid_disks = conf->raid_disks; + else + raid_disks = conf->previous_raid_disks; + } + + sectors &= ~((sector_t)mddev->chunk_size/512 - 1); + sectors &= ~((sector_t)mddev->new_chunk/512 - 1); + return sectors * (raid_disks - conf->max_degraded); +} + +static raid5_conf_t *setup_conf(mddev_t *mddev) { raid5_conf_t *conf; int raid_disk, memory; mdk_rdev_t *rdev; struct disk_info *disk; - int working_disks = 0; - if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) { + if (mddev->new_level != 5 + && mddev->new_level != 4 + && mddev->new_level != 6) { printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n", - mdname(mddev), mddev->level); - return -EIO; + mdname(mddev), mddev->new_level); + return ERR_PTR(-EIO); } - - if (mddev->chunk_size < PAGE_SIZE) { - printk(KERN_ERR "md/raid5: chunk_size must be at least " - "PAGE_SIZE but %d < %ld\n", - mddev->chunk_size, PAGE_SIZE); - return -EINVAL; + if ((mddev->new_level == 5 + && !algorithm_valid_raid5(mddev->new_layout)) || + (mddev->new_level == 6 + && !algorithm_valid_raid6(mddev->new_layout))) { + printk(KERN_ERR "raid5: %s: layout %d not supported\n", + mdname(mddev), mddev->new_layout); + return ERR_PTR(-EIO); } - - if (mddev->reshape_position != MaxSector) { - /* Check that we can continue the reshape. - * Currently only disks can change, it must - * increase, and we must be past the point where - * a stripe over-writes itself - */ - sector_t here_new, here_old; - int old_disks; - int max_degraded = (mddev->level == 5 ? 1 : 2); - - if (mddev->new_level != mddev->level || - mddev->new_layout != mddev->layout || - mddev->new_chunk != mddev->chunk_size) { - printk(KERN_ERR "raid5: %s: unsupported reshape " - "required - aborting.\n", - mdname(mddev)); - return -EINVAL; - } - if (mddev->delta_disks <= 0) { - printk(KERN_ERR "raid5: %s: unsupported reshape " - "(reduce disks) required - aborting.\n", - mdname(mddev)); - return -EINVAL; - } - old_disks = mddev->raid_disks - mddev->delta_disks; - /* reshape_position must be on a new-stripe boundary, and one - * further up in new geometry must map after here in old - * geometry. - */ - here_new = mddev->reshape_position; - if (sector_div(here_new, (mddev->chunk_size>>9)* - (mddev->raid_disks - max_degraded))) { - printk(KERN_ERR "raid5: reshape_position not " - "on a stripe boundary\n"); - return -EINVAL; - } - /* here_new is the stripe we will write to */ - here_old = mddev->reshape_position; - sector_div(here_old, (mddev->chunk_size>>9)* - (old_disks-max_degraded)); - /* here_old is the first stripe that we might need to read - * from */ - if (here_new >= here_old) { - /* Reading from the same stripe as writing to - bad */ - printk(KERN_ERR "raid5: reshape_position too early for " - "auto-recovery - aborting.\n"); - return -EINVAL; - } - printk(KERN_INFO "raid5: reshape will continue\n"); - /* OK, we should be able to continue; */ + if (mddev->new_level == 6 && mddev->raid_disks < 4) { + printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n", + mdname(mddev), mddev->raid_disks); + return ERR_PTR(-EINVAL); } + if (!mddev->new_chunk || mddev->new_chunk % PAGE_SIZE) { + printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", + mddev->new_chunk, mdname(mddev)); + return ERR_PTR(-EINVAL); + } - mddev->private = kzalloc(sizeof (raid5_conf_t), GFP_KERNEL); - if ((conf = mddev->private) == NULL) + conf = kzalloc(sizeof(raid5_conf_t), GFP_KERNEL); + if (conf == NULL) goto abort; - if (mddev->reshape_position == MaxSector) { - conf->previous_raid_disks = conf->raid_disks = mddev->raid_disks; - } else { - conf->raid_disks = mddev->raid_disks; + + conf->raid_disks = mddev->raid_disks; + if (mddev->reshape_position == MaxSector) + conf->previous_raid_disks = mddev->raid_disks; + else conf->previous_raid_disks = mddev->raid_disks - mddev->delta_disks; - } conf->disks = kzalloc(conf->raid_disks * sizeof(struct disk_info), GFP_KERNEL); @@ -4086,13 +4357,12 @@ static int run(mddev_t *mddev) if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) goto abort; - if (mddev->level == 6) { + if (mddev->new_level == 6) { conf->spare_page = alloc_page(GFP_KERNEL); if (!conf->spare_page) goto abort; } spin_lock_init(&conf->device_lock); - mddev->queue->queue_lock = &conf->device_lock; init_waitqueue_head(&conf->wait_for_stripe); init_waitqueue_head(&conf->wait_for_overlap); INIT_LIST_HEAD(&conf->handle_list); @@ -4121,47 +4391,134 @@ static int run(mddev_t *mddev) printk(KERN_INFO "raid5: device %s operational as raid" " disk %d\n", bdevname(rdev->bdev,b), raid_disk); - working_disks++; } else /* Cannot rely on bitmap to complete recovery */ conf->fullsync = 1; } - /* - * 0 for a fully functional array, 1 or 2 for a degraded array. - */ - mddev->degraded = conf->raid_disks - working_disks; - conf->mddev = mddev; - conf->chunk_size = mddev->chunk_size; - conf->level = mddev->level; + conf->chunk_size = mddev->new_chunk; + conf->level = mddev->new_level; if (conf->level == 6) conf->max_degraded = 2; else conf->max_degraded = 1; - conf->algorithm = mddev->layout; + conf->algorithm = mddev->new_layout; conf->max_nr_stripes = NR_STRIPES; - conf->expand_progress = mddev->reshape_position; - - /* device size must be a multiple of chunk size */ - mddev->size &= ~(mddev->chunk_size/1024 -1); - mddev->resync_max_sectors = mddev->size << 1; + conf->reshape_progress = mddev->reshape_position; + if (conf->reshape_progress != MaxSector) { + conf->prev_chunk = mddev->chunk_size; + conf->prev_algo = mddev->layout; + } - if (conf->level == 6 && conf->raid_disks < 4) { - printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n", - mdname(mddev), conf->raid_disks); + memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + + conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024; + if (grow_stripes(conf, conf->max_nr_stripes)) { + printk(KERN_ERR + "raid5: couldn't allocate %dkB for buffers\n", memory); goto abort; - } - if (!conf->chunk_size || conf->chunk_size % 4) { - printk(KERN_ERR "raid5: invalid chunk size %d for %s\n", - conf->chunk_size, mdname(mddev)); + } else + printk(KERN_INFO "raid5: allocated %dkB for %s\n", + memory, mdname(mddev)); + + conf->thread = md_register_thread(raid5d, mddev, "%s_raid5"); + if (!conf->thread) { + printk(KERN_ERR + "raid5: couldn't allocate thread for %s\n", + mdname(mddev)); goto abort; } - if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { - printk(KERN_ERR - "raid5: unsupported parity algorithm %d for %s\n", - conf->algorithm, mdname(mddev)); - goto abort; + + return conf; + + abort: + if (conf) { + shrink_stripes(conf); + safe_put_page(conf->spare_page); + kfree(conf->disks); + kfree(conf->stripe_hashtbl); + kfree(conf); + return ERR_PTR(-EIO); + } else + return ERR_PTR(-ENOMEM); +} + +static int run(mddev_t *mddev) +{ + raid5_conf_t *conf; + int working_disks = 0; + mdk_rdev_t *rdev; + + if (mddev->reshape_position != MaxSector) { + /* Check that we can continue the reshape. + * Currently only disks can change, it must + * increase, and we must be past the point where + * a stripe over-writes itself + */ + sector_t here_new, here_old; + int old_disks; + int max_degraded = (mddev->level == 6 ? 2 : 1); + + if (mddev->new_level != mddev->level) { + printk(KERN_ERR "raid5: %s: unsupported reshape " + "required - aborting.\n", + mdname(mddev)); + return -EINVAL; + } + old_disks = mddev->raid_disks - mddev->delta_disks; + /* reshape_position must be on a new-stripe boundary, and one + * further up in new geometry must map after here in old + * geometry. + */ + here_new = mddev->reshape_position; + if (sector_div(here_new, (mddev->new_chunk>>9)* + (mddev->raid_disks - max_degraded))) { + printk(KERN_ERR "raid5: reshape_position not " + "on a stripe boundary\n"); + return -EINVAL; + } + /* here_new is the stripe we will write to */ + here_old = mddev->reshape_position; + sector_div(here_old, (mddev->chunk_size>>9)* + (old_disks-max_degraded)); + /* here_old is the first stripe that we might need to read + * from */ + if (here_new >= here_old) { + /* Reading from the same stripe as writing to - bad */ + printk(KERN_ERR "raid5: reshape_position too early for " + "auto-recovery - aborting.\n"); + return -EINVAL; + } + printk(KERN_INFO "raid5: reshape will continue\n"); + /* OK, we should be able to continue; */ + } else { + BUG_ON(mddev->level != mddev->new_level); + BUG_ON(mddev->layout != mddev->new_layout); + BUG_ON(mddev->chunk_size != mddev->new_chunk); + BUG_ON(mddev->delta_disks != 0); } + + if (mddev->private == NULL) + conf = setup_conf(mddev); + else + conf = mddev->private; + + if (IS_ERR(conf)) + return PTR_ERR(conf); + + mddev->thread = conf->thread; + conf->thread = NULL; + mddev->private = conf; + + /* + * 0 for a fully functional array, 1 or 2 for a degraded array. + */ + list_for_each_entry(rdev, &mddev->disks, same_set) + if (rdev->raid_disk >= 0 && + test_bit(In_sync, &rdev->flags)) + working_disks++; + + mddev->degraded = conf->raid_disks - working_disks; + if (mddev->degraded > conf->max_degraded) { printk(KERN_ERR "raid5: not enough operational devices for %s" " (%d/%d failed)\n", @@ -4169,6 +4526,10 @@ static int run(mddev_t *mddev) goto abort; } + /* device size must be a multiple of chunk size */ + mddev->dev_sectors &= ~(mddev->chunk_size / 512 - 1); + mddev->resync_max_sectors = mddev->dev_sectors; + if (mddev->degraded > 0 && mddev->recovery_cp != MaxSector) { if (mddev->ok_start_degraded) @@ -4184,43 +4545,22 @@ static int run(mddev_t *mddev) } } - { - mddev->thread = md_register_thread(raid5d, mddev, "%s_raid5"); - if (!mddev->thread) { - printk(KERN_ERR - "raid5: couldn't allocate thread for %s\n", - mdname(mddev)); - goto abort; - } - } - memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + - conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024; - if (grow_stripes(conf, conf->max_nr_stripes)) { - printk(KERN_ERR - "raid5: couldn't allocate %dkB for buffers\n", memory); - shrink_stripes(conf); - md_unregister_thread(mddev->thread); - goto abort; - } else - printk(KERN_INFO "raid5: allocated %dkB for %s\n", - memory, mdname(mddev)); - if (mddev->degraded == 0) printk("raid5: raid level %d set %s active with %d out of %d" - " devices, algorithm %d\n", conf->level, mdname(mddev), - mddev->raid_disks-mddev->degraded, mddev->raid_disks, - conf->algorithm); + " devices, algorithm %d\n", conf->level, mdname(mddev), + mddev->raid_disks-mddev->degraded, mddev->raid_disks, + mddev->new_layout); else printk(KERN_ALERT "raid5: raid level %d set %s active with %d" " out of %d devices, algorithm %d\n", conf->level, mdname(mddev), mddev->raid_disks - mddev->degraded, - mddev->raid_disks, conf->algorithm); + mddev->raid_disks, mddev->new_layout); print_raid5_conf(conf); - if (conf->expand_progress != MaxSector) { + if (conf->reshape_progress != MaxSector) { printk("...ok start reshape thread\n"); - conf->expand_lo = conf->expand_progress; + conf->reshape_safe = conf->reshape_progress; atomic_set(&conf->reshape_stripes, 0); clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); @@ -4247,18 +4587,22 @@ static int run(mddev_t *mddev) "raid5: failed to create sysfs attributes for %s\n", mdname(mddev)); + mddev->queue->queue_lock = &conf->device_lock; + mddev->queue->unplug_fn = raid5_unplug_device; mddev->queue->backing_dev_info.congested_data = mddev; mddev->queue->backing_dev_info.congested_fn = raid5_congested; - mddev->array_sectors = 2 * mddev->size * (conf->previous_raid_disks - - conf->max_degraded); + md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec); return 0; abort: + md_unregister_thread(mddev->thread); + mddev->thread = NULL; if (conf) { + shrink_stripes(conf); print_raid5_conf(conf); safe_put_page(conf->spare_page); kfree(conf->disks); @@ -4396,6 +4740,10 @@ static int raid5_remove_disk(mddev_t *mddev, int number) print_raid5_conf(conf); rdev = p->rdev; if (rdev) { + if (number >= conf->raid_disks && + conf->reshape_progress == MaxSector) + clear_bit(In_sync, &rdev->flags); + if (test_bit(In_sync, &rdev->flags) || atomic_read(&rdev->nr_pending)) { err = -EBUSY; @@ -4405,7 +4753,8 @@ static int raid5_remove_disk(mddev_t *mddev, int number) * isn't possible. */ if (!test_bit(Faulty, &rdev->flags) && - mddev->degraded <= conf->max_degraded) { + mddev->degraded <= conf->max_degraded && + number < conf->raid_disks) { err = -EBUSY; goto abort; } @@ -4472,36 +4821,48 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) * any io in the removed space completes, but it hardly seems * worth it. */ - raid5_conf_t *conf = mddev_to_conf(mddev); - sectors &= ~((sector_t)mddev->chunk_size/512 - 1); - mddev->array_sectors = sectors * (mddev->raid_disks - - conf->max_degraded); + md_set_array_sectors(mddev, raid5_size(mddev, sectors, + mddev->raid_disks)); + if (mddev->array_sectors > + raid5_size(mddev, sectors, mddev->raid_disks)) + return -EINVAL; set_capacity(mddev->gendisk, mddev->array_sectors); mddev->changed = 1; - if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) { - mddev->recovery_cp = mddev->size << 1; + if (sectors > mddev->dev_sectors && mddev->recovery_cp == MaxSector) { + mddev->recovery_cp = mddev->dev_sectors; set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); } - mddev->size = sectors /2; + mddev->dev_sectors = sectors; mddev->resync_max_sectors = sectors; return 0; } -#ifdef CONFIG_MD_RAID5_RESHAPE static int raid5_check_reshape(mddev_t *mddev) { raid5_conf_t *conf = mddev_to_conf(mddev); - int err; - if (mddev->delta_disks < 0 || - mddev->new_level != mddev->level) - return -EINVAL; /* Cannot shrink array or change level yet */ - if (mddev->delta_disks == 0) - return 0; /* nothing to do */ + if (mddev->delta_disks == 0 && + mddev->new_layout == mddev->layout && + mddev->new_chunk == mddev->chunk_size) + return -EINVAL; /* nothing to do */ if (mddev->bitmap) /* Cannot grow a bitmap yet */ return -EBUSY; + if (mddev->degraded > conf->max_degraded) + return -EINVAL; + if (mddev->delta_disks < 0) { + /* We might be able to shrink, but the devices must + * be made bigger first. + * For raid6, 4 is the minimum size. + * Otherwise 2 is the minimum + */ + int min = 2; + if (mddev->level == 6) + min = 4; + if (mddev->raid_disks + mddev->delta_disks < min) + return -EINVAL; + } /* Can only proceed if there are plenty of stripe_heads. * We need a minimum of one full stripe,, and for sensible progress @@ -4514,18 +4875,12 @@ static int raid5_check_reshape(mddev_t *mddev) if ((mddev->chunk_size / STRIPE_SIZE) * 4 > conf->max_nr_stripes || (mddev->new_chunk / STRIPE_SIZE) * 4 > conf->max_nr_stripes) { printk(KERN_WARNING "raid5: reshape: not enough stripes. Needed %lu\n", - (mddev->chunk_size / STRIPE_SIZE)*4); + (max(mddev->chunk_size, mddev->new_chunk) + / STRIPE_SIZE)*4); return -ENOSPC; } - err = resize_stripes(conf, conf->raid_disks + mddev->delta_disks); - if (err) - return err; - - if (mddev->degraded > conf->max_degraded) - return -EINVAL; - /* looks like we might be able to manage this */ - return 0; + return resize_stripes(conf, conf->raid_disks + mddev->delta_disks); } static int raid5_start_reshape(mddev_t *mddev) @@ -4550,12 +4905,31 @@ static int raid5_start_reshape(mddev_t *mddev) */ return -EINVAL; + /* Refuse to reduce size of the array. Any reductions in + * array size must be through explicit setting of array_size + * attribute. + */ + if (raid5_size(mddev, 0, conf->raid_disks + mddev->delta_disks) + < mddev->array_sectors) { + printk(KERN_ERR "md: %s: array size must be reduced " + "before number of disks\n", mdname(mddev)); + return -EINVAL; + } + atomic_set(&conf->reshape_stripes, 0); spin_lock_irq(&conf->device_lock); conf->previous_raid_disks = conf->raid_disks; conf->raid_disks += mddev->delta_disks; - conf->expand_progress = 0; - conf->expand_lo = 0; + conf->prev_chunk = conf->chunk_size; + conf->chunk_size = mddev->new_chunk; + conf->prev_algo = conf->algorithm; + conf->algorithm = mddev->new_layout; + if (mddev->delta_disks < 0) + conf->reshape_progress = raid5_size(mddev, 0, 0); + else + conf->reshape_progress = 0; + conf->reshape_safe = conf->reshape_progress; + conf->generation++; spin_unlock_irq(&conf->device_lock); /* Add some new drives, as many as will fit. @@ -4580,9 +4954,12 @@ static int raid5_start_reshape(mddev_t *mddev) break; } - spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices; - spin_unlock_irqrestore(&conf->device_lock, flags); + if (mddev->delta_disks > 0) { + spin_lock_irqsave(&conf->device_lock, flags); + mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) + - added_devices; + spin_unlock_irqrestore(&conf->device_lock, flags); + } mddev->raid_disks = conf->raid_disks; mddev->reshape_position = 0; set_bit(MD_CHANGE_DEVS, &mddev->flags); @@ -4597,52 +4974,86 @@ static int raid5_start_reshape(mddev_t *mddev) mddev->recovery = 0; spin_lock_irq(&conf->device_lock); mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks; - conf->expand_progress = MaxSector; + conf->reshape_progress = MaxSector; spin_unlock_irq(&conf->device_lock); return -EAGAIN; } + conf->reshape_checkpoint = jiffies; md_wakeup_thread(mddev->sync_thread); md_new_event(mddev); return 0; } -#endif +/* This is called from the reshape thread and should make any + * changes needed in 'conf' + */ static void end_reshape(raid5_conf_t *conf) { - struct block_device *bdev; if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { - conf->mddev->array_sectors = 2 * conf->mddev->size * - (conf->raid_disks - conf->max_degraded); - set_capacity(conf->mddev->gendisk, conf->mddev->array_sectors); - conf->mddev->changed = 1; - - bdev = bdget_disk(conf->mddev->gendisk, 0); - if (bdev) { - mutex_lock(&bdev->bd_inode->i_mutex); - i_size_write(bdev->bd_inode, - (loff_t)conf->mddev->array_sectors << 9); - mutex_unlock(&bdev->bd_inode->i_mutex); - bdput(bdev); - } + spin_lock_irq(&conf->device_lock); - conf->expand_progress = MaxSector; + conf->previous_raid_disks = conf->raid_disks; + conf->reshape_progress = MaxSector; spin_unlock_irq(&conf->device_lock); - conf->mddev->reshape_position = MaxSector; + wake_up(&conf->wait_for_overlap); /* read-ahead size must cover two whole stripes, which is * 2 * (datadisks) * chunksize where 'n' is the number of raid devices */ { - int data_disks = conf->previous_raid_disks - conf->max_degraded; - int stripe = data_disks * - (conf->mddev->chunk_size / PAGE_SIZE); + int data_disks = conf->raid_disks - conf->max_degraded; + int stripe = data_disks * (conf->chunk_size + / PAGE_SIZE); if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe) conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe; } } } +/* This is called from the raid5d thread with mddev_lock held. + * It makes config changes to the device. + */ +static void raid5_finish_reshape(mddev_t *mddev) +{ + struct block_device *bdev; + raid5_conf_t *conf = mddev_to_conf(mddev); + + if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { + + if (mddev->delta_disks > 0) { + md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); + set_capacity(mddev->gendisk, mddev->array_sectors); + mddev->changed = 1; + + bdev = bdget_disk(mddev->gendisk, 0); + if (bdev) { + mutex_lock(&bdev->bd_inode->i_mutex); + i_size_write(bdev->bd_inode, + (loff_t)mddev->array_sectors << 9); + mutex_unlock(&bdev->bd_inode->i_mutex); + bdput(bdev); + } + } else { + int d; + mddev->degraded = conf->raid_disks; + for (d = 0; d < conf->raid_disks ; d++) + if (conf->disks[d].rdev && + test_bit(In_sync, + &conf->disks[d].rdev->flags)) + mddev->degraded--; + for (d = conf->raid_disks ; + d < conf->raid_disks - mddev->delta_disks; + d++) + raid5_remove_disk(mddev, d); + } + mddev->layout = conf->algorithm; + mddev->chunk_size = conf->chunk_size; + mddev->reshape_position = MaxSector; + mddev->delta_disks = 0; + } +} + static void raid5_quiesce(mddev_t *mddev, int state) { raid5_conf_t *conf = mddev_to_conf(mddev); @@ -4672,6 +5083,212 @@ static void raid5_quiesce(mddev_t *mddev, int state) } } + +static void *raid5_takeover_raid1(mddev_t *mddev) +{ + int chunksect; + + if (mddev->raid_disks != 2 || + mddev->degraded > 1) + return ERR_PTR(-EINVAL); + + /* Should check if there are write-behind devices? */ + + chunksect = 64*2; /* 64K by default */ + + /* The array must be an exact multiple of chunksize */ + while (chunksect && (mddev->array_sectors & (chunksect-1))) + chunksect >>= 1; + + if ((chunksect<<9) < STRIPE_SIZE) + /* array size does not allow a suitable chunk size */ + return ERR_PTR(-EINVAL); + + mddev->new_level = 5; + mddev->new_layout = ALGORITHM_LEFT_SYMMETRIC; + mddev->new_chunk = chunksect << 9; + + return setup_conf(mddev); +} + +static void *raid5_takeover_raid6(mddev_t *mddev) +{ + int new_layout; + + switch (mddev->layout) { + case ALGORITHM_LEFT_ASYMMETRIC_6: + new_layout = ALGORITHM_LEFT_ASYMMETRIC; + break; + case ALGORITHM_RIGHT_ASYMMETRIC_6: + new_layout = ALGORITHM_RIGHT_ASYMMETRIC; + break; + case ALGORITHM_LEFT_SYMMETRIC_6: + new_layout = ALGORITHM_LEFT_SYMMETRIC; + break; + case ALGORITHM_RIGHT_SYMMETRIC_6: + new_layout = ALGORITHM_RIGHT_SYMMETRIC; + break; + case ALGORITHM_PARITY_0_6: + new_layout = ALGORITHM_PARITY_0; + break; + case ALGORITHM_PARITY_N: + new_layout = ALGORITHM_PARITY_N; + break; + default: + return ERR_PTR(-EINVAL); + } + mddev->new_level = 5; + mddev->new_layout = new_layout; + mddev->delta_disks = -1; + mddev->raid_disks -= 1; + return setup_conf(mddev); +} + + +static int raid5_reconfig(mddev_t *mddev, int new_layout, int new_chunk) +{ + /* For a 2-drive array, the layout and chunk size can be changed + * immediately as not restriping is needed. + * For larger arrays we record the new value - after validation + * to be used by a reshape pass. + */ + raid5_conf_t *conf = mddev_to_conf(mddev); + + if (new_layout >= 0 && !algorithm_valid_raid5(new_layout)) + return -EINVAL; + if (new_chunk > 0) { + if (new_chunk & (new_chunk-1)) + /* not a power of 2 */ + return -EINVAL; + if (new_chunk < PAGE_SIZE) + return -EINVAL; + if (mddev->array_sectors & ((new_chunk>>9)-1)) + /* not factor of array size */ + return -EINVAL; + } + + /* They look valid */ + + if (mddev->raid_disks == 2) { + + if (new_layout >= 0) { + conf->algorithm = new_layout; + mddev->layout = mddev->new_layout = new_layout; + } + if (new_chunk > 0) { + conf->chunk_size = new_chunk; + mddev->chunk_size = mddev->new_chunk = new_chunk; + } + set_bit(MD_CHANGE_DEVS, &mddev->flags); + md_wakeup_thread(mddev->thread); + } else { + if (new_layout >= 0) + mddev->new_layout = new_layout; + if (new_chunk > 0) + mddev->new_chunk = new_chunk; + } + return 0; +} + +static int raid6_reconfig(mddev_t *mddev, int new_layout, int new_chunk) +{ + if (new_layout >= 0 && !algorithm_valid_raid6(new_layout)) + return -EINVAL; + if (new_chunk > 0) { + if (new_chunk & (new_chunk-1)) + /* not a power of 2 */ + return -EINVAL; + if (new_chunk < PAGE_SIZE) + return -EINVAL; + if (mddev->array_sectors & ((new_chunk>>9)-1)) + /* not factor of array size */ + return -EINVAL; + } + + /* They look valid */ + + if (new_layout >= 0) + mddev->new_layout = new_layout; + if (new_chunk > 0) + mddev->new_chunk = new_chunk; + + return 0; +} + +static void *raid5_takeover(mddev_t *mddev) +{ + /* raid5 can take over: + * raid0 - if all devices are the same - make it a raid4 layout + * raid1 - if there are two drives. We need to know the chunk size + * raid4 - trivial - just use a raid4 layout. + * raid6 - Providing it is a *_6 layout + * + * For now, just do raid1 + */ + + if (mddev->level == 1) + return raid5_takeover_raid1(mddev); + if (mddev->level == 4) { + mddev->new_layout = ALGORITHM_PARITY_N; + mddev->new_level = 5; + return setup_conf(mddev); + } + if (mddev->level == 6) + return raid5_takeover_raid6(mddev); + + return ERR_PTR(-EINVAL); +} + + +static struct mdk_personality raid5_personality; + +static void *raid6_takeover(mddev_t *mddev) +{ + /* Currently can only take over a raid5. We map the + * personality to an equivalent raid6 personality + * with the Q block at the end. + */ + int new_layout; + + if (mddev->pers != &raid5_personality) + return ERR_PTR(-EINVAL); + if (mddev->degraded > 1) + return ERR_PTR(-EINVAL); + if (mddev->raid_disks > 253) + return ERR_PTR(-EINVAL); + if (mddev->raid_disks < 3) + return ERR_PTR(-EINVAL); + + switch (mddev->layout) { + case ALGORITHM_LEFT_ASYMMETRIC: + new_layout = ALGORITHM_LEFT_ASYMMETRIC_6; + break; + case ALGORITHM_RIGHT_ASYMMETRIC: + new_layout = ALGORITHM_RIGHT_ASYMMETRIC_6; + break; + case ALGORITHM_LEFT_SYMMETRIC: + new_layout = ALGORITHM_LEFT_SYMMETRIC_6; + break; + case ALGORITHM_RIGHT_SYMMETRIC: + new_layout = ALGORITHM_RIGHT_SYMMETRIC_6; + break; + case ALGORITHM_PARITY_0: + new_layout = ALGORITHM_PARITY_0_6; + break; + case ALGORITHM_PARITY_N: + new_layout = ALGORITHM_PARITY_N; + break; + default: + return ERR_PTR(-EINVAL); + } + mddev->new_level = 6; + mddev->new_layout = new_layout; + mddev->delta_disks = 1; + mddev->raid_disks += 1; + return setup_conf(mddev); +} + + static struct mdk_personality raid6_personality = { .name = "raid6", @@ -4687,11 +5304,13 @@ static struct mdk_personality raid6_personality = .spare_active = raid5_spare_active, .sync_request = sync_request, .resize = raid5_resize, -#ifdef CONFIG_MD_RAID5_RESHAPE + .size = raid5_size, .check_reshape = raid5_check_reshape, .start_reshape = raid5_start_reshape, -#endif + .finish_reshape = raid5_finish_reshape, .quiesce = raid5_quiesce, + .takeover = raid6_takeover, + .reconfig = raid6_reconfig, }; static struct mdk_personality raid5_personality = { @@ -4708,11 +5327,13 @@ static struct mdk_personality raid5_personality = .spare_active = raid5_spare_active, .sync_request = sync_request, .resize = raid5_resize, -#ifdef CONFIG_MD_RAID5_RESHAPE + .size = raid5_size, .check_reshape = raid5_check_reshape, .start_reshape = raid5_start_reshape, -#endif + .finish_reshape = raid5_finish_reshape, .quiesce = raid5_quiesce, + .takeover = raid5_takeover, + .reconfig = raid5_reconfig, }; static struct mdk_personality raid4_personality = @@ -4730,20 +5351,15 @@ static struct mdk_personality raid4_personality = .spare_active = raid5_spare_active, .sync_request = sync_request, .resize = raid5_resize, -#ifdef CONFIG_MD_RAID5_RESHAPE + .size = raid5_size, .check_reshape = raid5_check_reshape, .start_reshape = raid5_start_reshape, -#endif + .finish_reshape = raid5_finish_reshape, .quiesce = raid5_quiesce, }; static int __init raid5_init(void) { - int e; - - e = raid6_select_algo(); - if ( e ) - return e; register_md_personality(&raid6_personality); register_md_personality(&raid5_personality); register_md_personality(&raid4_personality); diff --git a/trunk/include/linux/raid/raid5.h b/trunk/drivers/md/raid5.h similarity index 81% rename from trunk/include/linux/raid/raid5.h rename to trunk/drivers/md/raid5.h index 3b2672792457..52ba99954dec 100644 --- a/trunk/include/linux/raid/raid5.h +++ b/trunk/drivers/md/raid5.h @@ -1,7 +1,6 @@ #ifndef _RAID5_H #define _RAID5_H -#include #include /* @@ -197,15 +196,19 @@ enum reconstruct_states { struct stripe_head { struct hlist_node hash; - struct list_head lru; /* inactive_list or handle_list */ - struct raid5_private_data *raid_conf; - sector_t sector; /* sector of this row */ - int pd_idx; /* parity disk index */ - unsigned long state; /* state flags */ - atomic_t count; /* nr of active thread/requests */ + struct list_head lru; /* inactive_list or handle_list */ + struct raid5_private_data *raid_conf; + short generation; /* increments with every + * reshape */ + sector_t sector; /* sector of this row */ + short pd_idx; /* parity disk index */ + short qd_idx; /* 'Q' disk index for raid6 */ + short ddf_layout;/* use DDF ordering to calculate Q */ + unsigned long state; /* state flags */ + atomic_t count; /* nr of active thread/requests */ spinlock_t lock; int bm_seq; /* sequence number for bitmap flushes */ - int disks; /* disks in stripe */ + int disks; /* disks in stripe */ enum check_states check_state; enum reconstruct_states reconstruct_state; /* stripe_operations @@ -238,7 +241,7 @@ struct stripe_head_state { /* r6_state - extra state data only relevant to r6 */ struct r6_state { - int p_failed, q_failed, qd_idx, failed_num[2]; + int p_failed, q_failed, failed_num[2]; }; /* Flags */ @@ -268,6 +271,8 @@ struct r6_state { #define READ_MODIFY_WRITE 2 /* not a write method, but a compute_parity mode */ #define CHECK_PARITY 3 +/* Additional compute_parity mode -- updates the parity w/o LOCKING */ +#define UPDATE_PARITY 4 /* * Stripe state @@ -319,7 +324,7 @@ struct r6_state { * PREREAD_ACTIVE is set, else we set DELAYED which will send it to the delayed queue. * HANDLE gets cleared if stripe_handle leave nothing locked. */ - + struct disk_info { mdk_rdev_t *rdev; @@ -334,12 +339,21 @@ struct raid5_private_data { int raid_disks; int max_nr_stripes; - /* used during an expand */ - sector_t expand_progress; /* MaxSector when no expand happening */ - sector_t expand_lo; /* from here up to expand_progress it out-of-bounds - * as we haven't flushed the metadata yet - */ + /* reshape_progress is the leading edge of a 'reshape' + * It has value MaxSector when no reshape is happening + * If delta_disks < 0, it is the last sector we started work on, + * else is it the next sector to work on. + */ + sector_t reshape_progress; + /* reshape_safe is the trailing edge of a reshape. We know that + * before (or after) this address, all reshape has completed. + */ + sector_t reshape_safe; int previous_raid_disks; + int prev_chunk, prev_algo; + short generation; /* increments with every reshape */ + unsigned long reshape_checkpoint; /* Time we last updated + * metadata */ struct list_head handle_list; /* stripes needing handling */ struct list_head hold_list; /* preread ready stripes */ @@ -385,6 +399,11 @@ struct raid5_private_data { int pool_size; /* number of disks in stripeheads in pool */ spinlock_t device_lock; struct disk_info *disks; + + /* When taking over an array from a different personality, we store + * the new thread here until we fully activate the array. + */ + struct mdk_thread_s *thread; }; typedef struct raid5_private_data raid5_conf_t; @@ -394,9 +413,62 @@ typedef struct raid5_private_data raid5_conf_t; /* * Our supported algorithms */ -#define ALGORITHM_LEFT_ASYMMETRIC 0 -#define ALGORITHM_RIGHT_ASYMMETRIC 1 -#define ALGORITHM_LEFT_SYMMETRIC 2 -#define ALGORITHM_RIGHT_SYMMETRIC 3 +#define ALGORITHM_LEFT_ASYMMETRIC 0 /* Rotating Parity N with Data Restart */ +#define ALGORITHM_RIGHT_ASYMMETRIC 1 /* Rotating Parity 0 with Data Restart */ +#define ALGORITHM_LEFT_SYMMETRIC 2 /* Rotating Parity N with Data Continuation */ +#define ALGORITHM_RIGHT_SYMMETRIC 3 /* Rotating Parity 0 with Data Continuation */ + +/* Define non-rotating (raid4) algorithms. These allow + * conversion of raid4 to raid5. + */ +#define ALGORITHM_PARITY_0 4 /* P or P,Q are initial devices */ +#define ALGORITHM_PARITY_N 5 /* P or P,Q are final devices. */ + +/* DDF RAID6 layouts differ from md/raid6 layouts in two ways. + * Firstly, the exact positioning of the parity block is slightly + * different between the 'LEFT_*' modes of md and the "_N_*" modes + * of DDF. + * Secondly, or order of datablocks over which the Q syndrome is computed + * is different. + * Consequently we have different layouts for DDF/raid6 than md/raid6. + * These layouts are from the DDFv1.2 spec. + * Interestingly DDFv1.2-Errata-A does not specify N_CONTINUE but + * leaves RLQ=3 as 'Vendor Specific' + */ + +#define ALGORITHM_ROTATING_ZERO_RESTART 8 /* DDF PRL=6 RLQ=1 */ +#define ALGORITHM_ROTATING_N_RESTART 9 /* DDF PRL=6 RLQ=2 */ +#define ALGORITHM_ROTATING_N_CONTINUE 10 /*DDF PRL=6 RLQ=3 */ + + +/* For every RAID5 algorithm we define a RAID6 algorithm + * with exactly the same layout for data and parity, and + * with the Q block always on the last device (N-1). + * This allows trivial conversion from RAID5 to RAID6 + */ +#define ALGORITHM_LEFT_ASYMMETRIC_6 16 +#define ALGORITHM_RIGHT_ASYMMETRIC_6 17 +#define ALGORITHM_LEFT_SYMMETRIC_6 18 +#define ALGORITHM_RIGHT_SYMMETRIC_6 19 +#define ALGORITHM_PARITY_0_6 20 +#define ALGORITHM_PARITY_N_6 ALGORITHM_PARITY_N + +static inline int algorithm_valid_raid5(int layout) +{ + return (layout >= 0) && + (layout <= 5); +} +static inline int algorithm_valid_raid6(int layout) +{ + return (layout >= 0 && layout <= 5) + || + (layout == 8 || layout == 10) + || + (layout >= 16 && layout <= 20); +} +static inline int algorithm_is_DDF(int layout) +{ + return layout >= 8 && layout <= 10; +} #endif diff --git a/trunk/drivers/md/raid6algos.c b/trunk/drivers/md/raid6algos.c index 21987e3dbe6c..866215ac7f25 100644 --- a/trunk/drivers/md/raid6algos.c +++ b/trunk/drivers/md/raid6algos.c @@ -5,7 +5,7 @@ * 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, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or + * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -16,13 +16,20 @@ * Algorithm list and algorithm selection for RAID-6 */ -#include "raid6.h" +#include #ifndef __KERNEL__ #include #include +#else +#if !RAID6_USE_EMPTY_ZERO_PAGE +/* In .bss so it's zeroed */ +const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); +EXPORT_SYMBOL(raid6_empty_zero_page); +#endif #endif struct raid6_calls raid6_call; +EXPORT_SYMBOL_GPL(raid6_call); /* Various routine sets */ extern const struct raid6_calls raid6_intx1; @@ -79,6 +86,7 @@ const struct raid6_calls * const raid6_algos[] = { #else /* Need more time to be stable in userspace */ #define RAID6_TIME_JIFFIES_LG2 9 +#define time_before(x, y) ((x) < (y)) #endif /* Try to pick the best algorithm */ @@ -152,3 +160,12 @@ int __init raid6_select_algo(void) return best ? 0 : -EINVAL; } + +static void raid6_exit(void) +{ + do { } while (0); +} + +subsys_initcall(raid6_select_algo); +module_exit(raid6_exit); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/md/raid6altivec.uc b/trunk/drivers/md/raid6altivec.uc index b9afd35b8812..699dfeee4944 100644 --- a/trunk/drivers/md/raid6altivec.uc +++ b/trunk/drivers/md/raid6altivec.uc @@ -5,7 +5,7 @@ * 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, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or + * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -22,7 +22,7 @@ * bracked this with preempt_disable/enable or in a lock) */ -#include "raid6.h" +#include #ifdef CONFIG_ALTIVEC diff --git a/trunk/drivers/md/raid6int.uc b/trunk/drivers/md/raid6int.uc index ad004cee0e26..f9bf9cba357f 100644 --- a/trunk/drivers/md/raid6int.uc +++ b/trunk/drivers/md/raid6int.uc @@ -5,7 +5,7 @@ * 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, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or + * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -18,7 +18,7 @@ * This file is postprocessed using unroll.pl */ -#include "raid6.h" +#include /* * This is the C data type to use diff --git a/trunk/drivers/md/raid6mmx.c b/trunk/drivers/md/raid6mmx.c index d4e4a1bd70ad..e7f6c13132bf 100644 --- a/trunk/drivers/md/raid6mmx.c +++ b/trunk/drivers/md/raid6mmx.c @@ -5,7 +5,7 @@ * 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, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or + * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -18,7 +18,7 @@ #if defined(__i386__) && !defined(__arch_um__) -#include "raid6.h" +#include #include "raid6x86.h" /* Shared with raid6sse1.c */ diff --git a/trunk/drivers/md/raid6recov.c b/trunk/drivers/md/raid6recov.c index a8c4d9451bd9..2609f00e0d61 100644 --- a/trunk/drivers/md/raid6recov.c +++ b/trunk/drivers/md/raid6recov.c @@ -5,7 +5,7 @@ * 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, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or + * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -18,7 +18,7 @@ * the syndrome.) */ -#include "raid6.h" +#include /* Recover two failed data blocks. */ void raid6_2data_recov(int disks, size_t bytes, int faila, int failb, @@ -63,9 +63,7 @@ void raid6_2data_recov(int disks, size_t bytes, int faila, int failb, p++; q++; } } - - - +EXPORT_SYMBOL_GPL(raid6_2data_recov); /* Recover failure of one data block plus the P block */ void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs) @@ -97,9 +95,10 @@ void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs) q++; dq++; } } +EXPORT_SYMBOL_GPL(raid6_datap_recov); - -#ifndef __KERNEL__ /* Testing only */ +#ifndef __KERNEL__ +/* Testing only */ /* Recover two failed blocks. */ void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs) diff --git a/trunk/drivers/md/raid6sse1.c b/trunk/drivers/md/raid6sse1.c index 0666237276ff..b274dd5eab8f 100644 --- a/trunk/drivers/md/raid6sse1.c +++ b/trunk/drivers/md/raid6sse1.c @@ -5,7 +5,7 @@ * 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, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or + * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -23,7 +23,7 @@ #if defined(__i386__) && !defined(__arch_um__) -#include "raid6.h" +#include #include "raid6x86.h" /* Defined in raid6mmx.c */ diff --git a/trunk/drivers/md/raid6sse2.c b/trunk/drivers/md/raid6sse2.c index b034ad868039..6ed6c6c0389f 100644 --- a/trunk/drivers/md/raid6sse2.c +++ b/trunk/drivers/md/raid6sse2.c @@ -5,7 +5,7 @@ * 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, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or + * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -19,7 +19,7 @@ #if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__) -#include "raid6.h" +#include #include "raid6x86.h" static const struct raid6_sse_constants { diff --git a/trunk/drivers/md/raid6test/Makefile b/trunk/drivers/md/raid6test/Makefile index 78e0396adf2a..58ffdf4f5161 100644 --- a/trunk/drivers/md/raid6test/Makefile +++ b/trunk/drivers/md/raid6test/Makefile @@ -5,7 +5,7 @@ CC = gcc OPTFLAGS = -O2 # Adjust as desired -CFLAGS = -I.. -g $(OPTFLAGS) +CFLAGS = -I.. -I ../../../include -g $(OPTFLAGS) LD = ld PERL = perl AR = ar diff --git a/trunk/drivers/md/raid6test/test.c b/trunk/drivers/md/raid6test/test.c index 559cc41b2585..7a930318b17d 100644 --- a/trunk/drivers/md/raid6test/test.c +++ b/trunk/drivers/md/raid6test/test.c @@ -17,7 +17,7 @@ #include #include #include -#include "raid6.h" +#include #define NDISKS 16 /* Including P and Q */ diff --git a/trunk/drivers/md/raid6x86.h b/trunk/drivers/md/raid6x86.h index 99fea7a70ca7..4c22c1568558 100644 --- a/trunk/drivers/md/raid6x86.h +++ b/trunk/drivers/md/raid6x86.h @@ -5,7 +5,7 @@ * 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, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or + * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ diff --git a/trunk/drivers/misc/Kconfig b/trunk/drivers/misc/Kconfig index 1c484084ed4f..0b92b2f6ea68 100644 --- a/trunk/drivers/misc/Kconfig +++ b/trunk/drivers/misc/Kconfig @@ -165,7 +165,7 @@ config SGI_XP depends on (IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || X86_UV) && SMP select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 - select SGI_GRU if (IA64_GENERIC || IA64_SGI_UV || X86_64) && SMP + select SGI_GRU if X86_64 && SMP ---help--- An SGI machine can be divided into multiple Single System Images which act independently of each other and have @@ -189,7 +189,7 @@ config HP_ILO config SGI_GRU tristate "SGI GRU driver" - depends on (X86_UV || IA64_SGI_UV || IA64_GENERIC) && SMP + depends on X86_UV && SMP default n select MMU_NOTIFIER ---help--- @@ -223,6 +223,16 @@ config DELL_LAPTOP This driver adds support for rfkill and backlight control to Dell laptops. +config ISL29003 + tristate "Intersil ISL29003 ambient light sensor" + depends on I2C && SYSFS + help + If you say yes here you get support for the Intersil ISL29003 + ambient light sensor. + + This driver can also be built as a module. If so, the module + will be called isl29003. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" diff --git a/trunk/drivers/misc/Makefile b/trunk/drivers/misc/Makefile index bc1199830554..7871f05dcb9b 100644 --- a/trunk/drivers/misc/Makefile +++ b/trunk/drivers/misc/Makefile @@ -18,5 +18,6 @@ obj-$(CONFIG_KGDB_TESTS) += kgdbts.o obj-$(CONFIG_SGI_XP) += sgi-xp/ obj-$(CONFIG_SGI_GRU) += sgi-gru/ obj-$(CONFIG_HP_ILO) += hpilo.o +obj-$(CONFIG_ISL29003) += isl29003.o obj-$(CONFIG_C2PORT) += c2port/ obj-y += eeprom/ diff --git a/trunk/drivers/misc/eeprom/at24.c b/trunk/drivers/misc/eeprom/at24.c index d4775528abc6..d184dfab9631 100644 --- a/trunk/drivers/misc/eeprom/at24.c +++ b/trunk/drivers/misc/eeprom/at24.c @@ -53,6 +53,7 @@ struct at24_data { struct at24_platform_data chip; + struct memory_accessor macc; bool use_smbus; /* @@ -225,14 +226,11 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, return status; } -static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, +static ssize_t at24_read(struct at24_data *at24, char *buf, loff_t off, size_t count) { - struct at24_data *at24; ssize_t retval = 0; - at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); - if (unlikely(!count)) return count; @@ -262,12 +260,14 @@ static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, return retval; } +static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct at24_data *at24; -/* - * REVISIT: export at24_bin{read,write}() to let other kernel code use - * eeprom data. For example, it might hold a board's Ethernet address, or - * board-specific calibration data generated on the manufacturing floor. - */ + at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); + return at24_read(at24, buf, off, count); +} /* @@ -347,14 +347,11 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, char *buf, return -ETIMEDOUT; } -static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, +static ssize_t at24_write(struct at24_data *at24, char *buf, loff_t off, size_t count) { - struct at24_data *at24; ssize_t retval = 0; - at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); - if (unlikely(!count)) return count; @@ -384,6 +381,39 @@ static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, return retval; } +static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct at24_data *at24; + + at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); + return at24_write(at24, buf, off, count); +} + +/*-------------------------------------------------------------------------*/ + +/* + * This lets other kernel code access the eeprom data. For example, it + * might hold a board's Ethernet address, or board-specific calibration + * data generated on the manufacturing floor. + */ + +static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf, + off_t offset, size_t count) +{ + struct at24_data *at24 = container_of(macc, struct at24_data, macc); + + return at24_read(at24, buf, offset, count); +} + +static ssize_t at24_macc_write(struct memory_accessor *macc, char *buf, + off_t offset, size_t count) +{ + struct at24_data *at24 = container_of(macc, struct at24_data, macc); + + return at24_write(at24, buf, offset, count); +} + /*-------------------------------------------------------------------------*/ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -413,6 +443,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) * is recommended anyhow. */ chip.page_size = 1; + + chip.setup = NULL; + chip.context = NULL; } if (!is_power_of_2(chip.byte_len)) @@ -463,6 +496,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->bin.read = at24_bin_read; at24->bin.size = chip.byte_len; + at24->macc.read = at24_macc_read; + writable = !(chip.flags & AT24_FLAG_READONLY); if (writable) { if (!use_smbus || i2c_check_functionality(client->adapter, @@ -470,6 +505,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) unsigned write_max = chip.page_size; + at24->macc.write = at24_macc_write; + at24->bin.write = at24_bin_write; at24->bin.attr.mode |= S_IWUSR; @@ -520,6 +557,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) at24->write_max, use_smbus ? ", use_smbus" : ""); + /* export data to kernel code */ + if (chip.setup) + chip.setup(&at24->macc, chip.context); + return 0; err_clients: diff --git a/trunk/drivers/misc/eeprom/at25.c b/trunk/drivers/misc/eeprom/at25.c index 290dbe99647a..6bc0dac5c1e8 100644 --- a/trunk/drivers/misc/eeprom/at25.c +++ b/trunk/drivers/misc/eeprom/at25.c @@ -30,6 +30,7 @@ struct at25_data { struct spi_device *spi; + struct memory_accessor mem; struct mutex lock; struct spi_eeprom chip; struct bin_attribute bin; @@ -75,6 +76,13 @@ at25_ee_read( struct spi_transfer t[2]; struct spi_message m; + if (unlikely(offset >= at25->bin.size)) + return 0; + if ((offset + count) > at25->bin.size) + count = at25->bin.size - offset; + if (unlikely(!count)) + return count; + cp = command; *cp++ = AT25_READ; @@ -127,13 +135,6 @@ at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr, dev = container_of(kobj, struct device, kobj); at25 = dev_get_drvdata(dev); - if (unlikely(off >= at25->bin.size)) - return 0; - if ((off + count) > at25->bin.size) - count = at25->bin.size - off; - if (unlikely(!count)) - return count; - return at25_ee_read(at25, buf, off, count); } @@ -146,6 +147,13 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count) unsigned buf_size; u8 *bounce; + if (unlikely(off >= at25->bin.size)) + return -EFBIG; + if ((off + count) > at25->bin.size) + count = at25->bin.size - off; + if (unlikely(!count)) + return count; + /* Temp buffer starts with command and address */ buf_size = at25->chip.page_size; if (buf_size > io_limit) @@ -253,18 +261,31 @@ at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr, dev = container_of(kobj, struct device, kobj); at25 = dev_get_drvdata(dev); - if (unlikely(off >= at25->bin.size)) - return -EFBIG; - if ((off + count) > at25->bin.size) - count = at25->bin.size - off; - if (unlikely(!count)) - return count; - return at25_ee_write(at25, buf, off, count); } /*-------------------------------------------------------------------------*/ +/* Let in-kernel code access the eeprom data. */ + +static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf, + off_t offset, size_t count) +{ + struct at25_data *at25 = container_of(mem, struct at25_data, mem); + + return at25_ee_read(at25, buf, offset, count); +} + +static ssize_t at25_mem_write(struct memory_accessor *mem, char *buf, + off_t offset, size_t count) +{ + struct at25_data *at25 = container_of(mem, struct at25_data, mem); + + return at25_ee_write(at25, buf, offset, count); +} + +/*-------------------------------------------------------------------------*/ + static int at25_probe(struct spi_device *spi) { struct at25_data *at25 = NULL; @@ -317,6 +338,10 @@ static int at25_probe(struct spi_device *spi) at25->addrlen = addrlen; /* Export the EEPROM bytes through sysfs, since that's convenient. + * And maybe to other kernel code; it might hold a board's Ethernet + * address, or board-specific calibration data generated on the + * manufacturing floor. + * * Default to root-only access to the data; EEPROMs often hold data * that's sensitive for read and/or write, like ethernet addresses, * security codes, board-specific manufacturing calibrations, etc. @@ -324,17 +349,22 @@ static int at25_probe(struct spi_device *spi) at25->bin.attr.name = "eeprom"; at25->bin.attr.mode = S_IRUSR; at25->bin.read = at25_bin_read; + at25->mem.read = at25_mem_read; at25->bin.size = at25->chip.byte_len; if (!(chip->flags & EE_READONLY)) { at25->bin.write = at25_bin_write; at25->bin.attr.mode |= S_IWUSR; + at25->mem.write = at25_mem_write; } err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin); if (err) goto fail; + if (chip->setup) + chip->setup(&at25->mem, chip->context); + dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n", (at25->bin.size < 1024) ? at25->bin.size diff --git a/trunk/drivers/misc/hpilo.c b/trunk/drivers/misc/hpilo.c index cf991850f01b..880ccf39e23b 100644 --- a/trunk/drivers/misc/hpilo.c +++ b/trunk/drivers/misc/hpilo.c @@ -209,7 +209,7 @@ static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data) /* give iLO some time to process stop request */ for (retries = MAX_WAIT; retries > 0; retries--) { doorbell_set(driver_ccb); - udelay(1); + udelay(WAIT_TIME); if (!(ioread32(&device_ccb->send_ctrl) & (1 << CTRL_BITPOS_A)) && !(ioread32(&device_ccb->recv_ctrl) & (1 << CTRL_BITPOS_A))) @@ -312,7 +312,7 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) for (i = MAX_WAIT; i > 0; i--) { if (ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, NULL, NULL)) break; - udelay(1); + udelay(WAIT_TIME); } if (i) { @@ -759,7 +759,7 @@ static void __exit ilo_exit(void) class_destroy(ilo_class); } -MODULE_VERSION("1.0"); +MODULE_VERSION("1.1"); MODULE_ALIAS(ILO_NAME); MODULE_DESCRIPTION(ILO_NAME); MODULE_AUTHOR("David Altobelli "); diff --git a/trunk/drivers/misc/hpilo.h b/trunk/drivers/misc/hpilo.h index b64a20ef07e3..03a14c82aad9 100644 --- a/trunk/drivers/misc/hpilo.h +++ b/trunk/drivers/misc/hpilo.h @@ -19,8 +19,12 @@ #define MAX_ILO_DEV 1 /* max number of files */ #define MAX_OPEN (MAX_CCB * MAX_ILO_DEV) +/* total wait time in usec */ +#define MAX_WAIT_TIME 10000 +/* per spin wait time in usec */ +#define WAIT_TIME 10 /* spin counter for open/close delay */ -#define MAX_WAIT 10000 +#define MAX_WAIT (MAX_WAIT_TIME / WAIT_TIME) /* * Per device, used to track global memory allocations. diff --git a/trunk/drivers/misc/isl29003.c b/trunk/drivers/misc/isl29003.c new file mode 100644 index 000000000000..2e2a5923d4c2 --- /dev/null +++ b/trunk/drivers/misc/isl29003.c @@ -0,0 +1,470 @@ +/* + * isl29003.c - Linux kernel module for + * Intersil ISL29003 ambient light sensor + * + * See file:Documentation/misc-devices/isl29003 + * + * Copyright (c) 2009 Daniel Mack + * + * Based on code written by + * Rodolfo Giometti + * Eurotech S.p.A. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include + +#define ISL29003_DRV_NAME "isl29003" +#define DRIVER_VERSION "1.0" + +#define ISL29003_REG_COMMAND 0x00 +#define ISL29003_ADC_ENABLED (1 << 7) +#define ISL29003_ADC_PD (1 << 6) +#define ISL29003_TIMING_INT (1 << 5) +#define ISL29003_MODE_SHIFT (2) +#define ISL29003_MODE_MASK (0x3 << ISL29003_MODE_SHIFT) +#define ISL29003_RES_SHIFT (0) +#define ISL29003_RES_MASK (0x3 << ISL29003_RES_SHIFT) + +#define ISL29003_REG_CONTROL 0x01 +#define ISL29003_INT_FLG (1 << 5) +#define ISL29003_RANGE_SHIFT (2) +#define ISL29003_RANGE_MASK (0x3 << ISL29003_RANGE_SHIFT) +#define ISL29003_INT_PERSISTS_SHIFT (0) +#define ISL29003_INT_PERSISTS_MASK (0xf << ISL29003_INT_PERSISTS_SHIFT) + +#define ISL29003_REG_IRQ_THRESH_HI 0x02 +#define ISL29003_REG_IRQ_THRESH_LO 0x03 +#define ISL29003_REG_LSB_SENSOR 0x04 +#define ISL29003_REG_MSB_SENSOR 0x05 +#define ISL29003_REG_LSB_TIMER 0x06 +#define ISL29003_REG_MSB_TIMER 0x07 + +#define ISL29003_NUM_CACHABLE_REGS 4 + +struct isl29003_data { + struct i2c_client *client; + struct mutex lock; + u8 reg_cache[ISL29003_NUM_CACHABLE_REGS]; +}; + +static int gain_range[] = { + 1000, 4000, 16000, 64000 +}; + +/* + * register access helpers + */ + +static int __isl29003_read_reg(struct i2c_client *client, + u32 reg, u8 mask, u8 shift) +{ + struct isl29003_data *data = i2c_get_clientdata(client); + return (data->reg_cache[reg] & mask) >> shift; +} + +static int __isl29003_write_reg(struct i2c_client *client, + u32 reg, u8 mask, u8 shift, u8 val) +{ + struct isl29003_data *data = i2c_get_clientdata(client); + int ret = 0; + u8 tmp; + + if (reg >= ISL29003_NUM_CACHABLE_REGS) + return -EINVAL; + + mutex_lock(&data->lock); + + tmp = data->reg_cache[reg]; + tmp &= ~mask; + tmp |= val << shift; + + ret = i2c_smbus_write_byte_data(client, reg, tmp); + if (!ret) + data->reg_cache[reg] = tmp; + + mutex_unlock(&data->lock); + return ret; +} + +/* + * internally used functions + */ + +/* range */ +static int isl29003_get_range(struct i2c_client *client) +{ + return __isl29003_read_reg(client, ISL29003_REG_CONTROL, + ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT); +} + +static int isl29003_set_range(struct i2c_client *client, int range) +{ + return __isl29003_write_reg(client, ISL29003_REG_CONTROL, + ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT, range); +} + +/* resolution */ +static int isl29003_get_resolution(struct i2c_client *client) +{ + return __isl29003_read_reg(client, ISL29003_REG_COMMAND, + ISL29003_RES_MASK, ISL29003_RES_SHIFT); +} + +static int isl29003_set_resolution(struct i2c_client *client, int res) +{ + return __isl29003_write_reg(client, ISL29003_REG_COMMAND, + ISL29003_RES_MASK, ISL29003_RES_SHIFT, res); +} + +/* mode */ +static int isl29003_get_mode(struct i2c_client *client) +{ + return __isl29003_read_reg(client, ISL29003_REG_COMMAND, + ISL29003_RES_MASK, ISL29003_RES_SHIFT); +} + +static int isl29003_set_mode(struct i2c_client *client, int mode) +{ + return __isl29003_write_reg(client, ISL29003_REG_COMMAND, + ISL29003_RES_MASK, ISL29003_RES_SHIFT, mode); +} + +/* power_state */ +static int isl29003_set_power_state(struct i2c_client *client, int state) +{ + return __isl29003_write_reg(client, ISL29003_REG_COMMAND, + ISL29003_ADC_ENABLED | ISL29003_ADC_PD, 0, + state ? ISL29003_ADC_ENABLED : ISL29003_ADC_PD); +} + +static int isl29003_get_power_state(struct i2c_client *client) +{ + struct isl29003_data *data = i2c_get_clientdata(client); + u8 cmdreg = data->reg_cache[ISL29003_REG_COMMAND]; + return ~cmdreg & ISL29003_ADC_PD; +} + +static int isl29003_get_adc_value(struct i2c_client *client) +{ + struct isl29003_data *data = i2c_get_clientdata(client); + int lsb, msb, range, bitdepth; + + mutex_lock(&data->lock); + lsb = i2c_smbus_read_byte_data(client, ISL29003_REG_LSB_SENSOR); + + if (lsb < 0) { + mutex_unlock(&data->lock); + return lsb; + } + + msb = i2c_smbus_read_byte_data(client, ISL29003_REG_MSB_SENSOR); + mutex_unlock(&data->lock); + + if (msb < 0) + return msb; + + range = isl29003_get_range(client); + bitdepth = (4 - isl29003_get_resolution(client)) * 4; + return (((msb << 8) | lsb) * gain_range[range]) >> bitdepth; +} + +/* + * sysfs layer + */ + +/* range */ +static ssize_t isl29003_show_range(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%i\n", isl29003_get_range(client)); +} + +static ssize_t isl29003_store_range(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long val; + int ret; + + if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3)) + return -EINVAL; + + ret = isl29003_set_range(client, val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(range, S_IWUSR | S_IRUGO, + isl29003_show_range, isl29003_store_range); + + +/* resolution */ +static ssize_t isl29003_show_resolution(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%d\n", isl29003_get_resolution(client)); +} + +static ssize_t isl29003_store_resolution(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long val; + int ret; + + if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3)) + return -EINVAL; + + ret = isl29003_set_resolution(client, val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO, + isl29003_show_resolution, isl29003_store_resolution); + +/* mode */ +static ssize_t isl29003_show_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%d\n", isl29003_get_mode(client)); +} + +static ssize_t isl29003_store_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long val; + int ret; + + if ((strict_strtoul(buf, 10, &val) < 0) || (val > 2)) + return -EINVAL; + + ret = isl29003_set_mode(client, val); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, + isl29003_show_mode, isl29003_store_mode); + + +/* power state */ +static ssize_t isl29003_show_power_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%d\n", isl29003_get_power_state(client)); +} + +static ssize_t isl29003_store_power_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + unsigned long val; + int ret; + + if ((strict_strtoul(buf, 10, &val) < 0) || (val > 1)) + return -EINVAL; + + ret = isl29003_set_power_state(client, val); + return ret ? ret : count; +} + +static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, + isl29003_show_power_state, isl29003_store_power_state); + + +/* lux */ +static ssize_t isl29003_show_lux(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + + /* No LUX data if not operational */ + if (!isl29003_get_power_state(client)) + return -EBUSY; + + return sprintf(buf, "%d\n", isl29003_get_adc_value(client)); +} + +static DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL); + +static struct attribute *isl29003_attributes[] = { + &dev_attr_range.attr, + &dev_attr_resolution.attr, + &dev_attr_mode.attr, + &dev_attr_power_state.attr, + &dev_attr_lux.attr, + NULL +}; + +static const struct attribute_group isl29003_attr_group = { + .attrs = isl29003_attributes, +}; + +static int isl29003_init_client(struct i2c_client *client) +{ + struct isl29003_data *data = i2c_get_clientdata(client); + int i; + + /* read all the registers once to fill the cache. + * if one of the reads fails, we consider the init failed */ + for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) { + int v = i2c_smbus_read_byte_data(client, i); + if (v < 0) + return -ENODEV; + + data->reg_cache[i] = v; + } + + /* set defaults */ + isl29003_set_range(client, 0); + isl29003_set_resolution(client, 0); + isl29003_set_mode(client, 0); + isl29003_set_power_state(client, 0); + + return 0; +} + +/* + * I2C layer + */ + +static int __devinit isl29003_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct isl29003_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + return -EIO; + + data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->lock); + + /* initialize the ISL29003 chip */ + err = isl29003_init_client(client); + if (err) + goto exit_kfree; + + /* register sysfs hooks */ + err = sysfs_create_group(&client->dev.kobj, &isl29003_attr_group); + if (err) + goto exit_kfree; + + dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION); + return 0; + +exit_kfree: + kfree(data); + return err; +} + +static int __devexit isl29003_remove(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group); + isl29003_set_power_state(client, 0); + kfree(i2c_get_clientdata(client)); + return 0; +} + +#ifdef CONFIG_PM +static int isl29003_suspend(struct i2c_client *client, pm_message_t mesg) +{ + return isl29003_set_power_state(client, 0); +} + +static int isl29003_resume(struct i2c_client *client) +{ + int i; + struct isl29003_data *data = i2c_get_clientdata(client); + + /* restore registers from cache */ + for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) + if (!i2c_smbus_write_byte_data(client, i, data->reg_cache[i])) + return -EIO; + + return 0; +} + +#else +#define isl29003_suspend NULL +#define isl29003_resume NULL +#endif /* CONFIG_PM */ + +static const struct i2c_device_id isl29003_id[] = { + { "isl29003", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, isl29003_id); + +static struct i2c_driver isl29003_driver = { + .driver = { + .name = ISL29003_DRV_NAME, + .owner = THIS_MODULE, + }, + .suspend = isl29003_suspend, + .resume = isl29003_resume, + .probe = isl29003_probe, + .remove = __devexit_p(isl29003_remove), + .id_table = isl29003_id, +}; + +static int __init isl29003_init(void) +{ + return i2c_add_driver(&isl29003_driver); +} + +static void __exit isl29003_exit(void) +{ + i2c_del_driver(&isl29003_driver); +} + +MODULE_AUTHOR("Daniel Mack "); +MODULE_DESCRIPTION("ISL29003 ambient light sensor driver"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DRIVER_VERSION); + +module_init(isl29003_init); +module_exit(isl29003_exit); + diff --git a/trunk/drivers/misc/sgi-gru/Makefile b/trunk/drivers/misc/sgi-gru/Makefile index 9e9170b3599a..bcd8136d2f98 100644 --- a/trunk/drivers/misc/sgi-gru/Makefile +++ b/trunk/drivers/misc/sgi-gru/Makefile @@ -3,5 +3,5 @@ ifdef CONFIG_SGI_GRU_DEBUG endif obj-$(CONFIG_SGI_GRU) := gru.o -gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o +gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o diff --git a/trunk/drivers/misc/sgi-gru/gru_instructions.h b/trunk/drivers/misc/sgi-gru/gru_instructions.h index 48762e7b98be..3fde33c1e8f3 100644 --- a/trunk/drivers/misc/sgi-gru/gru_instructions.h +++ b/trunk/drivers/misc/sgi-gru/gru_instructions.h @@ -19,8 +19,11 @@ #ifndef __GRU_INSTRUCTIONS_H__ #define __GRU_INSTRUCTIONS_H__ -#define gru_flush_cache_hook(p) -#define gru_emulator_wait_hook(p, w) +extern int gru_check_status_proc(void *cb); +extern int gru_wait_proc(void *cb); +extern void gru_wait_abort_proc(void *cb); + + /* * Architecture dependent functions @@ -29,16 +32,16 @@ #if defined(CONFIG_IA64) #include #include -#define __flush_cache(p) ia64_fc(p) +#define __flush_cache(p) ia64_fc((unsigned long)p) /* Use volatile on IA64 to ensure ordering via st4.rel */ -#define gru_ordered_store_int(p,v) \ +#define gru_ordered_store_int(p, v) \ do { \ barrier(); \ *((volatile int *)(p)) = v; /* force st.rel */ \ } while (0) #elif defined(CONFIG_X86_64) #define __flush_cache(p) clflush(p) -#define gru_ordered_store_int(p,v) \ +#define gru_ordered_store_int(p, v) \ do { \ barrier(); \ *(int *)p = v; \ @@ -558,20 +561,19 @@ extern int gru_get_cb_exception_detail(void *cb, #define GRU_EXC_STR_SIZE 256 -extern int gru_check_status_proc(void *cb); -extern int gru_wait_proc(void *cb); -extern void gru_wait_abort_proc(void *cb); /* * Control block definition for checking status */ struct gru_control_block_status { unsigned int icmd :1; - unsigned int unused1 :31; + unsigned int ima :3; + unsigned int reserved0 :4; + unsigned int unused1 :24; unsigned int unused2 :24; unsigned int istatus :2; unsigned int isubstatus :4; - unsigned int inused3 :2; + unsigned int unused3 :2; }; /* Get CB status */ diff --git a/trunk/drivers/misc/sgi-gru/grufault.c b/trunk/drivers/misc/sgi-gru/grufault.c index 3ee698ad8599..ab118558552e 100644 --- a/trunk/drivers/misc/sgi-gru/grufault.c +++ b/trunk/drivers/misc/sgi-gru/grufault.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "gru.h" #include "grutables.h" @@ -266,6 +267,44 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr, return 1; } +static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr, + int write, int atomic, unsigned long *gpa, int *pageshift) +{ + struct mm_struct *mm = gts->ts_mm; + struct vm_area_struct *vma; + unsigned long paddr; + int ret, ps; + + vma = find_vma(mm, vaddr); + if (!vma) + goto inval; + + /* + * Atomic lookup is faster & usually works even if called in non-atomic + * context. + */ + rmb(); /* Must/check ms_range_active before loading PTEs */ + ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &ps); + if (ret) { + if (atomic) + goto upm; + if (non_atomic_pte_lookup(vma, vaddr, write, &paddr, &ps)) + goto inval; + } + if (is_gru_paddr(paddr)) + goto inval; + paddr = paddr & ~((1UL << ps) - 1); + *gpa = uv_soc_phys_ram_to_gpa(paddr); + *pageshift = ps; + return 0; + +inval: + return -1; +upm: + return -2; +} + + /* * Drop a TLB entry into the GRU. The fault is described by info in an TFH. * Input: @@ -280,10 +319,8 @@ static int gru_try_dropin(struct gru_thread_state *gts, struct gru_tlb_fault_handle *tfh, unsigned long __user *cb) { - struct mm_struct *mm = gts->ts_mm; - struct vm_area_struct *vma; - int pageshift, asid, write, ret; - unsigned long paddr, gpa, vaddr; + int pageshift = 0, asid, write, ret, atomic = !cb; + unsigned long gpa = 0, vaddr = 0; /* * NOTE: The GRU contains magic hardware that eliminates races between @@ -317,28 +354,19 @@ static int gru_try_dropin(struct gru_thread_state *gts, if (atomic_read(>s->ts_gms->ms_range_active)) goto failactive; - vma = find_vma(mm, vaddr); - if (!vma) + ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift); + if (ret == -1) goto failinval; + if (ret == -2) + goto failupm; - /* - * Atomic lookup is faster & usually works even if called in non-atomic - * context. - */ - rmb(); /* Must/check ms_range_active before loading PTEs */ - ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &pageshift); - if (ret) { - if (!cb) + if (!(gts->ts_sizeavail & GRU_SIZEAVAIL(pageshift))) { + gts->ts_sizeavail |= GRU_SIZEAVAIL(pageshift); + if (atomic || !gru_update_cch(gts, 0)) { + gts->ts_force_cch_reload = 1; goto failupm; - if (non_atomic_pte_lookup(vma, vaddr, write, &paddr, - &pageshift)) - goto failinval; + } } - if (is_gru_paddr(paddr)) - goto failinval; - - paddr = paddr & ~((1UL << pageshift) - 1); - gpa = uv_soc_phys_ram_to_gpa(paddr); gru_cb_set_istatus_active(cb); tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, GRU_PAGESIZE(pageshift)); @@ -368,6 +396,7 @@ static int gru_try_dropin(struct gru_thread_state *gts, failfmm: /* FMM state on UPM call */ + gru_flush_cache(tfh); STAT(tlb_dropin_fail_fmm); gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state); return 0; @@ -448,6 +477,7 @@ irqreturn_t gru_intr(int irq, void *dev_id) up_read(>s->ts_mm->mmap_sem); } else { tfh_user_polling_mode(tfh); + STAT(intr_mm_lock_failed); } } return IRQ_HANDLED; @@ -497,10 +527,8 @@ int gru_handle_user_call_os(unsigned long cb) if (!gts) return -EINVAL; - if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) { - ret = -EINVAL; + if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) goto exit; - } /* * If force_unload is set, the UPM TLB fault is phony. The task @@ -508,6 +536,20 @@ int gru_handle_user_call_os(unsigned long cb) * unload the context. The task will page fault and assign a new * context. */ + if (gts->ts_tgid_owner == current->tgid && gts->ts_blade >= 0 && + gts->ts_blade != uv_numa_blade_id()) { + STAT(call_os_offnode_reference); + gts->ts_force_unload = 1; + } + + /* + * CCH may contain stale data if ts_force_cch_reload is set. + */ + if (gts->ts_gru && gts->ts_force_cch_reload) { + gru_update_cch(gts, 0); + gts->ts_force_cch_reload = 0; + } + ret = -EAGAIN; cbrnum = thread_cbr_number(gts, ucbnum); if (gts->ts_force_unload) { @@ -541,11 +583,13 @@ int gru_get_exception_detail(unsigned long arg) if (!gts) return -EINVAL; - if (gts->ts_gru) { - ucbnum = get_cb_number((void *)excdet.cb); + ucbnum = get_cb_number((void *)excdet.cb); + if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) { + ret = -EINVAL; + } else if (gts->ts_gru) { cbrnum = thread_cbr_number(gts, ucbnum); cbe = get_cbe_by_index(gts->ts_gru, cbrnum); - prefetchw(cbe); /* Harmless on hardware, required for emulator */ + prefetchw(cbe);/* Harmless on hardware, required for emulator */ excdet.opc = cbe->opccpy; excdet.exopc = cbe->exopccpy; excdet.ecause = cbe->ecause; @@ -567,6 +611,31 @@ int gru_get_exception_detail(unsigned long arg) /* * User request to unload a context. Content is saved for possible reload. */ +static int gru_unload_all_contexts(void) +{ + struct gru_thread_state *gts; + struct gru_state *gru; + int gid, ctxnum; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + foreach_gid(gid) { + gru = GID_TO_GRU(gid); + spin_lock(&gru->gs_lock); + for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) { + gts = gru->gs_gts[ctxnum]; + if (gts && mutex_trylock(>s->ts_ctxlock)) { + spin_unlock(&gru->gs_lock); + gru_unload_context(gts, 1); + gru_unlock_gts(gts); + spin_lock(&gru->gs_lock); + } + } + spin_unlock(&gru->gs_lock); + } + return 0; +} + int gru_user_unload_context(unsigned long arg) { struct gru_thread_state *gts; @@ -578,6 +647,9 @@ int gru_user_unload_context(unsigned long arg) gru_dbg(grudev, "gseg 0x%lx\n", req.gseg); + if (!req.gseg) + return gru_unload_all_contexts(); + gts = gru_find_lock_gts(req.gseg); if (!gts) return -EINVAL; @@ -609,7 +681,7 @@ int gru_user_flush_tlb(unsigned long arg) if (!gts) return -EINVAL; - gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.vaddr + req.len); + gru_flush_tlb_range(gts->ts_gms, req.vaddr, req.len); gru_unlock_gts(gts); return 0; diff --git a/trunk/drivers/misc/sgi-gru/grufile.c b/trunk/drivers/misc/sgi-gru/grufile.c index c67e4e8bd62c..3e6e42d2f01b 100644 --- a/trunk/drivers/misc/sgi-gru/grufile.c +++ b/trunk/drivers/misc/sgi-gru/grufile.c @@ -45,7 +45,9 @@ #include struct gru_blade_state *gru_base[GRU_MAX_BLADES] __read_mostly; -unsigned long gru_start_paddr, gru_end_paddr __read_mostly; +unsigned long gru_start_paddr __read_mostly; +unsigned long gru_end_paddr __read_mostly; +unsigned int gru_max_gids __read_mostly; struct gru_stats_s gru_stats; /* Guaranteed user available resources on each node */ @@ -101,7 +103,7 @@ static int gru_file_mmap(struct file *file, struct vm_area_struct *vma) return -EPERM; if (vma->vm_start & (GRU_GSEG_PAGESIZE - 1) || - vma->vm_end & (GRU_GSEG_PAGESIZE - 1)) + vma->vm_end & (GRU_GSEG_PAGESIZE - 1)) return -EINVAL; vma->vm_flags |= @@ -273,8 +275,11 @@ static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr, gru->gs_blade_id = bid; gru->gs_cbr_map = (GRU_CBR_AU == 64) ? ~0 : (1UL << GRU_CBR_AU) - 1; gru->gs_dsr_map = (1UL << GRU_DSR_AU) - 1; + gru->gs_asid_limit = MAX_ASID; gru_tgh_flush_init(gru); - gru_dbg(grudev, "bid %d, nid %d, gru %x, vaddr %p (0x%lx)\n", + if (gru->gs_gid >= gru_max_gids) + gru_max_gids = gru->gs_gid + 1; + gru_dbg(grudev, "bid %d, nid %d, gid %d, vaddr %p (0x%lx)\n", bid, nid, gru->gs_gid, gru->gs_gru_base_vaddr, gru->gs_gru_base_paddr); gru_kservices_init(gru); @@ -295,7 +300,7 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) for_each_online_node(nid) { bid = uv_node_to_blade_id(nid); pnode = uv_node_to_pnode(nid); - if (gru_base[bid]) + if (bid < 0 || gru_base[bid]) continue; page = alloc_pages_node(nid, GFP_KERNEL, order); if (!page) @@ -308,11 +313,11 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) dsrbytes = 0; cbrs = 0; for (gru = gru_base[bid]->bs_grus, chip = 0; - chip < GRU_CHIPLETS_PER_BLADE; + chip < GRU_CHIPLETS_PER_BLADE; chip++, gru++) { paddr = gru_chiplet_paddr(gru_base_paddr, pnode, chip); vaddr = gru_chiplet_vaddr(gru_base_vaddr, pnode, chip); - gru_init_chiplet(gru, paddr, vaddr, bid, nid, chip); + gru_init_chiplet(gru, paddr, vaddr, nid, bid, chip); n = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE; cbrs = max(cbrs, n); n = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES; @@ -370,26 +375,26 @@ static int __init gru_init(void) void *gru_start_vaddr; if (!is_uv_system()) - return 0; + return -ENODEV; #if defined CONFIG_IA64 gru_start_paddr = 0xd000000000UL; /* ZZZZZZZZZZZZZZZZZZZ fixme */ #else gru_start_paddr = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR) & 0x7fffffffffffUL; - #endif gru_start_vaddr = __va(gru_start_paddr); - gru_end_paddr = gru_start_paddr + MAX_NUMNODES * GRU_SIZE; + gru_end_paddr = gru_start_paddr + GRU_MAX_BLADES * GRU_SIZE; printk(KERN_INFO "GRU space: 0x%lx - 0x%lx\n", gru_start_paddr, gru_end_paddr); irq = get_base_irq(); for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) { ret = request_irq(irq + chip, gru_intr, 0, id, NULL); - /* TODO: fix irq handling on x86. For now ignore failures because + /* TODO: fix irq handling on x86. For now ignore failure because * interrupts are not required & not yet fully supported */ if (ret) { - printk("!!!WARNING: GRU ignoring request failure!!!\n"); + printk(KERN_WARNING + "!!!WARNING: GRU ignoring request failure!!!\n"); ret = 0; } if (ret) { @@ -435,7 +440,7 @@ static int __init gru_init(void) static void __exit gru_exit(void) { - int i, bid; + int i, bid, gid; int order = get_order(sizeof(struct gru_state) * GRU_CHIPLETS_PER_BLADE); @@ -445,6 +450,9 @@ static void __exit gru_exit(void) for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++) free_irq(IRQ_GRU + i, NULL); + foreach_gid(gid) + gru_kservices_exit(GID_TO_GRU(gid)); + for (bid = 0; bid < GRU_MAX_BLADES; bid++) free_pages((unsigned long)gru_base[bid], order); @@ -469,7 +477,11 @@ struct vm_operations_struct gru_vm_ops = { .fault = gru_fault, }; +#ifndef MODULE fs_initcall(gru_init); +#else +module_init(gru_init); +#endif module_exit(gru_exit); module_param(gru_options, ulong, 0644); diff --git a/trunk/drivers/misc/sgi-gru/gruhandles.c b/trunk/drivers/misc/sgi-gru/gruhandles.c new file mode 100644 index 000000000000..9b7ccb328697 --- /dev/null +++ b/trunk/drivers/misc/sgi-gru/gruhandles.c @@ -0,0 +1,183 @@ +/* + * GRU KERNEL MCS INSTRUCTIONS + * + * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "gru.h" +#include "grulib.h" +#include "grutables.h" + +/* 10 sec */ +#ifdef CONFIG_IA64 +#include +#define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10) +#else +#include +#define GRU_OPERATION_TIMEOUT ((cycles_t) tsc_khz*10*1000) +#endif + +/* Extract the status field from a kernel handle */ +#define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3) + +struct mcs_op_statistic mcs_op_statistics[mcsop_last]; + +static void update_mcs_stats(enum mcs_op op, unsigned long clks) +{ + atomic_long_inc(&mcs_op_statistics[op].count); + atomic_long_add(clks, &mcs_op_statistics[op].total); + if (mcs_op_statistics[op].max < clks) + mcs_op_statistics[op].max = clks; +} + +static void start_instruction(void *h) +{ + unsigned long *w0 = h; + + wmb(); /* setting CMD bit must be last */ + *w0 = *w0 | 1; + gru_flush_cache(h); +} + +static int wait_instruction_complete(void *h, enum mcs_op opc) +{ + int status; + cycles_t start_time = get_cycles(); + + while (1) { + cpu_relax(); + status = GET_MSEG_HANDLE_STATUS(h); + if (status != CCHSTATUS_ACTIVE) + break; + if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) + panic("GRU %p is malfunctioning\n", h); + } + if (gru_options & OPT_STATS) + update_mcs_stats(opc, get_cycles() - start_time); + return status; +} + +int cch_allocate(struct gru_context_configuration_handle *cch, + int asidval, int sizeavail, unsigned long cbrmap, + unsigned long dsrmap) +{ + int i; + + for (i = 0; i < 8; i++) { + cch->asid[i] = (asidval++); + cch->sizeavail[i] = sizeavail; + } + cch->dsr_allocation_map = dsrmap; + cch->cbr_allocation_map = cbrmap; + cch->opc = CCHOP_ALLOCATE; + start_instruction(cch); + return wait_instruction_complete(cch, cchop_allocate); +} + +int cch_start(struct gru_context_configuration_handle *cch) +{ + cch->opc = CCHOP_START; + start_instruction(cch); + return wait_instruction_complete(cch, cchop_start); +} + +int cch_interrupt(struct gru_context_configuration_handle *cch) +{ + cch->opc = CCHOP_INTERRUPT; + start_instruction(cch); + return wait_instruction_complete(cch, cchop_interrupt); +} + +int cch_deallocate(struct gru_context_configuration_handle *cch) +{ + cch->opc = CCHOP_DEALLOCATE; + start_instruction(cch); + return wait_instruction_complete(cch, cchop_deallocate); +} + +int cch_interrupt_sync(struct gru_context_configuration_handle + *cch) +{ + cch->opc = CCHOP_INTERRUPT_SYNC; + start_instruction(cch); + return wait_instruction_complete(cch, cchop_interrupt_sync); +} + +int tgh_invalidate(struct gru_tlb_global_handle *tgh, + unsigned long vaddr, unsigned long vaddrmask, + int asid, int pagesize, int global, int n, + unsigned short ctxbitmap) +{ + tgh->vaddr = vaddr; + tgh->asid = asid; + tgh->pagesize = pagesize; + tgh->n = n; + tgh->global = global; + tgh->vaddrmask = vaddrmask; + tgh->ctxbitmap = ctxbitmap; + tgh->opc = TGHOP_TLBINV; + start_instruction(tgh); + return wait_instruction_complete(tgh, tghop_invalidate); +} + +void tfh_write_only(struct gru_tlb_fault_handle *tfh, + unsigned long pfn, unsigned long vaddr, + int asid, int dirty, int pagesize) +{ + tfh->fillasid = asid; + tfh->fillvaddr = vaddr; + tfh->pfn = pfn; + tfh->dirty = dirty; + tfh->pagesize = pagesize; + tfh->opc = TFHOP_WRITE_ONLY; + start_instruction(tfh); +} + +void tfh_write_restart(struct gru_tlb_fault_handle *tfh, + unsigned long paddr, int gaa, + unsigned long vaddr, int asid, int dirty, + int pagesize) +{ + tfh->fillasid = asid; + tfh->fillvaddr = vaddr; + tfh->pfn = paddr >> GRU_PADDR_SHIFT; + tfh->gaa = gaa; + tfh->dirty = dirty; + tfh->pagesize = pagesize; + tfh->opc = TFHOP_WRITE_RESTART; + start_instruction(tfh); +} + +void tfh_restart(struct gru_tlb_fault_handle *tfh) +{ + tfh->opc = TFHOP_RESTART; + start_instruction(tfh); +} + +void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh) +{ + tfh->opc = TFHOP_USER_POLLING_MODE; + start_instruction(tfh); +} + +void tfh_exception(struct gru_tlb_fault_handle *tfh) +{ + tfh->opc = TFHOP_EXCEPTION; + start_instruction(tfh); +} + diff --git a/trunk/drivers/misc/sgi-gru/gruhandles.h b/trunk/drivers/misc/sgi-gru/gruhandles.h index b63018d60fe1..1ed74d7508c8 100644 --- a/trunk/drivers/misc/sgi-gru/gruhandles.h +++ b/trunk/drivers/misc/sgi-gru/gruhandles.h @@ -489,170 +489,28 @@ enum gru_cbr_state { * 64m 26 8 * ... */ -#define GRU_PAGESIZE(sh) ((((sh) > 20 ? (sh) + 2: (sh)) >> 1) - 6) +#define GRU_PAGESIZE(sh) ((((sh) > 20 ? (sh) + 2 : (sh)) >> 1) - 6) #define GRU_SIZEAVAIL(sh) (1UL << GRU_PAGESIZE(sh)) /* minimum TLB purge count to ensure a full purge */ #define GRUMAXINVAL 1024UL - -/* Extract the status field from a kernel handle */ -#define GET_MSEG_HANDLE_STATUS(h) (((*(unsigned long *)(h)) >> 16) & 3) - -static inline void start_instruction(void *h) -{ - unsigned long *w0 = h; - - wmb(); /* setting CMD bit must be last */ - *w0 = *w0 | 1; - gru_flush_cache(h); -} - -static inline int wait_instruction_complete(void *h) -{ - int status; - - do { - cpu_relax(); - barrier(); - status = GET_MSEG_HANDLE_STATUS(h); - } while (status == CCHSTATUS_ACTIVE); - return status; -} - -#if defined CONFIG_IA64 -static inline void cch_allocate_set_asids( - struct gru_context_configuration_handle *cch, int asidval) -{ - int i; - - for (i = 0; i <= RGN_HPAGE; i++) { /* assume HPAGE is last region */ - cch->asid[i] = (asidval++); -#if 0 - /* ZZZ hugepages not supported yet */ - if (i == RGN_HPAGE) - cch->sizeavail[i] = GRU_SIZEAVAIL(hpage_shift); - else -#endif - cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT); - } -} -#elif defined CONFIG_X86_64 -static inline void cch_allocate_set_asids( - struct gru_context_configuration_handle *cch, int asidval) -{ - int i; - - for (i = 0; i < 8; i++) { - cch->asid[i] = asidval++; - cch->sizeavail[i] = GRU_SIZEAVAIL(PAGE_SHIFT) | - GRU_SIZEAVAIL(21); - } -} -#endif - -static inline int cch_allocate(struct gru_context_configuration_handle *cch, - int asidval, unsigned long cbrmap, - unsigned long dsrmap) -{ - cch_allocate_set_asids(cch, asidval); - cch->dsr_allocation_map = dsrmap; - cch->cbr_allocation_map = cbrmap; - cch->opc = CCHOP_ALLOCATE; - start_instruction(cch); - return wait_instruction_complete(cch); -} - -static inline int cch_start(struct gru_context_configuration_handle *cch) -{ - cch->opc = CCHOP_START; - start_instruction(cch); - return wait_instruction_complete(cch); -} - -static inline int cch_interrupt(struct gru_context_configuration_handle *cch) -{ - cch->opc = CCHOP_INTERRUPT; - start_instruction(cch); - return wait_instruction_complete(cch); -} - -static inline int cch_deallocate(struct gru_context_configuration_handle *cch) -{ - cch->opc = CCHOP_DEALLOCATE; - start_instruction(cch); - return wait_instruction_complete(cch); -} - -static inline int cch_interrupt_sync(struct gru_context_configuration_handle - *cch) -{ - cch->opc = CCHOP_INTERRUPT_SYNC; - start_instruction(cch); - return wait_instruction_complete(cch); -} - -static inline int tgh_invalidate(struct gru_tlb_global_handle *tgh, - unsigned long vaddr, unsigned long vaddrmask, - int asid, int pagesize, int global, int n, - unsigned short ctxbitmap) -{ - tgh->vaddr = vaddr; - tgh->asid = asid; - tgh->pagesize = pagesize; - tgh->n = n; - tgh->global = global; - tgh->vaddrmask = vaddrmask; - tgh->ctxbitmap = ctxbitmap; - tgh->opc = TGHOP_TLBINV; - start_instruction(tgh); - return wait_instruction_complete(tgh); -} - -static inline void tfh_write_only(struct gru_tlb_fault_handle *tfh, - unsigned long pfn, unsigned long vaddr, - int asid, int dirty, int pagesize) -{ - tfh->fillasid = asid; - tfh->fillvaddr = vaddr; - tfh->pfn = pfn; - tfh->dirty = dirty; - tfh->pagesize = pagesize; - tfh->opc = TFHOP_WRITE_ONLY; - start_instruction(tfh); -} - -static inline void tfh_write_restart(struct gru_tlb_fault_handle *tfh, - unsigned long paddr, int gaa, - unsigned long vaddr, int asid, int dirty, - int pagesize) -{ - tfh->fillasid = asid; - tfh->fillvaddr = vaddr; - tfh->pfn = paddr >> GRU_PADDR_SHIFT; - tfh->gaa = gaa; - tfh->dirty = dirty; - tfh->pagesize = pagesize; - tfh->opc = TFHOP_WRITE_RESTART; - start_instruction(tfh); -} - -static inline void tfh_restart(struct gru_tlb_fault_handle *tfh) -{ - tfh->opc = TFHOP_RESTART; - start_instruction(tfh); -} - -static inline void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh) -{ - tfh->opc = TFHOP_USER_POLLING_MODE; - start_instruction(tfh); -} - -static inline void tfh_exception(struct gru_tlb_fault_handle *tfh) -{ - tfh->opc = TFHOP_EXCEPTION; - start_instruction(tfh); -} +int cch_allocate(struct gru_context_configuration_handle *cch, + int asidval, int sizeavail, unsigned long cbrmap, unsigned long dsrmap); + +int cch_start(struct gru_context_configuration_handle *cch); +int cch_interrupt(struct gru_context_configuration_handle *cch); +int cch_deallocate(struct gru_context_configuration_handle *cch); +int cch_interrupt_sync(struct gru_context_configuration_handle *cch); +int tgh_invalidate(struct gru_tlb_global_handle *tgh, unsigned long vaddr, + unsigned long vaddrmask, int asid, int pagesize, int global, int n, + unsigned short ctxbitmap); +void tfh_write_only(struct gru_tlb_fault_handle *tfh, unsigned long pfn, + unsigned long vaddr, int asid, int dirty, int pagesize); +void tfh_write_restart(struct gru_tlb_fault_handle *tfh, unsigned long paddr, + int gaa, unsigned long vaddr, int asid, int dirty, int pagesize); +void tfh_restart(struct gru_tlb_fault_handle *tfh); +void tfh_user_polling_mode(struct gru_tlb_fault_handle *tfh); +void tfh_exception(struct gru_tlb_fault_handle *tfh); #endif /* __GRUHANDLES_H__ */ diff --git a/trunk/drivers/misc/sgi-gru/grukservices.c b/trunk/drivers/misc/sgi-gru/grukservices.c index 880c55dfb662..d8bd7d84a7cf 100644 --- a/trunk/drivers/misc/sgi-gru/grukservices.c +++ b/trunk/drivers/misc/sgi-gru/grukservices.c @@ -52,8 +52,10 @@ */ /* Blade percpu resources PERMANENTLY reserved for kernel use */ -#define GRU_NUM_KERNEL_CBR 1 +#define GRU_NUM_KERNEL_CBR 1 #define GRU_NUM_KERNEL_DSR_BYTES 256 +#define GRU_NUM_KERNEL_DSR_CL (GRU_NUM_KERNEL_DSR_BYTES / \ + GRU_CACHE_LINE_BYTES) #define KERNEL_CTXNUM 15 /* GRU instruction attributes for all instructions */ @@ -94,7 +96,6 @@ struct message_header { char fill; }; -#define QLINES(mq) ((mq) + offsetof(struct message_queue, qlines)) #define HSTATUS(mq, h) ((mq) + offsetof(struct message_queue, hstatus[h])) static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr) @@ -122,7 +123,7 @@ int gru_get_cb_exception_detail(void *cb, struct gru_control_block_extended *cbe; cbe = get_cbe(GRUBASE(cb), get_cb_number(cb)); - prefetchw(cbe); /* Harmless on hardware, required for emulator */ + prefetchw(cbe); /* Harmless on hardware, required for emulator */ excdet->opc = cbe->opccpy; excdet->exopc = cbe->exopccpy; excdet->ecause = cbe->ecause; @@ -250,7 +251,8 @@ static inline void restore_present2(void *p, int val) * Create a message queue. * qlines - message queue size in cache lines. Includes 2-line header. */ -int gru_create_message_queue(void *p, unsigned int bytes) +int gru_create_message_queue(struct gru_message_queue_desc *mqd, + void *p, unsigned int bytes, int nasid, int vector, int apicid) { struct message_queue *mq = p; unsigned int qlines; @@ -265,6 +267,12 @@ int gru_create_message_queue(void *p, unsigned int bytes) mq->hstatus[0] = 0; mq->hstatus[1] = 1; mq->head = gru_mesq_head(2, qlines / 2 + 1); + mqd->mq = mq; + mqd->mq_gpa = uv_gpa(mq); + mqd->qlines = qlines; + mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid); + mqd->interrupt_vector = vector; + mqd->interrupt_apicid = apicid; return 0; } EXPORT_SYMBOL_GPL(gru_create_message_queue); @@ -277,8 +285,8 @@ EXPORT_SYMBOL_GPL(gru_create_message_queue); * -1 - if mesq sent successfully but queue not full * >0 - unexpected error. MQE_xxx returned */ -static int send_noop_message(void *cb, - unsigned long mq, void *mesg) +static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd, + void *mesg) { const struct message_header noop_header = { .present = MQS_NOOP, .lines = 1}; @@ -289,7 +297,7 @@ static int send_noop_message(void *cb, STAT(mesq_noop); save_mhdr = *mhdr; *mhdr = noop_header; - gru_mesq(cb, mq, gru_get_tri(mhdr), 1, IMA); + gru_mesq(cb, mqd->mq_gpa, gru_get_tri(mhdr), 1, IMA); ret = gru_wait(cb); if (ret) { @@ -313,7 +321,7 @@ static int send_noop_message(void *cb, break; case CBSS_PUT_NACKED: STAT(mesq_noop_put_nacked); - m = mq + (gru_get_amo_value_head(cb) << 6); + m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6); gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, 1, 1, IMA); if (gru_wait(cb) == CBS_IDLE) @@ -333,30 +341,20 @@ static int send_noop_message(void *cb, /* * Handle a gru_mesq full. */ -static int send_message_queue_full(void *cb, - unsigned long mq, void *mesg, int lines) +static int send_message_queue_full(void *cb, struct gru_message_queue_desc *mqd, + void *mesg, int lines) { union gru_mesqhead mqh; unsigned int limit, head; unsigned long avalue; - int half, qlines, save; + int half, qlines; /* Determine if switching to first/second half of q */ avalue = gru_get_amo_value(cb); head = gru_get_amo_value_head(cb); limit = gru_get_amo_value_limit(cb); - /* - * Fetch "qlines" from the queue header. Since the queue may be - * in memory that can't be accessed using socket addresses, use - * the GRU to access the data. Use DSR space from the message. - */ - save = *(int *)mesg; - gru_vload(cb, QLINES(mq), gru_get_tri(mesg), XTYPE_W, 1, 1, IMA); - if (gru_wait(cb) != CBS_IDLE) - goto cberr; - qlines = *(int *)mesg; - *(int *)mesg = save; + qlines = mqd->qlines; half = (limit != qlines); if (half) @@ -365,7 +363,7 @@ static int send_message_queue_full(void *cb, mqh = gru_mesq_head(2, qlines / 2 + 1); /* Try to get lock for switching head pointer */ - gru_gamir(cb, EOP_IR_CLR, HSTATUS(mq, half), XTYPE_DW, IMA); + gru_gamir(cb, EOP_IR_CLR, HSTATUS(mqd->mq_gpa, half), XTYPE_DW, IMA); if (gru_wait(cb) != CBS_IDLE) goto cberr; if (!gru_get_amo_value(cb)) { @@ -375,8 +373,8 @@ static int send_message_queue_full(void *cb, /* Got the lock. Send optional NOP if queue not full, */ if (head != limit) { - if (send_noop_message(cb, mq, mesg)) { - gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), + if (send_noop_message(cb, mqd, mesg)) { + gru_gamir(cb, EOP_IR_INC, HSTATUS(mqd->mq_gpa, half), XTYPE_DW, IMA); if (gru_wait(cb) != CBS_IDLE) goto cberr; @@ -387,14 +385,16 @@ static int send_message_queue_full(void *cb, } /* Then flip queuehead to other half of queue. */ - gru_gamer(cb, EOP_ERR_CSWAP, mq, XTYPE_DW, mqh.val, avalue, IMA); + gru_gamer(cb, EOP_ERR_CSWAP, mqd->mq_gpa, XTYPE_DW, mqh.val, avalue, + IMA); if (gru_wait(cb) != CBS_IDLE) goto cberr; /* If not successfully in swapping queue head, clear the hstatus lock */ if (gru_get_amo_value(cb) != avalue) { STAT(mesq_qf_switch_head_failed); - gru_gamir(cb, EOP_IR_INC, HSTATUS(mq, half), XTYPE_DW, IMA); + gru_gamir(cb, EOP_IR_INC, HSTATUS(mqd->mq_gpa, half), XTYPE_DW, + IMA); if (gru_wait(cb) != CBS_IDLE) goto cberr; } @@ -404,15 +404,25 @@ static int send_message_queue_full(void *cb, return MQE_UNEXPECTED_CB_ERR; } +/* + * Send a cross-partition interrupt to the SSI that contains the target + * message queue. Normally, the interrupt is automatically delivered by hardware + * but some error conditions require explicit delivery. + */ +static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd) +{ + if (mqd->interrupt_vector) + uv_hub_send_ipi(mqd->interrupt_pnode, mqd->interrupt_apicid, + mqd->interrupt_vector); +} + /* * Handle a gru_mesq failure. Some of these failures are software recoverable * or retryable. */ -static int send_message_failure(void *cb, - unsigned long mq, - void *mesg, - int lines) +static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd, + void *mesg, int lines) { int substatus, ret = 0; unsigned long m; @@ -429,7 +439,7 @@ static int send_message_failure(void *cb, break; case CBSS_QLIMIT_REACHED: STAT(mesq_send_qlimit_reached); - ret = send_message_queue_full(cb, mq, mesg, lines); + ret = send_message_queue_full(cb, mqd, mesg, lines); break; case CBSS_AMO_NACKED: STAT(mesq_send_amo_nacked); @@ -437,12 +447,14 @@ static int send_message_failure(void *cb, break; case CBSS_PUT_NACKED: STAT(mesq_send_put_nacked); - m =mq + (gru_get_amo_value_head(cb) << 6); + m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6); gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA); - if (gru_wait(cb) == CBS_IDLE) + if (gru_wait(cb) == CBS_IDLE) { ret = MQE_OK; - else + send_message_queue_interrupt(mqd); + } else { ret = MQE_UNEXPECTED_CB_ERR; + } break; default: BUG(); @@ -452,12 +464,12 @@ static int send_message_failure(void *cb, /* * Send a message to a message queue - * cb GRU control block to use to send message - * mq message queue + * mqd message queue descriptor * mesg message. ust be vaddr within a GSEG * bytes message size (<= 2 CL) */ -int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes) +int gru_send_message_gpa(struct gru_message_queue_desc *mqd, void *mesg, + unsigned int bytes) { struct message_header *mhdr; void *cb; @@ -481,10 +493,10 @@ int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes) do { ret = MQE_OK; - gru_mesq(cb, mq, gru_get_tri(mhdr), clines, IMA); + gru_mesq(cb, mqd->mq_gpa, gru_get_tri(mhdr), clines, IMA); istatus = gru_wait(cb); if (istatus != CBS_IDLE) - ret = send_message_failure(cb, mq, dsr, clines); + ret = send_message_failure(cb, mqd, dsr, clines); } while (ret == MQIE_AGAIN); gru_free_cpu_resources(cb, dsr); @@ -497,9 +509,9 @@ EXPORT_SYMBOL_GPL(gru_send_message_gpa); /* * Advance the receive pointer for the queue to the next message. */ -void gru_free_message(void *rmq, void *mesg) +void gru_free_message(struct gru_message_queue_desc *mqd, void *mesg) { - struct message_queue *mq = rmq; + struct message_queue *mq = mqd->mq; struct message_header *mhdr = mq->next; void *next, *pnext; int half = -1; @@ -529,16 +541,16 @@ EXPORT_SYMBOL_GPL(gru_free_message); * present. User must call next_message() to move to next message. * rmq message queue */ -void *gru_get_next_message(void *rmq) +void *gru_get_next_message(struct gru_message_queue_desc *mqd) { - struct message_queue *mq = rmq; + struct message_queue *mq = mqd->mq; struct message_header *mhdr = mq->next; int present = mhdr->present; /* skip NOOP messages */ STAT(mesq_receive); while (present == MQS_NOOP) { - gru_free_message(rmq, mhdr); + gru_free_message(mqd, mhdr); mhdr = mq->next; present = mhdr->present; } @@ -576,7 +588,7 @@ int gru_copy_gpa(unsigned long dest_gpa, unsigned long src_gpa, if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr)) return MQE_BUG_NO_RESOURCES; gru_bcopy(cb, src_gpa, dest_gpa, gru_get_tri(dsr), - XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_BYTES, IMA); + XTYPE_B, bytes, GRU_NUM_KERNEL_DSR_CL, IMA); ret = gru_wait(cb); gru_free_cpu_resources(cb, dsr); return ret; @@ -611,7 +623,7 @@ static int quicktest(struct gru_state *gru) if (word0 != word1 || word0 != MAGIC) { printk - ("GRU quicktest err: gru %d, found 0x%lx, expected 0x%lx\n", + ("GRU quicktest err: gid %d, found 0x%lx, expected 0x%lx\n", gru->gs_gid, word1, MAGIC); BUG(); /* ZZZ should not be fatal */ } @@ -660,15 +672,15 @@ int gru_kservices_init(struct gru_state *gru) cch->tlb_int_enable = 0; cch->tfm_done_bit_enable = 0; cch->unmap_enable = 1; - err = cch_allocate(cch, 0, cbr_map, dsr_map); + err = cch_allocate(cch, 0, 0, cbr_map, dsr_map); if (err) { gru_dbg(grudev, - "Unable to allocate kernel CCH: gru %d, err %d\n", + "Unable to allocate kernel CCH: gid %d, err %d\n", gru->gs_gid, err); BUG(); } if (cch_start(cch)) { - gru_dbg(grudev, "Unable to start kernel CCH: gru %d, err %d\n", + gru_dbg(grudev, "Unable to start kernel CCH: gid %d, err %d\n", gru->gs_gid, err); BUG(); } @@ -678,3 +690,22 @@ int gru_kservices_init(struct gru_state *gru) quicktest(gru); return 0; } + +void gru_kservices_exit(struct gru_state *gru) +{ + struct gru_context_configuration_handle *cch; + struct gru_blade_state *bs; + + bs = gru->gs_blade; + if (gru != &bs->bs_grus[1]) + return; + + cch = get_cch(gru->gs_gru_base_vaddr, KERNEL_CTXNUM); + lock_cch_handle(cch); + if (cch_interrupt_sync(cch)) + BUG(); + if (cch_deallocate(cch)) + BUG(); + unlock_cch_handle(cch); +} + diff --git a/trunk/drivers/misc/sgi-gru/grukservices.h b/trunk/drivers/misc/sgi-gru/grukservices.h index eb17e0a3ac61..747ed315d56f 100644 --- a/trunk/drivers/misc/sgi-gru/grukservices.h +++ b/trunk/drivers/misc/sgi-gru/grukservices.h @@ -41,6 +41,15 @@ * - gru_create_message_queue() needs interrupt vector info */ +struct gru_message_queue_desc { + void *mq; /* message queue vaddress */ + unsigned long mq_gpa; /* global address of mq */ + int qlines; /* queue size in CL */ + int interrupt_vector; /* interrupt vector */ + int interrupt_pnode; /* pnode for interrupt */ + int interrupt_apicid; /* lapicid for interrupt */ +}; + /* * Initialize a user allocated chunk of memory to be used as * a message queue. The caller must ensure that the queue is @@ -51,14 +60,19 @@ * to manage the queue. * * Input: - * p pointer to user allocated memory. + * mqd pointer to message queue descriptor + * p pointer to user allocated mesq memory. * bytes size of message queue in bytes + * vector interrupt vector (zero if no interrupts) + * nasid nasid of blade where interrupt is delivered + * apicid apicid of cpu for interrupt * * Errors: * 0 OK * >0 error */ -extern int gru_create_message_queue(void *p, unsigned int bytes); +extern int gru_create_message_queue(struct gru_message_queue_desc *mqd, + void *p, unsigned int bytes, int nasid, int vector, int apicid); /* * Send a message to a message queue. @@ -68,7 +82,7 @@ extern int gru_create_message_queue(void *p, unsigned int bytes); * * * Input: - * xmq message queue - must be a UV global physical address + * mqd pointer to message queue descriptor * mesg pointer to message. Must be 64-bit aligned * bytes size of message in bytes * @@ -77,8 +91,8 @@ extern int gru_create_message_queue(void *p, unsigned int bytes); * >0 Send failure - see error codes below * */ -extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg, - unsigned int bytes); +extern int gru_send_message_gpa(struct gru_message_queue_desc *mqd, + void *mesg, unsigned int bytes); /* Status values for gru_send_message() */ #define MQE_OK 0 /* message sent successfully */ @@ -94,10 +108,11 @@ extern int gru_send_message_gpa(unsigned long mq_gpa, void *mesg, * API extensions may allow for out-of-order freeing. * * Input - * mq message queue + * mqd pointer to message queue descriptor * mesq message being freed */ -extern void gru_free_message(void *mq, void *mesq); +extern void gru_free_message(struct gru_message_queue_desc *mqd, + void *mesq); /* * Get next message from message queue. Returns pointer to @@ -106,13 +121,13 @@ extern void gru_free_message(void *mq, void *mesq); * in order to move the queue pointers to next message. * * Input - * mq message queue + * mqd pointer to message queue descriptor * * Output: * p pointer to message * NULL no message available */ -extern void *gru_get_next_message(void *mq); +extern void *gru_get_next_message(struct gru_message_queue_desc *mqd); /* diff --git a/trunk/drivers/misc/sgi-gru/grumain.c b/trunk/drivers/misc/sgi-gru/grumain.c index 3d2fc216bae5..ec3f7a17d221 100644 --- a/trunk/drivers/misc/sgi-gru/grumain.c +++ b/trunk/drivers/misc/sgi-gru/grumain.c @@ -76,10 +76,9 @@ int gru_cpu_fault_map_id(void) /* Hit the asid limit. Start over */ static int gru_wrap_asid(struct gru_state *gru) { - gru_dbg(grudev, "gru %p\n", gru); + gru_dbg(grudev, "gid %d\n", gru->gs_gid); STAT(asid_wrap); gru->gs_asid_gen++; - gru_flush_all_tlb(gru); return MIN_ASID; } @@ -88,19 +87,21 @@ static int gru_reset_asid_limit(struct gru_state *gru, int asid) { int i, gid, inuse_asid, limit; - gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); + gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid); STAT(asid_next); limit = MAX_ASID; if (asid >= limit) asid = gru_wrap_asid(gru); + gru_flush_all_tlb(gru); gid = gru->gs_gid; again: for (i = 0; i < GRU_NUM_CCH; i++) { if (!gru->gs_gts[i]) continue; inuse_asid = gru->gs_gts[i]->ts_gms->ms_asids[gid].mt_asid; - gru_dbg(grudev, "gru %p, inuse_asid 0x%x, cxtnum %d, gts %p\n", - gru, inuse_asid, i, gru->gs_gts[i]); + gru_dbg(grudev, "gid %d, gts %p, gms %p, inuse 0x%x, cxt %d\n", + gru->gs_gid, gru->gs_gts[i], gru->gs_gts[i]->ts_gms, + inuse_asid, i); if (inuse_asid == asid) { asid += ASID_INC; if (asid >= limit) { @@ -120,8 +121,8 @@ static int gru_reset_asid_limit(struct gru_state *gru, int asid) } gru->gs_asid_limit = limit; gru->gs_asid = asid; - gru_dbg(grudev, "gru %p, new asid 0x%x, new_limit 0x%x\n", gru, asid, - limit); + gru_dbg(grudev, "gid %d, new asid 0x%x, new_limit 0x%x\n", gru->gs_gid, + asid, limit); return asid; } @@ -130,14 +131,12 @@ static int gru_assign_asid(struct gru_state *gru) { int asid; - spin_lock(&gru->gs_asid_lock); gru->gs_asid += ASID_INC; asid = gru->gs_asid; if (asid >= gru->gs_asid_limit) asid = gru_reset_asid_limit(gru, asid); - spin_unlock(&gru->gs_asid_lock); - gru_dbg(grudev, "gru %p, asid 0x%x\n", gru, asid); + gru_dbg(grudev, "gid %d, asid 0x%x\n", gru->gs_gid, asid); return asid; } @@ -215,17 +214,20 @@ static int check_gru_resources(struct gru_state *gru, int cbr_au_count, * TLB manangment requires tracking all GRU chiplets that have loaded a GSEG * context. */ -static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, - int ctxnum) +static int gru_load_mm_tracker(struct gru_state *gru, + struct gru_thread_state *gts) { + struct gru_mm_struct *gms = gts->ts_gms; struct gru_mm_tracker *asids = &gms->ms_asids[gru->gs_gid]; - unsigned short ctxbitmap = (1 << ctxnum); + unsigned short ctxbitmap = (1 << gts->ts_ctxnum); int asid; spin_lock(&gms->ms_asid_lock); asid = asids->mt_asid; - if (asid == 0 || asids->mt_asid_gen != gru->gs_asid_gen) { + spin_lock(&gru->gs_asid_lock); + if (asid == 0 || (asids->mt_ctxbitmap == 0 && asids->mt_asid_gen != + gru->gs_asid_gen)) { asid = gru_assign_asid(gru); asids->mt_asid = asid; asids->mt_asid_gen = gru->gs_asid_gen; @@ -233,6 +235,7 @@ static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, } else { STAT(asid_reuse); } + spin_unlock(&gru->gs_asid_lock); BUG_ON(asids->mt_ctxbitmap & ctxbitmap); asids->mt_ctxbitmap |= ctxbitmap; @@ -241,24 +244,28 @@ static int gru_load_mm_tracker(struct gru_state *gru, struct gru_mm_struct *gms, spin_unlock(&gms->ms_asid_lock); gru_dbg(grudev, - "gru %x, gms %p, ctxnum 0x%d, asid 0x%x, asidmap 0x%lx\n", - gru->gs_gid, gms, ctxnum, asid, gms->ms_asidmap[0]); + "gid %d, gts %p, gms %p, ctxnum %d, asid 0x%x, asidmap 0x%lx\n", + gru->gs_gid, gts, gms, gts->ts_ctxnum, asid, + gms->ms_asidmap[0]); return asid; } static void gru_unload_mm_tracker(struct gru_state *gru, - struct gru_mm_struct *gms, int ctxnum) + struct gru_thread_state *gts) { + struct gru_mm_struct *gms = gts->ts_gms; struct gru_mm_tracker *asids; unsigned short ctxbitmap; asids = &gms->ms_asids[gru->gs_gid]; - ctxbitmap = (1 << ctxnum); + ctxbitmap = (1 << gts->ts_ctxnum); spin_lock(&gms->ms_asid_lock); + spin_lock(&gru->gs_asid_lock); BUG_ON((asids->mt_ctxbitmap & ctxbitmap) != ctxbitmap); asids->mt_ctxbitmap ^= ctxbitmap; - gru_dbg(grudev, "gru %x, gms %p, ctxnum 0x%d, asidmap 0x%lx\n", - gru->gs_gid, gms, ctxnum, gms->ms_asidmap[0]); + gru_dbg(grudev, "gid %d, gts %p, gms %p, ctxnum 0x%d, asidmap 0x%lx\n", + gru->gs_gid, gts, gms, gts->ts_ctxnum, gms->ms_asidmap[0]); + spin_unlock(&gru->gs_asid_lock); spin_unlock(&gms->ms_asid_lock); } @@ -319,6 +326,7 @@ static struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, gts->ts_vma = vma; gts->ts_tlb_int_select = -1; gts->ts_gms = gru_register_mmu_notifier(); + gts->ts_sizeavail = GRU_SIZEAVAIL(PAGE_SHIFT); if (!gts->ts_gms) goto err; @@ -399,7 +407,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts) struct gru_state *gru; gru = gts->ts_gru; - gru_dbg(grudev, "gts %p, gru %p\n", gts, gru); + gru_dbg(grudev, "gts %p, gid %d\n", gts, gru->gs_gid); spin_lock(&gru->gs_lock); gru->gs_gts[gts->ts_ctxnum] = NULL; @@ -408,6 +416,7 @@ static void gru_free_gru_context(struct gru_thread_state *gts) __clear_bit(gts->ts_ctxnum, &gru->gs_context_map); gts->ts_ctxnum = NULLCTX; gts->ts_gru = NULL; + gts->ts_blade = -1; spin_unlock(&gru->gs_lock); gts_drop(gts); @@ -432,8 +441,8 @@ static inline long gru_copy_handle(void *d, void *s) return GRU_HANDLE_BYTES; } -static void gru_prefetch_context(void *gseg, void *cb, void *cbe, unsigned long cbrmap, - unsigned long length) +static void gru_prefetch_context(void *gseg, void *cb, void *cbe, + unsigned long cbrmap, unsigned long length) { int i, scr; @@ -500,12 +509,12 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate) zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE); cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); + gru_dbg(grudev, "gts %p\n", gts); lock_cch_handle(cch); if (cch_interrupt_sync(cch)) BUG(); - gru_dbg(grudev, "gts %p\n", gts); - gru_unload_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); + gru_unload_mm_tracker(gru, gts); if (savestate) gru_unload_context_data(gts->ts_gdata, gru->gs_gru_base_vaddr, ctxnum, gts->ts_cbr_map, @@ -534,7 +543,7 @@ static void gru_load_context(struct gru_thread_state *gts) cch = get_cch(gru->gs_gru_base_vaddr, ctxnum); lock_cch_handle(cch); - asid = gru_load_mm_tracker(gru, gts->ts_gms, gts->ts_ctxnum); + asid = gru_load_mm_tracker(gru, gts); cch->tfm_fault_bit_enable = (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR); @@ -544,7 +553,8 @@ static void gru_load_context(struct gru_thread_state *gts) cch->tlb_int_select = gts->ts_tlb_int_select; } cch->tfm_done_bit_enable = 0; - err = cch_allocate(cch, asid, gts->ts_cbr_map, gts->ts_dsr_map); + err = cch_allocate(cch, asid, gts->ts_sizeavail, gts->ts_cbr_map, + gts->ts_dsr_map); if (err) { gru_dbg(grudev, "err %d: cch %p, gts %p, cbr 0x%lx, dsr 0x%lx\n", @@ -565,11 +575,12 @@ static void gru_load_context(struct gru_thread_state *gts) /* * Update fields in an active CCH: * - retarget interrupts on local blade + * - update sizeavail mask * - force a delayed context unload by clearing the CCH asids. This * forces TLB misses for new GRU instructions. The context is unloaded * when the next TLB miss occurs. */ -static int gru_update_cch(struct gru_thread_state *gts, int int_select) +int gru_update_cch(struct gru_thread_state *gts, int force_unload) { struct gru_context_configuration_handle *cch; struct gru_state *gru = gts->ts_gru; @@ -583,9 +594,11 @@ static int gru_update_cch(struct gru_thread_state *gts, int int_select) goto exit; if (cch_interrupt(cch)) BUG(); - if (int_select >= 0) { - gts->ts_tlb_int_select = int_select; - cch->tlb_int_select = int_select; + if (!force_unload) { + for (i = 0; i < 8; i++) + cch->sizeavail[i] = gts->ts_sizeavail; + gts->ts_tlb_int_select = gru_cpu_fault_map_id(); + cch->tlb_int_select = gru_cpu_fault_map_id(); } else { for (i = 0; i < 8; i++) cch->asid[i] = 0; @@ -617,7 +630,7 @@ static int gru_retarget_intr(struct gru_thread_state *gts) gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select, gru_cpu_fault_map_id()); - return gru_update_cch(gts, gru_cpu_fault_map_id()); + return gru_update_cch(gts, 0); } @@ -688,7 +701,7 @@ static void gru_steal_context(struct gru_thread_state *gts) STAT(steal_context_failed); } gru_dbg(grudev, - "stole gru %x, ctxnum %d from gts %p. Need cb %d, ds %d;" + "stole gid %d, ctxnum %d from gts %p. Need cb %d, ds %d;" " avail cb %ld, ds %ld\n", gru->gs_gid, ctxnum, ngts, cbr, dsr, hweight64(gru->gs_cbr_map), hweight64(gru->gs_dsr_map)); @@ -727,6 +740,7 @@ static struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts) } reserve_gru_resources(gru, gts); gts->ts_gru = gru; + gts->ts_blade = gru->gs_blade_id; gts->ts_ctxnum = find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH); @@ -737,7 +751,7 @@ static struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts) STAT(assign_context); gru_dbg(grudev, - "gseg %p, gts %p, gru %x, ctx %d, cbr %d, dsr %d\n", + "gseg %p, gts %p, gid %d, ctx %d, cbr %d, dsr %d\n", gseg_virtual_address(gts->ts_gru, gts->ts_ctxnum), gts, gts->ts_gru->gs_gid, gts->ts_ctxnum, gts->ts_cbr_au_count, gts->ts_dsr_au_count); @@ -773,8 +787,8 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; again: - preempt_disable(); mutex_lock(>s->ts_ctxlock); + preempt_disable(); if (gts->ts_gru) { if (gts->ts_gru->gs_blade_id != uv_numa_blade_id()) { STAT(migrated_nopfn_unload); diff --git a/trunk/drivers/misc/sgi-gru/gruprocfs.c b/trunk/drivers/misc/sgi-gru/gruprocfs.c index 73b0ca061bb5..ee74821b171c 100644 --- a/trunk/drivers/misc/sgi-gru/gruprocfs.c +++ b/trunk/drivers/misc/sgi-gru/gruprocfs.c @@ -62,7 +62,9 @@ static int statistics_show(struct seq_file *s, void *p) printstat(s, asid_wrap); printstat(s, asid_reuse); printstat(s, intr); + printstat(s, intr_mm_lock_failed); printstat(s, call_os); + printstat(s, call_os_offnode_reference); printstat(s, call_os_check_for_bug); printstat(s, call_os_wait_queue); printstat(s, user_flush_tlb); @@ -120,6 +122,30 @@ static ssize_t statistics_write(struct file *file, const char __user *userbuf, return count; } +static int mcs_statistics_show(struct seq_file *s, void *p) +{ + int op; + unsigned long total, count, max; + static char *id[] = {"cch_allocate", "cch_start", "cch_interrupt", + "cch_interrupt_sync", "cch_deallocate", "tgh_invalidate"}; + + for (op = 0; op < mcsop_last; op++) { + count = atomic_long_read(&mcs_op_statistics[op].count); + total = atomic_long_read(&mcs_op_statistics[op].total); + max = mcs_op_statistics[op].max; + seq_printf(s, "%-20s%12ld%12ld%12ld\n", id[op], count, + count ? total / count : 0, max); + } + return 0; +} + +static ssize_t mcs_statistics_write(struct file *file, + const char __user *userbuf, size_t count, loff_t *data) +{ + memset(mcs_op_statistics, 0, sizeof(mcs_op_statistics)); + return count; +} + static int options_show(struct seq_file *s, void *p) { seq_printf(s, "0x%lx\n", gru_options); @@ -135,6 +161,7 @@ static ssize_t options_write(struct file *file, const char __user *userbuf, if (copy_from_user (buf, userbuf, count < sizeof(buf) ? count : sizeof(buf))) return -EFAULT; + buf[count - 1] = '\0'; if (!strict_strtoul(buf, 10, &val)) gru_options = val; @@ -199,7 +226,7 @@ static void seq_stop(struct seq_file *file, void *data) static void *seq_start(struct seq_file *file, loff_t *gid) { - if (*gid < GRU_MAX_GRUS) + if (*gid < gru_max_gids) return gid; return NULL; } @@ -207,7 +234,7 @@ static void *seq_start(struct seq_file *file, loff_t *gid) static void *seq_next(struct seq_file *file, void *data, loff_t *gid) { (*gid)++; - if (*gid < GRU_MAX_GRUS) + if (*gid < gru_max_gids) return gid; return NULL; } @@ -231,6 +258,11 @@ static int statistics_open(struct inode *inode, struct file *file) return single_open(file, statistics_show, NULL); } +static int mcs_statistics_open(struct inode *inode, struct file *file) +{ + return single_open(file, mcs_statistics_show, NULL); +} + static int options_open(struct inode *inode, struct file *file) { return single_open(file, options_show, NULL); @@ -255,6 +287,14 @@ static const struct file_operations statistics_fops = { .release = single_release, }; +static const struct file_operations mcs_statistics_fops = { + .open = mcs_statistics_open, + .read = seq_read, + .write = mcs_statistics_write, + .llseek = seq_lseek, + .release = single_release, +}; + static const struct file_operations options_fops = { .open = options_open, .read = seq_read, @@ -283,6 +323,7 @@ static struct proc_entry { struct proc_dir_entry *entry; } proc_files[] = { {"statistics", 0644, &statistics_fops}, + {"mcs_statistics", 0644, &mcs_statistics_fops}, {"debug_options", 0644, &options_fops}, {"cch_status", 0444, &cch_fops}, {"gru_status", 0444, &gru_fops}, diff --git a/trunk/drivers/misc/sgi-gru/grutables.h b/trunk/drivers/misc/sgi-gru/grutables.h index a78f70deeb59..bf1eeb7553ed 100644 --- a/trunk/drivers/misc/sgi-gru/grutables.h +++ b/trunk/drivers/misc/sgi-gru/grutables.h @@ -153,6 +153,7 @@ extern struct gru_stats_s gru_stats; extern struct gru_blade_state *gru_base[]; extern unsigned long gru_start_paddr, gru_end_paddr; +extern unsigned int gru_max_gids; #define GRU_MAX_BLADES MAX_NUMNODES #define GRU_MAX_GRUS (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE) @@ -184,7 +185,9 @@ struct gru_stats_s { atomic_long_t asid_wrap; atomic_long_t asid_reuse; atomic_long_t intr; + atomic_long_t intr_mm_lock_failed; atomic_long_t call_os; + atomic_long_t call_os_offnode_reference; atomic_long_t call_os_check_for_bug; atomic_long_t call_os_wait_queue; atomic_long_t user_flush_tlb; @@ -237,6 +240,17 @@ struct gru_stats_s { }; +enum mcs_op {cchop_allocate, cchop_start, cchop_interrupt, cchop_interrupt_sync, + cchop_deallocate, tghop_invalidate, mcsop_last}; + +struct mcs_op_statistic { + atomic_long_t count; + atomic_long_t total; + unsigned long max; +}; + +extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; + #define OPT_DPRINT 1 #define OPT_STATS 2 #define GRU_QUICKLOOK 4 @@ -278,13 +292,12 @@ struct gru_stats_s { /* Generate a GRU asid value from a GRU base asid & a virtual address. */ #if defined CONFIG_IA64 #define VADDR_HI_BIT 64 -#define GRUREGION(addr) ((addr) >> (VADDR_HI_BIT - 3) & 3) #elif defined CONFIG_X86_64 #define VADDR_HI_BIT 48 -#define GRUREGION(addr) (0) /* ZZZ could do better */ #else #error "Unsupported architecture" #endif +#define GRUREGION(addr) ((addr) >> (VADDR_HI_BIT - 3) & 3) #define GRUASID(asid, addr) ((asid) + GRUREGION(addr)) /*------------------------------------------------------------------------------ @@ -297,12 +310,12 @@ struct gru_state; * This structure is pointed to from the mmstruct via the notifier pointer. * There is one of these per address space. */ -struct gru_mm_tracker { - unsigned int mt_asid_gen; /* ASID wrap count */ - int mt_asid; /* current base ASID for gru */ - unsigned short mt_ctxbitmap; /* bitmap of contexts using +struct gru_mm_tracker { /* pack to reduce size */ + unsigned int mt_asid_gen:24; /* ASID wrap count */ + unsigned int mt_asid:24; /* current base ASID for gru */ + unsigned short mt_ctxbitmap:16;/* bitmap of contexts using asid */ -}; +} __attribute__ ((packed)); struct gru_mm_struct { struct mmu_notifier ms_notifier; @@ -348,6 +361,7 @@ struct gru_thread_state { long ts_user_options;/* misc user option flags */ pid_t ts_tgid_owner; /* task that is using the context - for migration */ + unsigned short ts_sizeavail; /* Pagesizes in use */ int ts_tsid; /* thread that owns the structure */ int ts_tlb_int_select;/* target cpu if interrupts @@ -359,6 +373,9 @@ struct gru_thread_state { required for contest */ unsigned char ts_cbr_au_count;/* Number of CBR resources required for contest */ + char ts_blade; /* If >= 0, migrate context if + ref from diferent blade */ + char ts_force_cch_reload; char ts_force_unload;/* force context to be unloaded after migration */ char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each @@ -392,12 +409,12 @@ struct gru_state { gru segments (64) */ void *gs_gru_base_vaddr; /* Virtual address of gru segments (64) */ - unsigned char gs_gid; /* unique GRU number */ + unsigned short gs_gid; /* unique GRU number */ + unsigned short gs_blade_id; /* blade of GRU */ unsigned char gs_tgh_local_shift; /* used to pick TGH for local flush */ unsigned char gs_tgh_first_remote; /* starting TGH# for remote flush */ - unsigned short gs_blade_id; /* blade of GRU */ spinlock_t gs_asid_lock; /* lock used for assigning asids */ spinlock_t gs_lock; /* lock used for @@ -492,6 +509,10 @@ struct gru_blade_state { (i) < GRU_CHIPLETS_PER_BLADE; \ (i)++, (gru)++) +/* Scan all GRUs */ +#define foreach_gid(gid) \ + for ((gid) = 0; (gid) < gru_max_gids; (gid)++) + /* Scan all active GTSs on a gru. Note: must hold ss_lock to use this macro. */ #define for_each_gts_on_gru(gts, gru, ctxnum) \ for ((ctxnum) = 0; (ctxnum) < GRU_NUM_CCH; (ctxnum)++) \ @@ -578,9 +599,11 @@ extern struct gru_thread_state *gru_find_thread_state(struct vm_area_struct extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, int tsid); extern void gru_unload_context(struct gru_thread_state *gts, int savestate); +extern int gru_update_cch(struct gru_thread_state *gts, int force_unload); extern void gts_drop(struct gru_thread_state *gts); extern void gru_tgh_flush_init(struct gru_state *gru); extern int gru_kservices_init(struct gru_state *gru); +extern void gru_kservices_exit(struct gru_state *gru); extern irqreturn_t gru_intr(int irq, void *dev_id); extern int gru_handle_user_call_os(unsigned long address); extern int gru_user_flush_tlb(unsigned long arg); diff --git a/trunk/drivers/misc/sgi-gru/grutlbpurge.c b/trunk/drivers/misc/sgi-gru/grutlbpurge.c index c84496a77691..1d125091f5e7 100644 --- a/trunk/drivers/misc/sgi-gru/grutlbpurge.c +++ b/trunk/drivers/misc/sgi-gru/grutlbpurge.c @@ -187,7 +187,7 @@ void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, " FLUSH gruid %d, asid 0x%x, num %ld, cbmap 0x%x\n", gid, asid, num, asids->mt_ctxbitmap); tgh = get_lock_tgh_handle(gru); - tgh_invalidate(tgh, start, 0, asid, grupagesize, 0, + tgh_invalidate(tgh, start, ~0, asid, grupagesize, 0, num - 1, asids->mt_ctxbitmap); get_unlock_tgh_handle(tgh); } else { @@ -210,11 +210,10 @@ void gru_flush_all_tlb(struct gru_state *gru) { struct gru_tlb_global_handle *tgh; - gru_dbg(grudev, "gru %p, gid %d\n", gru, gru->gs_gid); + gru_dbg(grudev, "gid %d\n", gru->gs_gid); tgh = get_lock_tgh_handle(gru); - tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0); + tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0xffff); get_unlock_tgh_handle(tgh); - preempt_enable(); } /* diff --git a/trunk/drivers/misc/sgi-xp/xpc.h b/trunk/drivers/misc/sgi-xp/xpc.h index 275b78896a73..114444cfd496 100644 --- a/trunk/drivers/misc/sgi-xp/xpc.h +++ b/trunk/drivers/misc/sgi-xp/xpc.h @@ -92,7 +92,9 @@ struct xpc_rsvd_page { u8 pad1[3]; /* align to next u64 in 1st 64-byte cacheline */ union { unsigned long vars_pa; /* phys address of struct xpc_vars */ - unsigned long activate_mq_gpa; /* gru phy addr of activate_mq */ + unsigned long activate_gru_mq_desc_gpa; /* phys addr of */ + /* activate mq's */ + /* gru mq descriptor */ } sn; unsigned long ts_jiffies; /* timestamp when rsvd pg was setup by XPC */ u64 pad2[10]; /* align to last u64 in 2nd 64-byte cacheline */ @@ -189,7 +191,9 @@ struct xpc_gru_mq_uv { int irq; /* irq raised when message is received in mq */ int mmr_blade; /* blade where watchlist was allocated from */ unsigned long mmr_offset; /* offset of irq mmr located on mmr_blade */ + unsigned long mmr_value; /* value of irq mmr located on mmr_blade */ int watchlist_num; /* number of watchlist allocatd by BIOS */ + void *gru_mq_desc; /* opaque structure used by the GRU driver */ }; /* @@ -197,6 +201,7 @@ struct xpc_gru_mq_uv { * heartbeat, partition active state, and channel state. This is UV only. */ struct xpc_activate_mq_msghdr_uv { + unsigned int gru_msg_hdr; /* FOR GRU INTERNAL USE ONLY */ short partid; /* sender's partid */ u8 act_state; /* sender's act_state at time msg sent */ u8 type; /* message's type */ @@ -232,7 +237,7 @@ struct xpc_activate_mq_msg_heartbeat_req_uv { struct xpc_activate_mq_msg_activate_req_uv { struct xpc_activate_mq_msghdr_uv hdr; unsigned long rp_gpa; - unsigned long activate_mq_gpa; + unsigned long activate_gru_mq_desc_gpa; }; struct xpc_activate_mq_msg_deactivate_req_uv { @@ -263,7 +268,7 @@ struct xpc_activate_mq_msg_chctl_openreply_uv { short ch_number; short remote_nentries; /* ??? Is this needed? What is? */ short local_nentries; /* ??? Is this needed? What is? */ - unsigned long local_notify_mq_gpa; + unsigned long notify_gru_mq_desc_gpa; }; /* @@ -510,8 +515,8 @@ struct xpc_channel_sn2 { }; struct xpc_channel_uv { - unsigned long remote_notify_mq_gpa; /* gru phys address of remote */ - /* partition's notify mq */ + void *cached_notify_gru_mq_desc; /* remote partition's notify mq's */ + /* gru mq descriptor */ struct xpc_send_msg_slot_uv *send_msg_slots; void *recv_msg_slots; /* each slot will hold a xpc_notify_mq_msg_uv */ @@ -682,8 +687,12 @@ struct xpc_partition_sn2 { }; struct xpc_partition_uv { - unsigned long remote_activate_mq_gpa; /* gru phys address of remote */ - /* partition's activate mq */ + unsigned long activate_gru_mq_desc_gpa; /* phys addr of parititon's */ + /* activate mq's gru mq */ + /* descriptor */ + void *cached_activate_gru_mq_desc; /* cached copy of partition's */ + /* activate mq's gru mq descriptor */ + struct mutex cached_activate_gru_mq_desc_mutex; spinlock_t flags_lock; /* protect updating of flags */ unsigned int flags; /* general flags */ u8 remote_act_state; /* remote partition's act_state */ @@ -694,8 +703,9 @@ struct xpc_partition_uv { /* struct xpc_partition_uv flags */ -#define XPC_P_HEARTBEAT_OFFLINE_UV 0x00000001 -#define XPC_P_ENGAGED_UV 0x00000002 +#define XPC_P_HEARTBEAT_OFFLINE_UV 0x00000001 +#define XPC_P_ENGAGED_UV 0x00000002 +#define XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV 0x00000004 /* struct xpc_partition_uv act_state change requests */ @@ -804,6 +814,7 @@ extern void xpc_activate_kthreads(struct xpc_channel *, int); extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); extern int (*xpc_setup_partitions_sn) (void); +extern void (*xpc_teardown_partitions_sn) (void); extern enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *, u64 *, unsigned long *, size_t *); @@ -846,8 +857,8 @@ extern void (*xpc_send_chctl_openrequest) (struct xpc_channel *, unsigned long *); extern void (*xpc_send_chctl_openreply) (struct xpc_channel *, unsigned long *); -extern void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *, - unsigned long); +extern enum xp_retval (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *, + unsigned long); extern enum xp_retval (*xpc_send_payload) (struct xpc_channel *, u32, void *, u16, u8, xpc_notify_func, void *); diff --git a/trunk/drivers/misc/sgi-xp/xpc_channel.c b/trunk/drivers/misc/sgi-xp/xpc_channel.c index 45fd653dbe31..99a2534c38a1 100644 --- a/trunk/drivers/misc/sgi-xp/xpc_channel.c +++ b/trunk/drivers/misc/sgi-xp/xpc_channel.c @@ -183,6 +183,7 @@ xpc_process_openclose_chctl_flags(struct xpc_partition *part, int ch_number, &part->remote_openclose_args[ch_number]; struct xpc_channel *ch = &part->channels[ch_number]; enum xp_retval reason; + enum xp_retval ret; spin_lock_irqsave(&ch->lock, irq_flags); @@ -399,8 +400,13 @@ xpc_process_openclose_chctl_flags(struct xpc_partition *part, int ch_number, DBUG_ON(args->local_nentries == 0); DBUG_ON(args->remote_nentries == 0); + ret = xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa); + if (ret != xpSuccess) { + XPC_DISCONNECT_CHANNEL(ch, ret, &irq_flags); + spin_unlock_irqrestore(&ch->lock, irq_flags); + return; + } ch->flags |= XPC_C_ROPENREPLY; - xpc_save_remote_msgqueue_pa(ch, args->local_msgqueue_pa); if (args->local_nentries < ch->remote_nentries) { dev_dbg(xpc_chan, "XPC_CHCTL_OPENREPLY: new " diff --git a/trunk/drivers/misc/sgi-xp/xpc_main.c b/trunk/drivers/misc/sgi-xp/xpc_main.c index 6576170de962..1ab9fda87fab 100644 --- a/trunk/drivers/misc/sgi-xp/xpc_main.c +++ b/trunk/drivers/misc/sgi-xp/xpc_main.c @@ -171,6 +171,7 @@ static struct notifier_block xpc_die_notifier = { }; int (*xpc_setup_partitions_sn) (void); +void (*xpc_teardown_partitions_sn) (void); enum xp_retval (*xpc_get_partition_rsvd_page_pa) (void *buf, u64 *cookie, unsigned long *rp_pa, size_t *len); @@ -217,8 +218,8 @@ void (*xpc_send_chctl_openrequest) (struct xpc_channel *ch, void (*xpc_send_chctl_openreply) (struct xpc_channel *ch, unsigned long *irq_flags); -void (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch, - unsigned long msgqueue_pa); +enum xp_retval (*xpc_save_remote_msgqueue_pa) (struct xpc_channel *ch, + unsigned long msgqueue_pa); enum xp_retval (*xpc_send_payload) (struct xpc_channel *ch, u32 flags, void *payload, u16 payload_size, @@ -998,6 +999,7 @@ xpc_setup_partitions(void) static void xpc_teardown_partitions(void) { + xpc_teardown_partitions_sn(); kfree(xpc_partitions); } diff --git a/trunk/drivers/misc/sgi-xp/xpc_sn2.c b/trunk/drivers/misc/sgi-xp/xpc_sn2.c index 2e975762c32b..eaaa964942de 100644 --- a/trunk/drivers/misc/sgi-xp/xpc_sn2.c +++ b/trunk/drivers/misc/sgi-xp/xpc_sn2.c @@ -66,6 +66,12 @@ xpc_setup_partitions_sn_sn2(void) return 0; } +static void +xpc_teardown_partitions_sn_sn2(void) +{ + /* nothing needs to be done */ +} + /* SH_IPI_ACCESS shub register value on startup */ static u64 xpc_sh1_IPI_access_sn2; static u64 xpc_sh2_IPI_access0_sn2; @@ -436,11 +442,12 @@ xpc_send_chctl_local_msgrequest_sn2(struct xpc_channel *ch) XPC_SEND_LOCAL_NOTIFY_IRQ_SN2(ch, XPC_CHCTL_MSGREQUEST); } -static void +static enum xp_retval xpc_save_remote_msgqueue_pa_sn2(struct xpc_channel *ch, unsigned long msgqueue_pa) { ch->sn.sn2.remote_msgqueue_pa = msgqueue_pa; + return xpSuccess; } /* @@ -1737,20 +1744,20 @@ xpc_clear_remote_msgqueue_flags_sn2(struct xpc_channel *ch) { struct xpc_channel_sn2 *ch_sn2 = &ch->sn.sn2; struct xpc_msg_sn2 *msg; - s64 put; + s64 put, remote_nentries = ch->remote_nentries; /* flags are zeroed when the buffer is allocated */ - if (ch_sn2->remote_GP.put < ch->remote_nentries) + if (ch_sn2->remote_GP.put < remote_nentries) return; - put = max(ch_sn2->w_remote_GP.put, ch->remote_nentries); + put = max(ch_sn2->w_remote_GP.put, remote_nentries); do { msg = (struct xpc_msg_sn2 *)((u64)ch_sn2->remote_msgqueue + - (put % ch->remote_nentries) * + (put % remote_nentries) * ch->entry_size); DBUG_ON(!(msg->flags & XPC_M_SN2_READY)); DBUG_ON(!(msg->flags & XPC_M_SN2_DONE)); - DBUG_ON(msg->number != put - ch->remote_nentries); + DBUG_ON(msg->number != put - remote_nentries); msg->flags = 0; } while (++put < ch_sn2->remote_GP.put); } @@ -2315,6 +2322,7 @@ xpc_init_sn2(void) size_t buf_size; xpc_setup_partitions_sn = xpc_setup_partitions_sn_sn2; + xpc_teardown_partitions_sn = xpc_teardown_partitions_sn_sn2; xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_sn2; xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_sn2; xpc_increment_heartbeat = xpc_increment_heartbeat_sn2; diff --git a/trunk/drivers/misc/sgi-xp/xpc_uv.c b/trunk/drivers/misc/sgi-xp/xpc_uv.c index 29c0502a96b2..f7fff4727edb 100644 --- a/trunk/drivers/misc/sgi-xp/xpc_uv.c +++ b/trunk/drivers/misc/sgi-xp/xpc_uv.c @@ -31,6 +31,21 @@ #include "../sgi-gru/grukservices.h" #include "xpc.h" +#if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV +struct uv_IO_APIC_route_entry { + __u64 vector : 8, + delivery_mode : 3, + dest_mode : 1, + delivery_status : 1, + polarity : 1, + __reserved_1 : 1, + trigger : 1, + mask : 1, + __reserved_2 : 15, + dest : 32; +}; +#endif + static atomic64_t xpc_heartbeat_uv; static DECLARE_BITMAP(xpc_heartbeating_to_mask_uv, XP_MAX_NPARTITIONS_UV); @@ -56,26 +71,52 @@ xpc_setup_partitions_sn_uv(void) for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) { part_uv = &xpc_partitions[partid].sn.uv; + mutex_init(&part_uv->cached_activate_gru_mq_desc_mutex); spin_lock_init(&part_uv->flags_lock); part_uv->remote_act_state = XPC_P_AS_INACTIVE; } return 0; } +static void +xpc_teardown_partitions_sn_uv(void) +{ + short partid; + struct xpc_partition_uv *part_uv; + unsigned long irq_flags; + + for (partid = 0; partid < XP_MAX_NPARTITIONS_UV; partid++) { + part_uv = &xpc_partitions[partid].sn.uv; + + if (part_uv->cached_activate_gru_mq_desc != NULL) { + mutex_lock(&part_uv->cached_activate_gru_mq_desc_mutex); + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + kfree(part_uv->cached_activate_gru_mq_desc); + part_uv->cached_activate_gru_mq_desc = NULL; + mutex_unlock(&part_uv-> + cached_activate_gru_mq_desc_mutex); + } + } +} + static int xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name) { + int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); + #if defined CONFIG_X86_64 mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset); if (mq->irq < 0) { dev_err(xpc_part, "uv_setup_irq() returned error=%d\n", - mq->irq); + -mq->irq); + return mq->irq; } -#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV - int mmr_pnode; - unsigned long mmr_value; + mq->mmr_value = uv_read_global_mmr64(mmr_pnode, mq->mmr_offset); +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV if (strcmp(irq_name, XPC_ACTIVATE_IRQ_NAME) == 0) mq->irq = SGI_XPC_ACTIVATE; else if (strcmp(irq_name, XPC_NOTIFY_IRQ_NAME) == 0) @@ -83,10 +124,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name) else return -EINVAL; - mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); - mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq; - - uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mmr_value); + mq->mmr_value = (unsigned long)cpu_physical_id(cpu) << 32 | mq->irq; + uv_write_global_mmr64(mmr_pnode, mq->mmr_offset, mq->mmr_value); #else #error not a supported configuration #endif @@ -127,7 +166,7 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq) return ret; } #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV - ret = sn_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), + ret = sn_mq_watchlist_alloc(mq->mmr_blade, (void *)uv_gpa(mq->address), mq->order, &mq->mmr_offset); if (ret < 0) { dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", @@ -168,12 +207,22 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, int pg_order; struct page *page; struct xpc_gru_mq_uv *mq; + struct uv_IO_APIC_route_entry *mmr_value; mq = kmalloc(sizeof(struct xpc_gru_mq_uv), GFP_KERNEL); if (mq == NULL) { dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() " "a xpc_gru_mq_uv structure\n"); ret = -ENOMEM; + goto out_0; + } + + mq->gru_mq_desc = kzalloc(sizeof(struct gru_message_queue_desc), + GFP_KERNEL); + if (mq->gru_mq_desc == NULL) { + dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to kmalloc() " + "a gru_message_queue_desc structure\n"); + ret = -ENOMEM; goto out_1; } @@ -194,14 +243,6 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, } mq->address = page_address(page); - ret = gru_create_message_queue(mq->address, mq_size); - if (ret != 0) { - dev_err(xpc_part, "gru_create_message_queue() returned " - "error=%d\n", ret); - ret = -EINVAL; - goto out_3; - } - /* enable generation of irq when GRU mq operation occurs to this mq */ ret = xpc_gru_mq_watchlist_alloc_uv(mq); if (ret != 0) @@ -214,10 +255,20 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, ret = request_irq(mq->irq, irq_handler, 0, irq_name, NULL); if (ret != 0) { dev_err(xpc_part, "request_irq(irq=%d) returned error=%d\n", - mq->irq, ret); + mq->irq, -ret); goto out_5; } + mmr_value = (struct uv_IO_APIC_route_entry *)&mq->mmr_value; + ret = gru_create_message_queue(mq->gru_mq_desc, mq->address, mq_size, + nid, mmr_value->vector, mmr_value->dest); + if (ret != 0) { + dev_err(xpc_part, "gru_create_message_queue() returned " + "error=%d\n", ret); + ret = -EINVAL; + goto out_6; + } + /* allow other partitions to access this GRU mq */ xp_ret = xp_expand_memprotect(xp_pa(mq->address), mq_size); if (xp_ret != xpSuccess) { @@ -237,8 +288,10 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, out_3: free_pages((unsigned long)mq->address, pg_order); out_2: - kfree(mq); + kfree(mq->gru_mq_desc); out_1: + kfree(mq); +out_0: return ERR_PTR(ret); } @@ -268,13 +321,14 @@ xpc_destroy_gru_mq_uv(struct xpc_gru_mq_uv *mq) } static enum xp_retval -xpc_send_gru_msg(unsigned long mq_gpa, void *msg, size_t msg_size) +xpc_send_gru_msg(struct gru_message_queue_desc *gru_mq_desc, void *msg, + size_t msg_size) { enum xp_retval xp_ret; int ret; while (1) { - ret = gru_send_message_gpa(mq_gpa, msg, msg_size); + ret = gru_send_message_gpa(gru_mq_desc, msg, msg_size); if (ret == MQE_OK) { xp_ret = xpSuccess; break; @@ -421,7 +475,15 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, part_uv->act_state_req = XPC_P_ASR_ACTIVATE_UV; part->remote_rp_pa = msg->rp_gpa; /* !!! _pa is _gpa */ part->remote_rp_ts_jiffies = msg_hdr->rp_ts_jiffies; - part_uv->remote_activate_mq_gpa = msg->activate_mq_gpa; + + if (msg->activate_gru_mq_desc_gpa != + part_uv->activate_gru_mq_desc_gpa) { + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags &= ~XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + part_uv->activate_gru_mq_desc_gpa = + msg->activate_gru_mq_desc_gpa; + } spin_unlock_irqrestore(&xpc_activate_IRQ_rcvd_lock, irq_flags); (*wakeup_hb_checker)++; @@ -498,7 +560,7 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, args = &part->remote_openclose_args[msg->ch_number]; args->remote_nentries = msg->remote_nentries; args->local_nentries = msg->local_nentries; - args->local_msgqueue_pa = msg->local_notify_mq_gpa; + args->local_msgqueue_pa = msg->notify_gru_mq_desc_gpa; spin_lock_irqsave(&part->chctl_lock, irq_flags); part->chctl.flags[msg->ch_number] |= XPC_CHCTL_OPENREPLY; @@ -558,9 +620,10 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id) short partid; struct xpc_partition *part; int wakeup_hb_checker = 0; + int part_referenced; while (1) { - msg_hdr = gru_get_next_message(xpc_activate_mq_uv->address); + msg_hdr = gru_get_next_message(xpc_activate_mq_uv->gru_mq_desc); if (msg_hdr == NULL) break; @@ -571,14 +634,15 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id) partid); } else { part = &xpc_partitions[partid]; - if (xpc_part_ref(part)) { - xpc_handle_activate_mq_msg_uv(part, msg_hdr, - &wakeup_hb_checker); + + part_referenced = xpc_part_ref(part); + xpc_handle_activate_mq_msg_uv(part, msg_hdr, + &wakeup_hb_checker); + if (part_referenced) xpc_part_deref(part); - } } - gru_free_message(xpc_activate_mq_uv->address, msg_hdr); + gru_free_message(xpc_activate_mq_uv->gru_mq_desc, msg_hdr); } if (wakeup_hb_checker) @@ -587,22 +651,74 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id) return IRQ_HANDLED; } +static enum xp_retval +xpc_cache_remote_gru_mq_desc_uv(struct gru_message_queue_desc *gru_mq_desc, + unsigned long gru_mq_desc_gpa) +{ + enum xp_retval ret; + + ret = xp_remote_memcpy(uv_gpa(gru_mq_desc), gru_mq_desc_gpa, + sizeof(struct gru_message_queue_desc)); + if (ret == xpSuccess) + gru_mq_desc->mq = NULL; + + return ret; +} + static enum xp_retval xpc_send_activate_IRQ_uv(struct xpc_partition *part, void *msg, size_t msg_size, int msg_type) { struct xpc_activate_mq_msghdr_uv *msg_hdr = msg; + struct xpc_partition_uv *part_uv = &part->sn.uv; + struct gru_message_queue_desc *gru_mq_desc; + unsigned long irq_flags; + enum xp_retval ret; DBUG_ON(msg_size > XPC_ACTIVATE_MSG_SIZE_UV); msg_hdr->type = msg_type; - msg_hdr->partid = XPC_PARTID(part); + msg_hdr->partid = xp_partition_id; msg_hdr->act_state = part->act_state; msg_hdr->rp_ts_jiffies = xpc_rsvd_page->ts_jiffies; + mutex_lock(&part_uv->cached_activate_gru_mq_desc_mutex); +again: + if (!(part_uv->flags & XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV)) { + gru_mq_desc = part_uv->cached_activate_gru_mq_desc; + if (gru_mq_desc == NULL) { + gru_mq_desc = kmalloc(sizeof(struct + gru_message_queue_desc), + GFP_KERNEL); + if (gru_mq_desc == NULL) { + ret = xpNoMemory; + goto done; + } + part_uv->cached_activate_gru_mq_desc = gru_mq_desc; + } + + ret = xpc_cache_remote_gru_mq_desc_uv(gru_mq_desc, + part_uv-> + activate_gru_mq_desc_gpa); + if (ret != xpSuccess) + goto done; + + spin_lock_irqsave(&part_uv->flags_lock, irq_flags); + part_uv->flags |= XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV; + spin_unlock_irqrestore(&part_uv->flags_lock, irq_flags); + } + /* ??? Is holding a spin_lock (ch->lock) during this call a bad idea? */ - return xpc_send_gru_msg(part->sn.uv.remote_activate_mq_gpa, msg, - msg_size); + ret = xpc_send_gru_msg(part_uv->cached_activate_gru_mq_desc, msg, + msg_size); + if (ret != xpSuccess) { + smp_rmb(); /* ensure a fresh copy of part_uv->flags */ + if (!(part_uv->flags & XPC_P_CACHED_ACTIVATE_GRU_MQ_DESC_UV)) + goto again; + } +done: + mutex_unlock(&part_uv->cached_activate_gru_mq_desc_mutex); + return ret; } static void @@ -620,7 +736,7 @@ static void xpc_send_activate_IRQ_ch_uv(struct xpc_channel *ch, unsigned long *irq_flags, void *msg, size_t msg_size, int msg_type) { - struct xpc_partition *part = &xpc_partitions[ch->number]; + struct xpc_partition *part = &xpc_partitions[ch->partid]; enum xp_retval ret; ret = xpc_send_activate_IRQ_uv(part, msg, msg_size, msg_type); @@ -692,7 +808,8 @@ xpc_get_partition_rsvd_page_pa_uv(void *buf, u64 *cookie, unsigned long *rp_pa, static int xpc_setup_rsvd_page_sn_uv(struct xpc_rsvd_page *rp) { - rp->sn.activate_mq_gpa = uv_gpa(xpc_activate_mq_uv->address); + rp->sn.activate_gru_mq_desc_gpa = + uv_gpa(xpc_activate_mq_uv->gru_mq_desc); return 0; } @@ -787,7 +904,8 @@ xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp, part->remote_rp_pa = remote_rp_gpa; /* !!! _pa here is really _gpa */ part->remote_rp_ts_jiffies = remote_rp->ts_jiffies; - part->sn.uv.remote_activate_mq_gpa = remote_rp->sn.activate_mq_gpa; + part->sn.uv.activate_gru_mq_desc_gpa = + remote_rp->sn.activate_gru_mq_desc_gpa; /* * ??? Is it a good idea to make this conditional on what is @@ -795,7 +913,8 @@ xpc_request_partition_activation_uv(struct xpc_rsvd_page *remote_rp, */ if (part->sn.uv.remote_act_state == XPC_P_AS_INACTIVE) { msg.rp_gpa = uv_gpa(xpc_rsvd_page); - msg.activate_mq_gpa = xpc_rsvd_page->sn.activate_mq_gpa; + msg.activate_gru_mq_desc_gpa = + xpc_rsvd_page->sn.activate_gru_mq_desc_gpa; xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), XPC_ACTIVATE_MQ_MSG_ACTIVATE_REQ_UV); } @@ -857,7 +976,8 @@ xpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head) if (head->first == NULL) head->last = NULL; } - head->n_entries++; + head->n_entries--; + BUG_ON(head->n_entries < 0); spin_unlock_irqrestore(&head->lock, irq_flags); first->next = NULL; return first; @@ -876,8 +996,7 @@ xpc_put_fifo_entry_uv(struct xpc_fifo_head_uv *head, else head->first = last; head->last = last; - head->n_entries--; - BUG_ON(head->n_entries < 0); + head->n_entries++; spin_unlock_irqrestore(&head->lock, irq_flags); } @@ -1037,6 +1156,12 @@ xpc_setup_msg_structures_uv(struct xpc_channel *ch) DBUG_ON(ch->flags & XPC_C_SETUP); + ch_uv->cached_notify_gru_mq_desc = kmalloc(sizeof(struct + gru_message_queue_desc), + GFP_KERNEL); + if (ch_uv->cached_notify_gru_mq_desc == NULL) + return xpNoMemory; + ret = xpc_allocate_send_msg_slot_uv(ch); if (ret == xpSuccess) { @@ -1060,7 +1185,8 @@ xpc_teardown_msg_structures_uv(struct xpc_channel *ch) DBUG_ON(!spin_is_locked(&ch->lock)); - ch_uv->remote_notify_mq_gpa = 0; + kfree(ch_uv->cached_notify_gru_mq_desc); + ch_uv->cached_notify_gru_mq_desc = NULL; if (ch->flags & XPC_C_SETUP) { xpc_init_fifo_uv(&ch_uv->msg_slot_free_list); @@ -1111,7 +1237,7 @@ xpc_send_chctl_openreply_uv(struct xpc_channel *ch, unsigned long *irq_flags) msg.ch_number = ch->number; msg.local_nentries = ch->local_nentries; msg.remote_nentries = ch->remote_nentries; - msg.local_notify_mq_gpa = uv_gpa(xpc_notify_mq_uv); + msg.notify_gru_mq_desc_gpa = uv_gpa(xpc_notify_mq_uv->gru_mq_desc); xpc_send_activate_IRQ_ch_uv(ch, irq_flags, &msg, sizeof(msg), XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV); } @@ -1128,11 +1254,15 @@ xpc_send_chctl_local_msgrequest_uv(struct xpc_partition *part, int ch_number) xpc_wakeup_channel_mgr(part); } -static void +static enum xp_retval xpc_save_remote_msgqueue_pa_uv(struct xpc_channel *ch, - unsigned long msgqueue_pa) + unsigned long gru_mq_desc_gpa) { - ch->sn.uv.remote_notify_mq_gpa = msgqueue_pa; + struct xpc_channel_uv *ch_uv = &ch->sn.uv; + + DBUG_ON(ch_uv->cached_notify_gru_mq_desc == NULL); + return xpc_cache_remote_gru_mq_desc_uv(ch_uv->cached_notify_gru_mq_desc, + gru_mq_desc_gpa); } static void @@ -1339,7 +1469,8 @@ xpc_handle_notify_IRQ_uv(int irq, void *dev_id) short partid; struct xpc_partition *part; - while ((msg = gru_get_next_message(xpc_notify_mq_uv)) != NULL) { + while ((msg = gru_get_next_message(xpc_notify_mq_uv->gru_mq_desc)) != + NULL) { partid = msg->hdr.partid; if (partid < 0 || partid >= XP_MAX_NPARTITIONS_UV) { @@ -1354,7 +1485,7 @@ xpc_handle_notify_IRQ_uv(int irq, void *dev_id) } } - gru_free_message(xpc_notify_mq_uv, msg); + gru_free_message(xpc_notify_mq_uv->gru_mq_desc, msg); } return IRQ_HANDLED; @@ -1438,7 +1569,8 @@ xpc_send_payload_uv(struct xpc_channel *ch, u32 flags, void *payload, msg->hdr.msg_slot_number = msg_slot->msg_slot_number; memcpy(&msg->payload, payload, payload_size); - ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, msg_size); + ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg, + msg_size); if (ret == xpSuccess) goto out_1; @@ -1529,7 +1661,7 @@ xpc_received_payload_uv(struct xpc_channel *ch, void *payload) msg->hdr.partid = xp_partition_id; msg->hdr.size = 0; /* size of zero indicates this is an ACK */ - ret = xpc_send_gru_msg(ch->sn.uv.remote_notify_mq_gpa, msg, + ret = xpc_send_gru_msg(ch->sn.uv.cached_notify_gru_mq_desc, msg, sizeof(struct xpc_notify_mq_msghdr_uv)); if (ret != xpSuccess) XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); @@ -1541,6 +1673,7 @@ int xpc_init_uv(void) { xpc_setup_partitions_sn = xpc_setup_partitions_sn_uv; + xpc_teardown_partitions_sn = xpc_teardown_partitions_sn_uv; xpc_process_activate_IRQ_rcvd = xpc_process_activate_IRQ_rcvd_uv; xpc_get_partition_rsvd_page_pa = xpc_get_partition_rsvd_page_pa_uv; xpc_setup_rsvd_page_sn = xpc_setup_rsvd_page_sn_uv; diff --git a/trunk/drivers/mmc/card/sdio_uart.c b/trunk/drivers/mmc/card/sdio_uart.c index 78ad48718ab0..36a8d53ad2a2 100644 --- a/trunk/drivers/mmc/card/sdio_uart.c +++ b/trunk/drivers/mmc/card/sdio_uart.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -933,67 +934,64 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file, return result; } -static int sdio_uart_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int sdio_uart_proc_show(struct seq_file *m, void *v) { - int i, len = 0; - off_t begin = 0; + int i; - len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", + seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", ""); - for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) { + for (i = 0; i < UART_NR; i++) { struct sdio_uart_port *port = sdio_uart_port_get(i); if (port) { - len += sprintf(page+len, "%d: uart:SDIO", i); + seq_printf(m, "%d: uart:SDIO", i); if(capable(CAP_SYS_ADMIN)) { - len += sprintf(page + len, " tx:%d rx:%d", + seq_printf(m, " tx:%d rx:%d", port->icount.tx, port->icount.rx); if (port->icount.frame) - len += sprintf(page + len, " fe:%d", + seq_printf(m, " fe:%d", port->icount.frame); if (port->icount.parity) - len += sprintf(page + len, " pe:%d", + seq_printf(m, " pe:%d", port->icount.parity); if (port->icount.brk) - len += sprintf(page + len, " brk:%d", + seq_printf(m, " brk:%d", port->icount.brk); if (port->icount.overrun) - len += sprintf(page + len, " oe:%d", + seq_printf(m, " oe:%d", port->icount.overrun); if (port->icount.cts) - len += sprintf(page + len, " cts:%d", + seq_printf(m, " cts:%d", port->icount.cts); if (port->icount.dsr) - len += sprintf(page + len, " dsr:%d", + seq_printf(m, " dsr:%d", port->icount.dsr); if (port->icount.rng) - len += sprintf(page + len, " rng:%d", + seq_printf(m, " rng:%d", port->icount.rng); if (port->icount.dcd) - len += sprintf(page + len, " dcd:%d", + seq_printf(m, " dcd:%d", port->icount.dcd); } - strcat(page, "\n"); - len++; sdio_uart_port_put(port); - } - - if (len + begin > off + count) - goto done; - if (len + begin < off) { - begin += len; - len = 0; + seq_putc(m, '\n'); } } - *eof = 1; + return 0; +} -done: - if (off >= len + begin) - return 0; - *start = page + (off - begin); - return (count < begin + len - off) ? count : (begin + len - off); +static int sdio_uart_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, sdio_uart_proc_show, NULL); } +static const struct file_operations sdio_uart_proc_fops = { + .owner = THIS_MODULE, + .open = sdio_uart_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static const struct tty_operations sdio_uart_ops = { .open = sdio_uart_open, .close = sdio_uart_close, @@ -1007,7 +1005,7 @@ static const struct tty_operations sdio_uart_ops = { .break_ctl = sdio_uart_break_ctl, .tiocmget = sdio_uart_tiocmget, .tiocmset = sdio_uart_tiocmset, - .read_proc = sdio_uart_read_proc, + .proc_fops = &sdio_uart_proc_fops, }; static struct tty_driver *sdio_uart_tty_driver; diff --git a/trunk/drivers/mtd/maps/pxa2xx-flash.c b/trunk/drivers/mtd/maps/pxa2xx-flash.c index e9026cb1c5b2..572d32fdf38a 100644 --- a/trunk/drivers/mtd/maps/pxa2xx-flash.c +++ b/trunk/drivers/mtd/maps/pxa2xx-flash.c @@ -117,7 +117,7 @@ static int __init pxa2xx_flash_probe(struct platform_device *pdev) return 0; } -static int __exit pxa2xx_flash_remove(struct platform_device *dev) +static int __devexit pxa2xx_flash_remove(struct platform_device *dev) { struct pxa2xx_flash_info *info = platform_get_drvdata(dev); diff --git a/trunk/drivers/net/Kconfig b/trunk/drivers/net/Kconfig index f062b424704e..16899eee397e 100644 --- a/trunk/drivers/net/Kconfig +++ b/trunk/drivers/net/Kconfig @@ -974,7 +974,7 @@ config ENC28J60_WRITEVERIFY config ETHOC tristate "OpenCores 10/100 Mbps Ethernet MAC support" - depends on NET_ETHERNET + depends on NET_ETHERNET && HAS_IOMEM select MII select PHYLIB help @@ -2547,6 +2547,23 @@ config S2IO More specific information on configuring the driver is in . +config VXGE + tristate "Neterion X3100 Series 10GbE PCIe Server Adapter" + depends on PCI && INET + ---help--- + This driver supports Neterion Inc's X3100 Series 10 GbE PCIe + I/O Virtualized Server Adapter. + More specific information on configuring the driver is in + . + +config VXGE_DEBUG_TRACE_ALL + bool "Enabling All Debug trace statments in driver" + default n + depends on VXGE + ---help--- + Say Y here if you want to enabling all the debug trace statements in + driver. By default only few debug trace statements are enabled. + config MYRI10GE tristate "Myricom Myri-10G Ethernet support" depends on PCI && INET diff --git a/trunk/drivers/net/Makefile b/trunk/drivers/net/Makefile index 98409c9dd445..edc9a0d6171d 100644 --- a/trunk/drivers/net/Makefile +++ b/trunk/drivers/net/Makefile @@ -220,6 +220,7 @@ obj-$(CONFIG_R8169) += r8169.o obj-$(CONFIG_AMD8111_ETH) += amd8111e.o obj-$(CONFIG_IBMVETH) += ibmveth.o obj-$(CONFIG_S2IO) += s2io.o +obj-$(CONFIG_VXGE) += vxge/ obj-$(CONFIG_MYRI10GE) += myri10ge/ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o diff --git a/trunk/drivers/net/dm9000.c b/trunk/drivers/net/dm9000.c index 254ec62b5f58..d8350860c0f8 100644 --- a/trunk/drivers/net/dm9000.c +++ b/trunk/drivers/net/dm9000.c @@ -559,7 +559,7 @@ static void dm9000_show_carrier(board_info_t *db, static void dm9000_poll_work(struct work_struct *w) { - struct delayed_work *dw = container_of(w, struct delayed_work, work); + struct delayed_work *dw = to_delayed_work(w); board_info_t *db = container_of(dw, board_info_t, phy_poll); struct net_device *ndev = db->ndev; diff --git a/trunk/drivers/net/dnet.c b/trunk/drivers/net/dnet.c index db1e31f95200..33fa9eee4cac 100644 --- a/trunk/drivers/net/dnet.c +++ b/trunk/drivers/net/dnet.c @@ -8,7 +8,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/trunk/drivers/net/fec_mpc52xx.c b/trunk/drivers/net/fec_mpc52xx.c index 049b0a7e01f3..8bbe7f617994 100644 --- a/trunk/drivers/net/fec_mpc52xx.c +++ b/trunk/drivers/net/fec_mpc52xx.c @@ -129,7 +129,8 @@ static void mpc52xx_fec_free_rx_buffers(struct net_device *dev, struct bcom_task struct sk_buff *skb; skb = bcom_retrieve_buffer(s, NULL, (struct bcom_bd **)&bd); - dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE); + dma_unmap_single(dev->dev.parent, bd->skb_pa, skb->len, + DMA_FROM_DEVICE); kfree_skb(skb); } } @@ -150,7 +151,7 @@ static int mpc52xx_fec_alloc_rx_buffers(struct net_device *dev, struct bcom_task bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk); bd->status = FEC_RX_BUFFER_SIZE; - bd->skb_pa = dma_map_single(&dev->dev, skb->data, + bd->skb_pa = dma_map_single(dev->dev.parent, skb->data, FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); bcom_submit_next_buffer(rxtsk, skb); @@ -270,15 +271,6 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev) phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN); } -static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv, - struct mii_ioctl_data *mii_data, int cmd) -{ - if (!priv->phydev) - return -ENOTSUPP; - - return phy_mii_ioctl(priv->phydev, mii_data, cmd); -} - static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv) { struct mpc52xx_fec __iomem *fec = priv->fec; @@ -370,7 +362,7 @@ static int mpc52xx_fec_close(struct net_device *dev) * invariant will hold if you make sure that the netif_*_queue() * calls are done at the proper times. */ -static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int mpc52xx_fec_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct mpc52xx_fec_priv *priv = netdev_priv(dev); struct bcom_fec_bd *bd; @@ -378,7 +370,7 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d if (bcom_queue_full(priv->tx_dmatsk)) { if (net_ratelimit()) dev_err(&dev->dev, "transmit queue overrun\n"); - return 1; + return NETDEV_TX_BUSY; } spin_lock_irq(&priv->lock); @@ -388,7 +380,8 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d bcom_prepare_next_buffer(priv->tx_dmatsk); bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC; - bd->skb_pa = dma_map_single(&dev->dev, skb->data, skb->len, DMA_TO_DEVICE); + bd->skb_pa = dma_map_single(dev->dev.parent, skb->data, skb->len, + DMA_TO_DEVICE); bcom_submit_next_buffer(priv->tx_dmatsk, skb); @@ -398,7 +391,7 @@ static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *d spin_unlock_irq(&priv->lock); - return 0; + return NETDEV_TX_OK; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -430,7 +423,8 @@ static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id) struct bcom_fec_bd *bd; skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, (struct bcom_bd **)&bd); - dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_TO_DEVICE); + dma_unmap_single(dev->dev.parent, bd->skb_pa, skb->len, + DMA_TO_DEVICE); dev_kfree_skb_irq(skb); } @@ -455,7 +449,8 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, (struct bcom_bd **)&bd); - dma_unmap_single(&dev->dev, bd->skb_pa, rskb->len, DMA_FROM_DEVICE); + dma_unmap_single(dev->dev.parent, bd->skb_pa, rskb->len, + DMA_FROM_DEVICE); /* Test for errors in received frame */ if (status & BCOM_FEC_RX_BD_ERRORS) { @@ -464,7 +459,8 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) bcom_prepare_next_buffer(priv->rx_dmatsk); bd->status = FEC_RX_BUFFER_SIZE; - bd->skb_pa = dma_map_single(&dev->dev, rskb->data, + bd->skb_pa = dma_map_single(dev->dev.parent, + rskb->data, FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); bcom_submit_next_buffer(priv->rx_dmatsk, rskb); @@ -499,7 +495,7 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) bcom_prepare_next_buffer(priv->rx_dmatsk); bd->status = FEC_RX_BUFFER_SIZE; - bd->skb_pa = dma_map_single(&dev->dev, skb->data, + bd->skb_pa = dma_map_single(dev->dev.parent, skb->data, FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); bcom_submit_next_buffer(priv->rx_dmatsk, skb); @@ -847,12 +843,20 @@ static void mpc52xx_fec_get_drvinfo(struct net_device *dev, static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct mpc52xx_fec_priv *priv = netdev_priv(dev); + + if (!priv->phydev) + return -ENODEV; + return phy_ethtool_gset(priv->phydev, cmd); } static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct mpc52xx_fec_priv *priv = netdev_priv(dev); + + if (!priv->phydev) + return -ENODEV; + return phy_ethtool_sset(priv->phydev, cmd); } @@ -882,9 +886,28 @@ static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct mpc52xx_fec_priv *priv = netdev_priv(dev); - return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd); + if (!priv->phydev) + return -ENOTSUPP; + + return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd); } +static const struct net_device_ops mpc52xx_fec_netdev_ops = { + .ndo_open = mpc52xx_fec_open, + .ndo_stop = mpc52xx_fec_close, + .ndo_start_xmit = mpc52xx_fec_start_xmit, + .ndo_set_multicast_list = mpc52xx_fec_set_multicast_list, + .ndo_set_mac_address = mpc52xx_fec_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = mpc52xx_fec_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_tx_timeout = mpc52xx_fec_tx_timeout, + .ndo_get_stats = mpc52xx_fec_get_stats, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = mpc52xx_fec_poll_controller, +#endif +}; + /* ======================================================================== */ /* OF Driver */ /* ======================================================================== */ @@ -929,22 +952,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) return -EBUSY; /* Init ether ndev with what we have */ - ndev->open = mpc52xx_fec_open; - ndev->stop = mpc52xx_fec_close; - ndev->hard_start_xmit = mpc52xx_fec_hard_start_xmit; - ndev->do_ioctl = mpc52xx_fec_ioctl; + ndev->netdev_ops = &mpc52xx_fec_netdev_ops; ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops; - ndev->get_stats = mpc52xx_fec_get_stats; - ndev->set_mac_address = mpc52xx_fec_set_mac_address; - ndev->set_multicast_list = mpc52xx_fec_set_multicast_list; - ndev->tx_timeout = mpc52xx_fec_tx_timeout; ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; ndev->base_addr = mem.start; -#ifdef CONFIG_NET_POLL_CONTROLLER - ndev->poll_controller = mpc52xx_fec_poll_controller; -#endif - - priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */ spin_lock_init(&priv->lock); diff --git a/trunk/drivers/net/fsl_pq_mdio.c b/trunk/drivers/net/fsl_pq_mdio.c index b3079a5a7f2b..aa1eb88c21fc 100644 --- a/trunk/drivers/net/fsl_pq_mdio.c +++ b/trunk/drivers/net/fsl_pq_mdio.c @@ -204,6 +204,7 @@ void fsl_pq_mdio_bus_name(char *name, struct device_node *np) snprintf(name, MII_BUS_ID_SIZE, "%s@%llx", np->name, (unsigned long long)taddr); } +EXPORT_SYMBOL_GPL(fsl_pq_mdio_bus_name); /* Scan the bus in reverse, looking for an empty spot */ static int fsl_pq_mdio_find_free(struct mii_bus *new_bus) @@ -387,7 +388,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev, * The TBIPHY-only buses will find PHYs at every address, * so we mask them all but the TBI */ - if (!of_device_is_compatible(np, "fsl,gianfar-mdio")) + if (of_device_is_compatible(np, "fsl,gianfar-tbi")) new_bus->phy_mask = ~(1 << tbiaddr); err = mdiobus_register(new_bus); diff --git a/trunk/drivers/net/gianfar.h b/trunk/drivers/net/gianfar.h index dd499d7cde26..0642d52aef5c 100644 --- a/trunk/drivers/net/gianfar.h +++ b/trunk/drivers/net/gianfar.h @@ -45,7 +45,6 @@ #include #include #include -#include /* The maximum number of packets to be handled in one call of gfar_poll */ #define GFAR_DEV_WEIGHT 64 diff --git a/trunk/drivers/net/hamradio/yam.c b/trunk/drivers/net/hamradio/yam.c index 500a40b2afe7..b06691937ce9 100644 --- a/trunk/drivers/net/hamradio/yam.c +++ b/trunk/drivers/net/hamradio/yam.c @@ -55,6 +55,8 @@ #include #include #include +#include +#include #include #include @@ -71,8 +73,6 @@ #include #include -#include "yam9600.h" -#include "yam1200.h" /* --------------------------------------------------------------------- */ @@ -82,6 +82,9 @@ static const char yam_drvinfo[] __initdata = KERN_INFO \ /* --------------------------------------------------------------------- */ +#define FIRMWARE_9600 "yam/9600.bin" +#define FIRMWARE_1200 "yam/1200.bin" + #define YAM_9600 1 #define YAM_1200 2 @@ -342,9 +345,51 @@ static int fpga_write(int iobase, unsigned char wrd) return 0; } -static unsigned char *add_mcs(unsigned char *bits, int bitrate) +/* + * predef should be 0 for loading user defined mcs + * predef should be YAM_1200 for loading predef 1200 mcs + * predef should be YAM_9600 for loading predef 9600 mcs + */ +static unsigned char *add_mcs(unsigned char *bits, int bitrate, + unsigned int predef) { + const char *fw_name[2] = {FIRMWARE_9600, FIRMWARE_1200}; + const struct firmware *fw; + struct platform_device *pdev; struct yam_mcs *p; + int err; + + switch (predef) { + case 0: + fw = NULL; + break; + case YAM_1200: + case YAM_9600: + predef--; + pdev = platform_device_register_simple("yam", 0, NULL, 0); + if (IS_ERR(pdev)) { + printk(KERN_ERR "yam: Failed to register firmware\n"); + return NULL; + } + err = request_firmware(&fw, fw_name[predef], &pdev->dev); + platform_device_unregister(pdev); + if (err) { + printk(KERN_ERR "Failed to load firmware \"%s\"\n", + fw_name[predef]); + return NULL; + } + if (fw->size != YAM_FPGA_SIZE) { + printk(KERN_ERR "Bogus length %zu in firmware \"%s\"\n", + fw->size, fw_name[predef]); + release_firmware(fw); + return NULL; + } + bits = (unsigned char *)fw->data; + break; + default: + printk(KERN_ERR "yam: Invalid predef number %u\n", predef); + return NULL; + } /* If it already exists, replace the bit data */ p = yam_data; @@ -359,6 +404,7 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate) /* Allocate a new mcs */ if ((p = kmalloc(sizeof(struct yam_mcs), GFP_KERNEL)) == NULL) { printk(KERN_WARNING "YAM: no memory to allocate mcs\n"); + release_firmware(fw); return NULL; } memcpy(p->bits, bits, YAM_FPGA_SIZE); @@ -366,6 +412,7 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate) p->next = yam_data; yam_data = p; + release_firmware(fw); return p->bits; } @@ -383,9 +430,11 @@ static unsigned char *get_mcs(int bitrate) /* Load predefined mcs data */ switch (bitrate) { case 1200: - return add_mcs(bits_1200, bitrate); + /* setting predef as YAM_1200 for loading predef 1200 mcs */ + return add_mcs(NULL, bitrate, YAM_1200); default: - return add_mcs(bits_9600, bitrate); + /* setting predef as YAM_9600 for loading predef 9600 mcs */ + return add_mcs(NULL, bitrate, YAM_9600); } } @@ -936,7 +985,8 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) kfree(ym); return -EINVAL; } - add_mcs(ym->bits, ym->bitrate); + /* setting predef as 0 for loading userdefined mcs data */ + add_mcs(ym->bits, ym->bitrate, 0); kfree(ym); break; @@ -1159,6 +1209,8 @@ static void __exit yam_cleanup_driver(void) MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr"); MODULE_DESCRIPTION("Yam amateur radio modem driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(FIRMWARE_1200); +MODULE_FIRMWARE(FIRMWARE_9600); module_init(yam_init_driver); module_exit(yam_cleanup_driver); diff --git a/trunk/drivers/net/hamradio/yam1200.h b/trunk/drivers/net/hamradio/yam1200.h deleted file mode 100644 index 53ca8a3903a7..000000000000 --- a/trunk/drivers/net/hamradio/yam1200.h +++ /dev/null @@ -1,343 +0,0 @@ -/* - * - * File yam1k2b5.mcs converted to h format by mcs2h - * - * (C) F6FBB 1998 - * - * Tue Aug 25 20:24:08 1998 - * - */ - -static unsigned char bits_1200[]= { -0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xf3,0xcb,0xff,0xdb,0xfc,0xf2, -0xff,0xf6,0xff,0x3c,0xbf,0xfd,0xbf,0xdf,0x6e,0x3f,0x6f,0xf1,0x7d,0xb4,0xfd,0xbf, -0xdf,0x6f,0x3f,0x6f,0xf7,0x0b,0xff,0xdb,0xfd,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff, -0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xef,0xff,0xff,0xff, -0xfd,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xbf, -0xff,0xff,0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfc,0xff,0xfe,0xff,0xff,0xff,0xf0, -0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xf1,0xff,0xff,0xfe,0x7f,0xbf,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xff,0xff,0xf0,0x9f, -0xff,0xff,0xff,0xfe,0xff,0xfd,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xff, -0xff,0xff,0xfb,0xff,0xfb,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xf7,0xff,0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xf0,0x5f,0xff, -0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xbf,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xfb,0xfe,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, -0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb, -0xff,0xff,0xff,0xfd,0xff,0xbf,0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xfb, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff, -0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xf7,0xff,0xff,0xf1,0xff,0xff,0xf7,0xbf,0xe7,0xff,0xff,0xff,0xff,0xfb, -0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdb, -0xff,0xff,0xf5,0xa5,0xfd,0x4b,0x6e,0xef,0x33,0x32,0xdd,0xd3,0x4a,0xd6,0x92,0xfe, -0xb3,0x3f,0xbd,0xf1,0xfa,0xdb,0xfe,0xf7,0xf6,0x96,0xbd,0xbd,0xff,0xbd,0xff,0xed, -0x7f,0x6b,0x7f,0xfb,0xdf,0xfe,0xfb,0xfe,0x90,0xcf,0xff,0xff,0xff,0xfe,0xbe,0xef, -0xff,0xff,0xdb,0x5f,0xf6,0xff,0xf6,0x8f,0xfd,0xa5,0xdd,0xff,0xff,0xff,0xff,0x6f, -0x7f,0xdb,0xf1,0xfc,0xbf,0xff,0x6f,0xff,0xef,0xfc,0x5b,0x5d,0xda,0xdf,0xf4,0xff, -0xf2,0xff,0xfd,0xbf,0xff,0xff,0xff,0xd0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, -0xff,0xfb,0xef,0xb7,0xfc,0x33,0xff,0xfb,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0, -0x0f,0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x72,0x0f,0xf1,0x6f,0xff,0xfe,0x94,0x3f, -0xff,0xff,0xff,0x7b,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf0, -0xf7,0xef,0xb7,0xfc,0x33,0xff,0xff,0xff,0x04,0x6a,0xf3,0x3c,0x36,0xff,0xf0,0x0f, -0xf1,0x0f,0xff,0xff,0xff,0xf3,0x15,0x73,0x8f,0xf2,0x6f,0xff,0xfe,0x94,0x3f,0xff, -0xff,0xff,0x7d,0x9f,0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x9e, -0xff,0xfc,0xef,0xd3,0xfb,0xff,0x7f,0xf5,0x5f,0xfe,0x59,0xff,0xff,0xff,0xfc,0xf1, -0xfe,0x7f,0xff,0xff,0xfa,0x17,0xff,0xe7,0xef,0xef,0xff,0xff,0x3f,0xf1,0xff,0xff, -0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xfc,0xea, -0xff,0xf0,0xff,0xff,0xbf,0xf9,0x3f,0xb1,0xef,0xff,0xd7,0xff,0xfb,0xff,0xf0,0xff, -0xff,0xf3,0xff,0xdf,0xff,0x7b,0xff,0xfd,0xff,0xf6,0xff,0xbf,0xff,0xff,0xbf,0xff, -0xff,0xff,0xda,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x01,0x00,0x00,0x02,0x02, -0x02,0x02,0x00,0x40,0x40,0x40,0x10,0x00,0x00,0x00,0x20,0x00,0x00,0x01,0x00,0x00, -0x00,0x00,0x00,0x00,0x19,0x00,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10, -0x00,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfb,0xff,0xfd,0xff, -0xff,0x7f,0xff,0xff,0xbf,0xff,0xef,0xff,0xff,0xfd,0xff,0xff,0xf1,0xff,0xdf,0xff, -0xff,0xff,0xff,0xff,0xff,0xbf,0xfe,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xdf, -0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xdf,0xff,0x7f,0xff,0xff,0xff,0xff, -0xdf,0xdf,0xff,0xef,0xff,0x9e,0xef,0xff,0xff,0x7f,0xff,0xf1,0xef,0xff,0xff,0xff, -0xf7,0xfa,0xbf,0xff,0xff,0xfe,0x47,0xef,0xff,0xbd,0xf6,0xff,0xff,0xdf,0xf5,0xf0, -0xf0,0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x01,0x02,0x08, -0x16,0x00,0x00,0x00,0x80,0x00,0x01,0x02,0x00,0x80,0x01,0x0c,0x02,0x00,0x00,0x01, -0x00,0x00,0x20,0x00,0x00,0x06,0x00,0x20,0x00,0x10,0x00,0x14,0x00,0x04,0xc1,0xf0, -0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f, -0xec,0xff,0xff,0xfa,0xff,0xbf,0xff,0x6f,0xff,0xe1,0xff,0xff,0xff,0xff,0xbd,0xfe, -0x46,0xff,0xef,0x7f,0xcd,0xdf,0xff,0xff,0xfd,0xff,0xbd,0xff,0x7f,0x7f,0xf0,0x4f, -0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff, -0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa4,0xbc,0xcd,0x6d,0x6b,0x6f,0x5b,0xdc,0x33, -0x5a,0xf6,0xf7,0xf6,0xb3,0x3f,0xbd,0xc1,0xfa,0x5a,0xf6,0xf6,0xb6,0xf7,0xff,0xbd, -0xbb,0x3c,0xce,0xcf,0x34,0xef,0x33,0xbb,0xcc,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff, -0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xd6,0xff,0xfd,0xfd,0xbf,0xff,0xad, -0xbf,0xf9,0x7f,0x6f,0xfc,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0xff,0xda,0xdb,0xfc, -0xdb,0xff,0x76,0x8f,0xf6,0xff,0xcd,0xab,0xfe,0xfb,0xff,0xd0,0xff,0xff,0xff,0xff, -0xfe,0xff,0x9f,0xff,0xf4,0x20,0xaf,0x6d,0x0b,0xc1,0x7b,0xff,0xff,0xff,0xcb,0xff, -0x3f,0xf0,0xef,0x7f,0x0f,0xf1,0xc3,0x3c,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x0b, -0x1d,0x6a,0x64,0x05,0x6b,0x99,0x01,0xff,0xfd,0xef,0xf0,0x2f,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xf4,0x00,0x2f,0xcc,0x0b,0xc3,0x7f,0xff,0xff,0xff,0x0a,0xdf,0xbf, -0xfd,0x7f,0xff,0xff,0xf1,0xc3,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x4a,0x0e, -0x96,0x64,0x02,0x97,0x99,0x10,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff, -0xff,0xff,0xfe,0x84,0xf9,0xd5,0x27,0xf1,0x7f,0xff,0xf8,0xeb,0xdf,0xf3,0xcf,0x3f, -0x1f,0xff,0xf7,0x11,0xff,0xcf,0xff,0xfe,0x67,0xff,0xff,0xff,0xff,0xc4,0xff,0xff, -0xb3,0xa1,0xff,0xf9,0xe0,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff, -0xff,0xfb,0x7f,0xe0,0xff,0xc7,0xfe,0x7f,0x3f,0xff,0xfd,0x77,0x8d,0x7f,0x0f,0xff, -0xc3,0xff,0xf1,0xbf,0x8f,0xcf,0xff,0xff,0xdd,0x7b,0xff,0xf6,0xfa,0xf7,0xff,0x40, -0x9f,0xf9,0x7f,0xd8,0xff,0xff,0xfa,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00, -0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x10,0x00,0x00,0x10, -0x00,0x01,0x00,0x10,0x20,0x20,0x00,0x00,0x10,0x00,0x04,0x01,0x05,0x00,0x00,0x00, -0x00,0x40,0x40,0x00,0x00,0x3c,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff, -0xff,0xff,0xfe,0x7f,0x7f,0xff,0xef,0xff,0xff,0xdf,0xff,0xff,0xdf,0xff,0xef,0xf7, -0xf1,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xfc,0xfd,0xff,0x7f, -0x7e,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0xff,0xff, -0xff,0xff,0xfe,0xeb,0xfd,0x6f,0xff,0xf7,0xfe,0xf5,0x7f,0xff,0xff,0x7f,0xbf,0xb1, -0xff,0xff,0x9f,0xbf,0xfb,0xff,0xfe,0xff,0xfe,0xff,0xf7,0xeb,0xdf,0xbf,0x5f,0xdd, -0xff,0xdb,0xfd,0xd0,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x00,0x42,0x00, -0x00,0x00,0x30,0x18,0x04,0x08,0x09,0x21,0x82,0x80,0x02,0x00,0x08,0x00,0x01,0x00, -0x00,0x00,0x0c,0x20,0x10,0x00,0x11,0x00,0x44,0x84,0x00,0x20,0x20,0x84,0x80,0x00, -0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xf7,0xff,0xfb,0xdd,0xf9,0xff, -0xda,0xff,0xdc,0xdd,0xfc,0xfb,0xff,0xbf,0xfb,0x3e,0xd7,0x96,0xfe,0x61,0xf7,0xff, -0x7f,0xff,0x3f,0xfd,0xff,0xdf,0xcf,0xf7,0xdf,0xf7,0xbf,0xfd,0xff,0xfe,0xef,0xef, -0xfe,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf3,0xbd,0xfd,0x4b,0x74,0xcf, -0x73,0x5b,0xcb,0x3b,0xdf,0xfe,0xf7,0xfe,0xd3,0x75,0xac,0xa1,0xfb,0xdf,0xfe,0xf7, -0x76,0x96,0xb5,0x24,0xbd,0xa5,0xad,0x49,0x2f,0x69,0x2b,0x52,0x5b,0xbd,0xff,0xff, -0xf0,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0xff,0xcc, -0xa7,0xfb,0xad,0xff,0x7f,0x6f,0xff,0x6d,0x7f,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff, -0x6f,0xff,0xdb,0xff,0xdb,0xff,0xf6,0x97,0xf6,0xff,0xb5,0xb5,0xff,0xff,0xff,0xd0, -0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xa5,0xbc,0x43,0xfc,0x7c,0x03,0xe7, -0xff,0xff,0x20,0xff,0xff,0xff,0xcc,0xfd,0x7d,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59, -0xba,0x56,0x66,0x6a,0xad,0x9a,0xa9,0x9a,0x97,0xa5,0xaa,0xbb,0xff,0xff,0xf0,0x0f, -0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xfd,0xf7,0xfd,0x43,0xff,0xfd,0x6b,0xe7,0xff, -0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0x3f,0xf1,0xff,0xff,0xff,0xff,0xd5,0x59,0xb5, -0xa6,0x66,0x6a,0xad,0x9a,0xa9,0x99,0x6b,0x5a,0xaa,0xff,0xff,0xb7,0xf0,0x3f,0xff, -0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x9c,0xf7,0xfd,0xd2,0x41,0xff,0xff,0xf2,0x7f, -0x8f,0xff,0xff,0x3d,0xf3,0xff,0x17,0xf1,0xff,0xff,0xff,0xff,0xff,0x7f,0xdf,0xfc, -0x8f,0x38,0xff,0xef,0x23,0xff,0xfb,0xf7,0xc8,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff, -0xff,0xfe,0xf5,0x7f,0xff,0xfd,0xff,0xe4,0xff,0xeb,0xff,0xcf,0xbf,0xfa,0xff,0xab, -0xef,0xff,0xfb,0xff,0xf3,0xfd,0x61,0xff,0xff,0xff,0xff,0xfa,0xff,0xfb,0xfd,0x0d, -0xff,0xfe,0xff,0x43,0x7f,0xfe,0xbf,0xd0,0xfd,0xff,0xfa,0xf0,0x3f,0xff,0xff,0xff, -0xfe,0xf3,0xc0,0x00,0x00,0x00,0x02,0x00,0x02,0x01,0x00,0x60,0xc0,0x40,0x00,0x00, -0x00,0x00,0x34,0x04,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x88,0x00, -0x00,0x03,0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x3c,0xf0,0x3f,0xff,0xff,0xff,0xfe, -0xfd,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfd,0xff, -0xff,0xff,0xff,0xfe,0xfe,0x5f,0xff,0xff,0xcb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0, -0xff,0xff,0xfd,0xff,0xef,0xe3,0xde,0xee,0xd9,0xc5,0x93,0xff,0xff,0xfe,0xfe,0xff, -0xfb,0xee,0xfe,0xf1,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xbf,0xf7,0xff,0xff,0x7f, -0xaf,0xbd,0xdf,0xdf,0xfb,0xf3,0xf3,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x34, -0x00,0x06,0x61,0x00,0x18,0x01,0xa0,0x05,0x17,0x00,0x20,0x05,0x28,0x20,0x00,0x00, -0x05,0x00,0x41,0x00,0x00,0x40,0x00,0x09,0x00,0x01,0x20,0x86,0x82,0x08,0x40,0x03, -0x80,0x30,0x70,0x08,0x14,0x02,0xc1,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, -0xff,0xff,0xbd,0xef,0xfb,0xff,0xff,0xfb,0x9c,0x7f,0xef,0xdf,0xff,0xbf,0xeb,0xde, -0xff,0xc1,0x7f,0xff,0xfb,0x7f,0xff,0xff,0xff,0x5f,0xff,0xff,0xff,0xdf,0xbf,0xef, -0x3f,0xf7,0x8f,0xef,0x7f,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbd, -0xdf,0xef,0x7d,0x6d,0x2b,0x5a,0x5d,0xd2,0xdf,0xf6,0x92,0xb6,0xb2,0xb3,0xac,0xa1, -0xfb,0xdf,0xfe,0xf1,0xee,0xf5,0xf6,0xbc,0x6b,0xbd,0x7d,0xaf,0x1a,0xef,0x5f,0x6b, -0xc6,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff, -0xf6,0xff,0xf6,0xb7,0xfd,0xad,0xfd,0xbf,0xf3,0x6f,0xff,0x6f,0xff,0xdb,0xd1,0xfd, -0xbf,0xff,0x6f,0xf5,0x6b,0xbc,0x5b,0x3c,0xda,0xef,0x16,0xaf,0x16,0xff,0xcd,0xab, -0xff,0x6f,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfc,0xbf,0xff,0xff, -0xff,0x6c,0x03,0x10,0xc1,0xf3,0xff,0xf3,0x3a,0xf3,0xca,0xff,0xaf,0xf1,0xff,0xff, -0xff,0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff, -0xff,0x5f,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff, -0xea,0x0f,0x50,0xc3,0xf3,0x7f,0xff,0xf3,0xf3,0xc3,0xff,0xaf,0xf1,0xff,0xff,0xff, -0xff,0xd9,0x96,0xa6,0x65,0xa6,0x66,0x6a,0x95,0x69,0x69,0x6a,0x5a,0x5a,0xff,0xff, -0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xd7,0xff,0xff,0x5f,0xc1, -0x3f,0xf7,0x5e,0xf5,0xce,0x9e,0x5f,0x3f,0x17,0xff,0xf3,0xe1,0xff,0xff,0xff,0xff, -0xd8,0xff,0xfa,0xfe,0x67,0xff,0xfe,0xbf,0x5a,0xff,0xff,0xaf,0xf5,0xff,0xff,0xff, -0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfd,0xff,0xf7,0xff,0xfd,0x4e,0x3d, -0x3f,0xe7,0x0b,0xbf,0x8f,0xf9,0xff,0xeb,0xe3,0xff,0xe1,0xff,0xff,0xfc,0xff,0xc7, -0x9f,0xff,0x3e,0x39,0xe5,0xff,0xcf,0x9b,0xf9,0xff,0xff,0xc5,0xff,0xff,0xfa,0xf0, -0x5f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, -0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x20,0x00,0x20, -0x00,0x01,0x10,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0xf0,0x4f, -0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xbf, -0x3f,0xff,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf1,0xff,0xff,0xff,0xff,0xf7,0xff,0xf7, -0xff,0xed,0xff,0xfb,0xfe,0xff,0x7f,0xff,0x7f,0xdf,0xff,0xff,0xdd,0xf0,0x3f,0xff, -0xff,0xff,0xfe,0xf0,0xff,0xff,0xf3,0xff,0xf7,0xff,0xfe,0x5f,0xff,0xf7,0xff,0xff, -0xdf,0xff,0xff,0xff,0xf7,0xfe,0x7b,0xf1,0xff,0xfd,0xfd,0xff,0xdf,0xdf,0xff,0x7d, -0x73,0xf9,0xff,0xc3,0x7e,0xfe,0xff,0xef,0xd7,0xff,0xcf,0xd0,0xf0,0x6f,0xff,0xff, -0xff,0xfe,0xf8,0x30,0x00,0x00,0x40,0x04,0x00,0x01,0x41,0x20,0x00,0x04,0x00,0x02, -0xd5,0x09,0x00,0x02,0x80,0x02,0x01,0x00,0x00,0x00,0x0a,0x04,0x00,0x07,0x00,0x01, -0x50,0x01,0x80,0x02,0x61,0x40,0x41,0x0c,0x14,0x08,0xc1,0xf0,0x9f,0xff,0xff,0xff, -0xfe,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0xdf,0xcb,0x5f,0xfe,0xef,0xff,0xfe, -0xff,0x3f,0xff,0x7f,0xfd,0xc1,0xff,0xff,0x7f,0xff,0xdf,0xfd,0xfc,0xfd,0xf7,0xee, -0xff,0xff,0x4e,0xff,0xdf,0xcf,0xdb,0xeb,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0x7f, -0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff, -0xf7,0xfb,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0x7f,0xff,0xff,0xff,0x7f,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xdd,0xff, -0xff,0xff,0xa5,0xff,0x6f,0x6b,0xe9,0x6f,0xda,0xca,0xfb,0xdd,0xee,0xf7,0xf6,0xb2, -0xb3,0xa4,0xa1,0x5b,0x5b,0xf6,0xd7,0xf4,0xf7,0x7b,0xbd,0xbd,0xad,0xcf,0xef,0x7f, -0x6b,0x7f,0x3b,0xdf,0xdb,0xff,0xff,0x30,0xcf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, -0xff,0xff,0xff,0xf6,0xfe,0x96,0xff,0xfd,0xb5,0xfd,0xbf,0xad,0x7f,0xff,0x6f,0xff, -0xde,0xd1,0xad,0xad,0xe9,0xff,0xf1,0xec,0xef,0xde,0x3f,0xcb,0xff,0xf6,0xff,0x32, -0xff,0xc5,0xbd,0xff,0xff,0xff,0xd0,0xbf,0xff,0xff,0xff,0xfe,0xfe,0xfb,0xff,0xf4, -0x28,0xbf,0xff,0xfd,0xfb,0xd3,0xff,0xff,0x42,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3, -0xc1,0xff,0x33,0xff,0xc0,0x15,0x6b,0x70,0xff,0xf0,0xf2,0x4f,0xff,0xfc,0x3e,0x97, -0x3c,0xff,0xff,0xfd,0xef,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfe,0x78, -0xbf,0xff,0xfd,0xf3,0xef,0x55,0xff,0x7e,0xff,0xff,0xff,0xea,0xb3,0xfc,0xc3,0xc1, -0xff,0x33,0xff,0xc0,0x15,0x6f,0xff,0x0f,0xf0,0xf0,0x0f,0xff,0xfc,0x3d,0x6b,0xc3, -0xff,0xff,0xfe,0xf7,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff, -0xff,0x23,0xf8,0x7f,0xff,0x4e,0xff,0xff,0xff,0xfb,0xf9,0x17,0xff,0xf6,0xf1,0xff, -0xcf,0xef,0xff,0xff,0x13,0xdf,0xe6,0x2f,0xc7,0xff,0xff,0xe7,0xc1,0xfd,0xff,0xfe, -0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xfe,0xae,0xff, -0xff,0x7f,0x3b,0x3f,0xfc,0x7f,0xfc,0xef,0xff,0xfc,0xe2,0x7b,0xff,0xf1,0xfd,0xed, -0xef,0xff,0xff,0x35,0x73,0xff,0xff,0xfe,0xfa,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, -0xff,0xfa,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x80,0x00,0x00,0x40,0x00,0x00,0x00,0x0c,0x04,0x01,0x40,0x40,0x00, -0x00,0x30,0x28,0x04,0x00,0x08,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00, -0x38,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xfb,0xff,0x7f, -0xff,0xff,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xdf,0xdf,0xff, -0xff,0xff,0xff,0xed,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xbf,0xbf,0xff,0xff,0xc3, -0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xbf,0xfd,0xff,0xbf,0xff,0xff,0xfd,0xff,0xff, -0xff,0xff,0xff,0xfd,0x7b,0xff,0x7f,0xff,0xbd,0xff,0xf1,0xef,0xff,0xff,0xfd,0xdf, -0xfd,0xfb,0xff,0xff,0xbf,0xbe,0xff,0xcd,0x7f,0xfc,0xf7,0xf7,0x6f,0xbf,0xd8,0xf0, -0xef,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00,0x00,0x00,0x04,0x00,0x00,0xa0,0x00,0x00, -0xc0,0x00,0x00,0x20,0x34,0x00,0x00,0x00,0x0c,0x81,0x00,0x20,0xa4,0x20,0x00,0x10, -0x08,0x04,0x48,0x08,0x00,0x40,0x93,0x00,0x10,0x00,0x38,0x18,0x20,0xc1,0xf0,0x3f, -0xff,0xff,0xff,0xfe,0xff,0xfb,0xff,0xff,0xb9,0xdf,0xfe,0xb3,0xff,0xff,0xe7,0xfd, -0xff,0xff,0x3b,0xff,0x7f,0xff,0xbf,0xff,0xc1,0xff,0xfc,0xff,0xff,0x3f,0x77,0xfe, -0xfe,0xcf,0xff,0xbf,0xfd,0xbf,0xff,0xfe,0xed,0xf2,0xfd,0xf7,0xff,0xf0,0x2f,0xff, -0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff, -0xff,0xfe,0xff,0xff,0xff,0xf3,0xad,0xcf,0xef,0x70,0xc9,0x73,0x3b,0xdf,0x5b,0x4a, -0xf6,0xb7,0xfe,0xd7,0xf5,0xbc,0xc1,0x33,0xca,0xd6,0xb7,0x6e,0xf7,0xfb,0xbd,0xc5, -0x24,0xcf,0x6f,0x2f,0x4d,0x2b,0xba,0x5a,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff, -0xfe,0xbf,0xff,0xff,0xff,0xff,0xf6,0xf6,0xd7,0xff,0xff,0xad,0xbd,0xff,0xff,0xff, -0xef,0xf7,0x7f,0xfc,0x5b,0xb1,0xfd,0xbd,0x75,0x6f,0xef,0x6a,0xfd,0x5b,0xfb,0xdb, -0x3a,0xbf,0x8e,0x9f,0xff,0xbf,0xfd,0xff,0x6f,0xff,0xd0,0x6f,0xff,0xff,0xff,0xfe, -0xff,0xbb,0xff,0xf0,0x3f,0xff,0xff,0xfd,0xfb,0x7f,0xde,0xff,0xff,0x5a,0xd6,0xbf, -0xd8,0x2a,0xbf,0xbf,0xf1,0xe5,0xff,0xcc,0xc0,0xa9,0x70,0xff,0xf3,0x3c,0x3c,0xfd, -0x57,0xfd,0x98,0x03,0x00,0xc3,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff, -0xff,0xff,0xff,0x3d,0xbf,0xff,0xfd,0xfb,0xff,0xdb,0xff,0xff,0x0f,0xfc,0x3f,0xd8, -0x2a,0xbf,0xbf,0xf1,0xef,0xff,0xcc,0xc0,0x96,0xbe,0xff,0xf3,0x3f,0xff,0xfd,0x57, -0xfd,0x99,0x0f,0xff,0xc3,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xff,0xff, -0xff,0xf1,0xe7,0xff,0xff,0xf3,0x8e,0x7b,0xff,0xa8,0xff,0xdf,0x7f,0x8e,0x78,0x73, -0xff,0xf1,0x51,0x62,0xff,0xfc,0x4b,0xff,0xf3,0xff,0x7e,0xcf,0xf9,0xff,0xfd,0xff, -0xff,0x7f,0xff,0xe0,0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff, -0xfb,0xfd,0xae,0xff,0xfc,0xfe,0x6f,0x3f,0xf8,0xfd,0x77,0xaf,0xfe,0x37,0xfe,0x7b, -0xff,0xb1,0x8c,0xff,0xef,0xfd,0xf8,0xe7,0xbf,0xff,0xf1,0xfe,0x3e,0xf7,0xfe,0x95, -0x3e,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00,0x00, -0x01,0x04,0x00,0x00,0x00,0x00,0x80,0x02,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x08, -0x41,0x80,0x10,0x00,0x00,0x08,0x10,0x84,0x00,0x0c,0x04,0x02,0x61,0x00,0x00,0x81, -0x00,0x00,0x00,0x00,0x3d,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff, -0xff,0xff,0x7f,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, -0x7f,0xbf,0xf7,0x7f,0xef,0xff,0xef,0xff,0xf7,0xfd,0xff,0xff,0xfd,0x7f,0xff,0xbe, -0xdf,0xff,0xff,0xd9,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xff,0x7f,0xfb,0xff, -0xfb,0xff,0xbf,0xff,0xf3,0x7f,0xfb,0xfd,0xeb,0x7f,0xdf,0xfa,0xff,0xde,0xf0,0xed, -0xff,0xb1,0xf7,0xf9,0x1f,0xb5,0x5b,0xfe,0x7e,0xf7,0xbe,0xfd,0x7f,0x5f,0xb5,0xf7, -0xff,0xff,0xd0,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x01,0x00,0x07,0x42,0x01, -0x00,0x6a,0x18,0x50,0x80,0x00,0x00,0x02,0x40,0x01,0x01,0x20,0x01,0x01,0x24,0x14, -0x21,0x10,0x02,0x08,0x07,0x08,0x00,0x40,0x10,0x80,0x58,0x00,0x84,0x80,0x18,0x10, -0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xff,0xdb,0xb7,0xf3, -0xdf,0x7c,0xf8,0x74,0xff,0xff,0x6f,0x7d,0x3f,0x7e,0xec,0x7f,0xc1,0xf5,0xff,0xcf, -0x6f,0x9f,0xf9,0xdf,0xbe,0xe5,0xe7,0xff,0xd7,0xf3,0xdd,0xfb,0xff,0xfc,0xff,0xbf, -0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xf0,0x2f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xff,0xb4,0xcf,0xef,0x77,0x6f,0x73, -0x3a,0x4a,0x3a,0xcb,0xd4,0xf7,0x2e,0xd6,0xbd,0xbd,0xa1,0x3b,0xdf,0xd6,0xf7,0xee, -0xd3,0x35,0xbd,0xfb,0xbd,0xce,0xeb,0x2b,0x4d,0x2f,0xbb,0xda,0xff,0xff,0xfe,0xb0, -0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdf,0x5f,0x36,0xaf,0x3f,0xed,0xb7, -0xf5,0xfd,0xf3,0x2b,0xef,0x77,0xff,0xfb,0xda,0xb1,0xbd,0xa3,0x77,0x69,0x7f,0x4f, -0xff,0xdb,0xfa,0x5b,0xff,0xf2,0xfe,0xff,0x96,0xff,0xff,0xfe,0xdf,0xff,0xd0,0xaf, -0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x8f,0xfd,0x40,0x6f,0x9e,0x83,0x5a,0x0f, -0xfa,0xc3,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xd0,0x00,0xfe,0xbf,0xcd,0x3f,0xf0, -0xef,0xfc,0xc5,0x0c,0x3f,0xfd,0x68,0x0b,0xff,0xff,0xff,0xfe,0xdf,0xf0,0xff,0xff, -0xff,0xff,0xfe,0xff,0xbb,0xff,0xfd,0x85,0xff,0xd4,0x6f,0x9f,0xc3,0x5a,0x0f,0xff, -0xff,0xff,0xff,0xfc,0xe9,0x7f,0xf3,0x01,0xf0,0xfb,0xc2,0xbf,0xfc,0x00,0x37,0xef, -0xfc,0xcd,0xbc,0x3f,0xff,0x0c,0xbf,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff, -0xff,0xfe,0xff,0xff,0xff,0xff,0xd9,0xf7,0xd1,0xb7,0x7e,0x7f,0xf1,0xe4,0xfd,0xff, -0xfb,0xfb,0xff,0x5f,0xff,0x7f,0xb1,0xbc,0x0f,0x67,0xeb,0xb8,0x3f,0xff,0xe2,0xff, -0xe9,0xff,0xfd,0xe3,0xff,0x3f,0x9f,0xc2,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff, -0xfe,0xf5,0x7f,0xff,0xf0,0x3f,0xbc,0xff,0xd5,0xf5,0xce,0x3f,0xfe,0xff,0xfe,0x6d, -0xff,0xf1,0xbf,0x7b,0xff,0xf1,0xfd,0xff,0x4f,0xff,0x87,0xff,0xae,0xff,0xb1,0xf8, -0xfe,0xff,0xff,0x78,0x01,0xb9,0xff,0xff,0xff,0xfa,0xf0,0x2f,0xff,0xff,0xff,0xfe, -0xf3,0xc0,0x00,0x00,0x00,0x04,0x02,0x13,0x02,0x00,0x80,0x40,0x00,0x90,0x10,0x00, -0x10,0x00,0x02,0x00,0x01,0x20,0x80,0x12,0x10,0x00,0x40,0x08,0x00,0x04,0x00,0x00, -0x02,0x00,0x01,0x40,0x00,0x80,0x00,0x00,0x3c,0xf0,0xef,0xff,0xff,0xff,0xfe,0xfd, -0x1f,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xf7,0xdf,0xf7,0xff, -0xf7,0xfb,0xeb,0xd1,0xff,0xff,0xff,0xff,0xef,0xf7,0xff,0xff,0xfb,0xff,0xfe,0xff, -0xff,0x7e,0xff,0xfb,0xff,0xff,0xff,0xdb,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf0,0xff, -0xff,0xb7,0xeb,0xf7,0xdf,0xff,0xfe,0xf5,0x6b,0xe7,0xed,0xf7,0x3e,0xec,0xff,0x54, -0xef,0x6f,0xf1,0xf5,0xaf,0x6f,0xf6,0xfd,0xff,0xdd,0x7b,0xff,0xef,0xbf,0x7f,0xff, -0xff,0xf7,0xff,0xf3,0x5f,0xf7,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x00, -0x80,0x40,0x04,0x00,0x81,0x2c,0x04,0x24,0x00,0x02,0x01,0xc8,0x02,0x00,0x02,0x24, -0x00,0x01,0xb4,0x42,0xdc,0x44,0x02,0x15,0x90,0x02,0x03,0x48,0x39,0x10,0x02,0x24, -0xa0,0xba,0x00,0x00,0x40,0xc1,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, -0xfe,0xfc,0xf7,0xf0,0xee,0xb6,0x5d,0xfd,0xf5,0xff,0xdb,0xf7,0x7f,0x7f,0xbe,0xff, -0xc1,0xfe,0xbf,0xfa,0xfa,0x5f,0xff,0xad,0xff,0xef,0xff,0x7f,0xdf,0x7f,0xfe,0xbf, -0xb7,0x94,0xbf,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xd7,0xff,0xff,0xfb,0xb5,0xff, -0xef,0x7c,0xeb,0x2b,0x52,0x5b,0x3b,0xda,0xd4,0xf3,0x36,0x96,0xb5,0xbd,0xf1,0xfb, -0xda,0xee,0xf6,0xfe,0xd3,0x35,0xbd,0xdf,0xad,0xcf,0xef,0x7e,0xcd,0x6b,0xbb,0xdf, -0xff,0xff,0xfd,0xb0,0xef,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xd3,0x5f,0xf6, -0xff,0xf6,0xff,0xfd,0xad,0xfd,0xff,0x7f,0xef,0xff,0x6f,0x7f,0xdb,0xf1,0xa5,0xa3, -0x7f,0x6f,0x6b,0x4f,0xff,0xdb,0xfb,0xcb,0xff,0xf6,0xff,0xf4,0xd7,0xfd,0xbf,0xfe, -0xdf,0xff,0xd0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdf,0xff,0xff,0xff, -0x3f,0x7f,0xfc,0xe5,0xff,0x20,0xfe,0xff,0xff,0xdf,0x7f,0xff,0xf1,0x7f,0xff,0xfe, -0xff,0xf0,0x7c,0x3d,0x4f,0xf3,0xc3,0x3f,0xff,0xff,0x6f,0xc3,0xff,0x0f,0xff,0xff, -0xaf,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0xb7,0xe0,0x0f,0xff,0xff,0x2b, -0xff,0x7d,0xbf,0xff,0xdf,0xff,0xff,0xf8,0x9f,0x7f,0xff,0xf1,0x55,0xff,0xff,0xff, -0xfd,0x7c,0x3c,0xff,0xf3,0xc3,0x3f,0xff,0xff,0xef,0xc3,0xff,0xdf,0xff,0xff,0xff, -0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0x9f,0xbf,0x7f, -0xf9,0x19,0x47,0x8e,0xe7,0x9f,0x3f,0x17,0xff,0xfc,0x81,0xc1,0x7e,0xf3,0xd9,0xf9, -0x73,0xdf,0xf4,0x7f,0xfa,0xff,0xff,0xff,0xfb,0x7f,0x77,0xc7,0xff,0xff,0xff,0xf0, -0x2f,0xff,0xff,0xff,0xfe,0xf5,0xf7,0xff,0xfb,0xff,0xf7,0x3f,0xfc,0xbf,0x3e,0x3f, -0xec,0xff,0x81,0xaf,0xfe,0x4f,0xf3,0xbb,0xff,0xf0,0x7e,0xff,0x6f,0xff,0x87,0xff, -0xbb,0xff,0xd5,0xfc,0xff,0x7f,0xfc,0x6f,0xff,0xef,0xe7,0xff,0xff,0xfa,0xf0,0x3f, -0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, -0x00,0x30,0x10,0x60,0x20,0x00,0x08,0x00,0x01,0x20,0x80,0x00,0x10,0x00,0x04,0x00, -0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x80,0x40,0x00,0x08,0x20,0x3c,0xf0,0x6f,0xff, -0xff,0xff,0xfe,0xf5,0xbf,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0x7f,0xfe,0x3f,0xff, -0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xf1,0xdf,0xdf,0xff,0xff,0xff,0x7f,0xdf,0xff, -0xfd,0xbd,0xff,0xff,0xff,0xfb,0xdf,0xff,0xff,0xff,0xff,0x5b,0xf0,0xff,0xff,0xff, -0xff,0xfe,0xf0,0xbf,0xbf,0xbf,0xff,0xf7,0xfb,0xff,0xfe,0xee,0xfa,0xff,0xff,0xff, -0x3d,0x3b,0xff,0xff,0xfe,0xfb,0xf1,0xff,0xbf,0x7b,0xff,0xff,0xef,0xff,0xbf,0xff, -0xff,0xff,0xff,0xff,0xfe,0xff,0xf7,0xef,0xff,0xfb,0xd0,0xf0,0xdf,0xff,0xff,0xff, -0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x00,0x0b,0x10,0x05,0x01,0x00,0x08,0x00,0x02, -0x01,0x01,0x00,0x00,0x10,0x01,0xc8,0x08,0x00,0x00,0x00,0x00,0x42,0x02,0x00,0x00, -0x00,0x80,0x02,0x00,0x00,0x40,0x24,0x80,0x00,0xc1,0xf0,0x3f,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xff,0xf7,0xfd,0xf7,0xfa,0xef,0xee,0xf9,0xfd,0xff,0xf7,0xfe,0xbf, -0x1f,0xfd,0x9e,0xfd,0xd1,0xef,0xff,0xf7,0x7f,0x9f,0xff,0xef,0xff,0xf6,0xff,0xfe, -0xfe,0x7b,0xff,0xbd,0xff,0x7e,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xff,0xff, -0xff,0xf7,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xdf,0xfd,0xff,0xff,0xdf,0xff, -0xff,0x5f,0xf1,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xef,0xff, -0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0xfb,0xff,0xff,0xef,0xfb,0xfd, -0xff,0xf1,0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xf7,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0xff,0xe7,0xff, -0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xcf,0xff,0xfb,0xff,0xfb,0xf1, -0xff,0xff,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7b,0xff,0xff,0xff,0x7f,0xff,0xf1,0xff, -0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xef,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x57,0xff,0xfe,0xbf,0xfb,0xf1,0xff,0xff, -0xfd,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xd7,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd, -0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xef,0x2f,0xf1,0x3c,0xbf,0xbc, -0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff, -0x01,0xe2,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff }; diff --git a/trunk/drivers/net/hamradio/yam9600.h b/trunk/drivers/net/hamradio/yam9600.h deleted file mode 100644 index 5ed1fe6ff43e..000000000000 --- a/trunk/drivers/net/hamradio/yam9600.h +++ /dev/null @@ -1,343 +0,0 @@ -/* - * - * File yam111.mcs converted to h format by mcs2h - * - * (C) F6FBB 1998 - * - * Tue Aug 25 20:23:03 1998 - * - */ - -static unsigned char bits_9600[]= { -0xff,0xf2,0x00,0xa5,0xad,0xff,0xfe,0x9f,0xff,0xef,0xfb,0xcb,0xff,0xdb,0xfe,0xf2, -0xff,0xf6,0xff,0x9c,0xbf,0xfd,0xbf,0xef,0x2e,0x3f,0x6f,0xf1,0xfd,0xb4,0xfd,0xbf, -0xff,0x6f,0xff,0x6f,0xff,0x0b,0xff,0xdb,0xff,0xf2,0xff,0xf6,0xff,0xff,0xff,0xff, -0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xfd,0xdf,0xff,0xff,0xff,0xf7,0xff,0xff,0xff, -0xfb,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0x7f,0xf1,0xff,0xfe,0xff,0xbf,0xbf, -0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xff,0xff,0xfe,0xff,0xfe,0xff,0xff,0xff,0xf0, -0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xf7, -0xff,0xff,0xf7,0xef,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0x7e,0xff,0xff, -0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0xdf, -0xff,0xff,0xff,0xfe,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xef,0xff,0xf3,0xfb,0xfe,0xff,0xf1,0xff,0xfd,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xdf,0xff,0xf0,0x7f,0xff, -0xff,0xff,0xfe,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xdf,0xff,0xff,0xff,0xf7,0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff, -0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf5, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff, -0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0xff,0xef,0xff,0x7f,0xff,0xef, -0xff,0xef,0xff,0x7f,0xef,0xf1,0xff,0xef,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xff, -0xff,0xff,0xff,0xbd,0xff,0xef,0x7f,0xef,0x7f,0xfb,0xdf,0xd3,0x5a,0xfe,0xd7,0xd6, -0xf7,0x7f,0xbd,0xf1,0xbb,0x5d,0xd6,0xf7,0xfe,0x96,0xff,0xbd,0xaf,0xad,0xbf,0xef, -0x7f,0x6b,0x7f,0xfb,0xd6,0xfe,0xf7,0xff,0x10,0xef,0xff,0xff,0xff,0xfe,0xbe,0xef, -0xff,0xff,0xdb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xbf,0xff,0x7f,0xff,0x7f, -0xdf,0xdb,0xf1,0xfd,0x35,0xff,0x6f,0xff,0x6f,0xff,0xdb,0xff,0xcb,0xff,0xf6,0xff, -0xf2,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff, -0xff,0xf1,0x24,0xf0,0xff,0xff,0xcf,0xef,0x3f,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f, -0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x55,0xff,0xcc,0xc0,0x3f,0xff,0xff, -0xf1,0x00,0xf0,0xff,0xff,0xcf,0xdf,0xff,0xff,0xf0,0xff,0xff,0xff,0xfc,0x3f,0xff, -0xff,0xff,0x7d,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfe,0x7f,0xdf,0xff,0xff,0xff,0xf1, -0xff,0xcf,0xff,0xf3,0xff,0x97,0xff,0xff,0x8f,0xe7,0xff,0xff,0xfc,0x71,0xff,0xff, -0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xf5,0xff,0xbf,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0xf7,0xef,0xff,0xff,0xfc,0x7b,0xff,0xf1,0x3f, -0xff,0xef,0xff,0xcf,0xe3,0xe3,0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xbf,0xff, -0xbf,0xff,0xda,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf2,0xc0,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00, -0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xdb,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0x9f,0xff, -0xff,0xff,0xf7,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xdb,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf0,0xbb,0xdf,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xfb,0xdf,0xbf,0xf1,0xfe,0xfd,0xf7,0xff, -0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x77,0xfd,0xf2, -0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf8,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03, -0x00,0x00,0x00,0x02,0x00,0x90,0x00,0x00,0x00,0x0c,0x01,0x00,0x00,0x04,0x24,0x00, -0x40,0x01,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x01,0xc0,0xf0, -0x4f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xbf,0xff,0xff,0x6f,0xff,0xdf,0xff,0xd1,0xff,0xfe,0xff,0xff,0xff,0xff, -0xff,0xff,0xdf,0xff,0xfb,0xff,0xfb,0xef,0xff,0xff,0xee,0xff,0xff,0x7f,0xf0,0xdf, -0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff, -0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xad,0xff,0x69,0x2a,0xed,0x6b,0xfb,0xdf,0x3a, -0xdc,0xf4,0x96,0xee,0xb3,0x3d,0x35,0xc1,0xbb,0xdd,0xfe,0xf6,0xfe,0xd6,0xb5,0xad, -0xbf,0xa5,0xad,0x49,0x2f,0x4f,0x2b,0xda,0x5f,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff, -0xff,0xfe,0xbf,0xff,0xff,0xfb,0x5b,0xf7,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xa5, -0xf3,0x6f,0xf3,0x6e,0xfa,0x7b,0xd1,0xfd,0xb5,0x77,0x6f,0xe9,0x6f,0xff,0xdb,0xfb, -0xdb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0x3f,0xfe,0xf7,0xff,0xd0,0x4f,0xff,0xff,0xff, -0xfe,0xff,0x9f,0xff,0xff,0x0f,0xff,0xc0,0x3f,0x9c,0x03,0xff,0xff,0x8b,0xa5,0xfe, -0x80,0x3e,0xc2,0xbf,0xac,0xb1,0x24,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xa3, -0xff,0xfd,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0xaf,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xff,0x0f,0xff,0xc0,0x3f,0xd4,0x6b,0xff,0xff,0xdb,0xff,0xfe,0x86, -0xbf,0xc2,0xbf,0x30,0xa1,0x24,0xff,0xff,0xff,0xff,0xcc,0xff,0x0f,0xff,0xa3,0xff, -0x05,0x6b,0xff,0xff,0xf0,0xa5,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff, -0xff,0xff,0xfb,0xc7,0xff,0xc4,0xff,0xff,0x7f,0xff,0xec,0xfe,0x7f,0xdf,0xd8,0xb9, -0x47,0xfc,0x36,0xc1,0xdf,0xff,0xff,0xf9,0xff,0xf3,0xff,0xf7,0xff,0xfc,0xff,0xfd, -0x3f,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff, -0xff,0xff,0xff,0xfe,0xff,0xff,0x7e,0xbd,0x3f,0xff,0x2b,0xfe,0x2f,0xf5,0xa3,0xfc, -0x5b,0xfe,0x61,0x9f,0x7f,0xef,0xff,0xff,0xa7,0xfb,0xff,0xff,0xfa,0xfe,0xff,0x33, -0xf1,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xf1,0xc0,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x30,0x24,0x04, -0x00,0x01,0x00,0x80,0x40,0x00,0x08,0x00,0x00,0x00,0x02,0x01,0x01,0x00,0x02,0x00, -0x00,0x00,0x00,0x00,0x01,0x3d,0xf0,0x2f,0xff,0xff,0xff,0xfe,0xfd,0xbd,0xff,0xfd, -0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xff,0x7f,0xf6,0xef,0xbf,0xf7,0xff,0x73,0xeb, -0xf1,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,0xf9,0xff,0xfd,0xfe,0xff,0xff, -0xff,0xff,0xff,0xff,0xd9,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf0,0xbf,0x7f,0xff,0xff, -0xff,0x7f,0xff,0xff,0xde,0xff,0xff,0xef,0xdd,0xde,0x77,0xf2,0xfb,0xed,0xe7,0xf1, -0x73,0xfd,0xfd,0xdf,0xff,0x7d,0xbe,0xdf,0xff,0xfb,0xff,0xef,0xff,0xef,0xff,0xff, -0xff,0xff,0xff,0xd0,0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x20,0x02,0x00,0x22, -0x40,0xc0,0x00,0x00,0x00,0x08,0x00,0x02,0x41,0x02,0x12,0x00,0x21,0x87,0x81,0x00, -0x00,0x80,0x04,0x0b,0x28,0x01,0xb0,0x00,0x82,0x00,0x40,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0xc1,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xfd,0xff, -0xf7,0xff,0xfe,0x7f,0xed,0x79,0xff,0xde,0xeb,0x7f,0x74,0xf7,0xf7,0xe1,0xf9,0xff, -0xf6,0x5f,0x7f,0xff,0xff,0xff,0xd7,0xdb,0xef,0xff,0xbb,0xff,0xff,0xff,0xcc,0xff, -0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xf0,0x0f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x3d,0xcd,0x49,0x7f,0x6f, -0x2b,0xba,0x5c,0xd2,0xda,0xf6,0xf3,0x3e,0xf7,0xff,0xbd,0xf1,0xfa,0xdf,0xfe,0xf7, -0xcc,0xf6,0xbb,0xa5,0xb3,0xad,0xbf,0x6f,0x7d,0x6f,0x6b,0xdb,0xdf,0xbd,0xff,0xfe, -0xb0,0x5f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xfb,0xdb,0x57,0xf6,0xfe,0x9f,0xd5, -0xb7,0xff,0xaf,0xe5,0x3f,0xff,0xff,0x6f,0xff,0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0x69, -0x6c,0xdf,0xda,0xdf,0xcb,0xff,0xf6,0xff,0x76,0xfd,0xfd,0xbf,0xff,0xff,0xff,0xd0, -0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfd,0xbd,0x08,0x03,0x89,0x4f,0x5a, -0x0f,0xf0,0xff,0xf8,0xbf,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xf3, -0xfa,0xa0,0xf0,0xf2,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff, -0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xfd,0x00,0x6b,0xff,0xff,0x5a,0x0f, -0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff,0xff,0xb3,0xf5, -0x50,0xf0,0xf0,0xff,0xff,0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff, -0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0xbc,0xff,0xe4,0xe7,0x71,0xff,0xf9,0xc4,0xf4, -0x7f,0x7f,0xcf,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xfb,0xf7,0x73,0xbf,0x14, -0xff,0xe6,0xff,0xff,0xe1,0x7d,0xff,0xff,0xe7,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff, -0xff,0xfe,0xf5,0xff,0xff,0xfe,0xd2,0xfa,0xff,0xc4,0xf4,0x5c,0xbf,0xfa,0xff,0xff, -0xec,0x7e,0xbf,0xff,0xff,0xff,0xf1,0xff,0xff,0xef,0xff,0xff,0x6b,0xdb,0xff,0xdf, -0xf9,0xfb,0xbf,0xff,0xf1,0xff,0xbf,0xff,0xff,0xff,0xfb,0xf0,0xbf,0xff,0xff,0xff, -0xfe,0xf3,0xc0,0x00,0x02,0x00,0x00,0x00,0x00,0x82,0x00,0x00,0x00,0x00,0x80,0x00, -0x00,0x00,0x00,0x40,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x20,0x00,0x00,0x00,0x00, -0x01,0x00,0x01,0x00,0x00,0x80,0x02,0x00,0x01,0x3c,0xf0,0x5f,0xff,0xff,0xff,0xfe, -0xfd,0xbf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0x7f,0xff,0xdf,0xff,0xef,0xff, -0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff, -0xff,0xff,0xff,0xff,0xff,0xfd,0xff,0xff,0xc3,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf0, -0xff,0xdf,0xff,0xff,0xf7,0x23,0xff,0xff,0xfd,0xff,0xef,0xff,0xfe,0x7f,0x7d,0xf7, -0xfe,0xff,0x7f,0x71,0xff,0xfb,0x7f,0xff,0xff,0xff,0x6e,0xfd,0xf7,0xfd,0xff,0xbf, -0xff,0xbf,0xf9,0xfd,0xff,0xdf,0xef,0xf0,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xf8,0x30, -0x40,0x01,0x00,0x83,0x00,0x00,0x00,0x0c,0x06,0x08,0x04,0x26,0x26,0x00,0x00,0x06, -0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x70,0x08,0x80,0x00,0x20,0x01,0x20, -0x00,0x02,0x00,0x30,0x00,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, -0xff,0xff,0x7b,0x3f,0xf7,0xff,0xd7,0xfe,0xfe,0xfb,0xfe,0x3b,0xfe,0xbd,0xff,0x2f, -0xff,0x71,0xff,0xfb,0x7f,0xe7,0xff,0xf9,0xef,0xff,0xd7,0xfa,0xff,0xb7,0xbb,0xfe, -0xff,0xff,0x74,0xff,0xf7,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xb5, -0xbd,0x6f,0x7c,0xeb,0x7f,0xfb,0xdb,0xd3,0x4b,0xee,0xd6,0xf6,0xb7,0xfd,0xac,0xa1, -0xfb,0xdf,0xfe,0xf7,0xf4,0x96,0xbd,0xb4,0xc5,0xa5,0xaf,0x6f,0x69,0x4f,0x7f,0xba, -0xdb,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff, -0xf6,0xff,0xf6,0xff,0xbd,0xbf,0xa5,0xbf,0xff,0x7d,0x7f,0xef,0xff,0xfb,0xf1,0xfd, -0xbf,0xff,0x6f,0xff,0x6b,0x7a,0xdb,0xff,0xdb,0xdf,0xf6,0xfe,0xb6,0xfd,0xfd,0xbf, -0xfe,0xf7,0xff,0xd0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xf4,0x2f,0xff, -0xfc,0x43,0x6b,0xff,0xff,0xff,0x0d,0xff,0xfc,0x33,0x3f,0xf0,0x5f,0xf1,0xff,0xff, -0xff,0xff,0xf9,0xde,0xf0,0x4c,0xfe,0x77,0xaf,0xff,0xff,0xef,0xff,0xf0,0xff,0xdb, -0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xfe,0xf7,0xff,0xf0,0x2f,0xff,0xfd, -0x43,0x7f,0xff,0xff,0xf1,0x0f,0xff,0xfc,0x33,0x3f,0xff,0xaf,0xf1,0xff,0xff,0xff, -0xff,0xf6,0xd7,0xff,0xbc,0xfd,0xbd,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff, -0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xfb,0xf1, -0xbf,0xff,0xf9,0xfd,0xcf,0xf2,0x70,0xff,0x1f,0x9f,0xf3,0xf1,0xff,0xff,0xff,0xff, -0xfc,0xf7,0xff,0x13,0x9f,0xfc,0xff,0xff,0x84,0xf7,0xff,0xff,0x47,0xff,0xff,0xff, -0xf0,0xbf,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xf1,0xfc,0xff,0xfe,0xfe,0x79, -0x3f,0xff,0x1d,0x46,0xcf,0xff,0xcf,0xfc,0x7b,0xff,0xf1,0xff,0xff,0xff,0xff,0xed, -0xf3,0xab,0xff,0xcb,0xff,0xf8,0xff,0xfc,0xf5,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0, -0x8f,0xff,0xff,0xff,0xfe,0xf3,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00, -0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x04,0x08,0x01,0x00,0x00,0x00,0x00,0x00,0x20, -0x0c,0x00,0x00,0x04,0x01,0x00,0x01,0x00,0x00,0x80,0x00,0x00,0x01,0x3c,0xf0,0x7f, -0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xfd,0xfe,0xff,0xff,0xff,0xff,0xfe,0xff, -0xdf,0xff,0xff,0xf7,0xff,0xff,0xff,0xef,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xeb, -0xff,0xdf,0xff,0xff,0xfb,0xf7,0x7f,0xff,0xfe,0xff,0xff,0xbf,0xdb,0xf0,0xff,0xff, -0xff,0xff,0xfe,0xf0,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0x7f,0xf7,0xff, -0xbf,0xbf,0xcf,0xff,0xff,0xff,0x3e,0xf1,0x7f,0xff,0xff,0xef,0xff,0xff,0xff,0xfe, -0xff,0xfd,0xff,0xbf,0xbd,0xfe,0xff,0xfb,0xf7,0xdf,0xfb,0xd0,0xf0,0x9f,0xff,0xff, -0xff,0xfe,0xf8,0x30,0x20,0x00,0x40,0x01,0x80,0xc0,0x30,0x00,0x00,0x20,0x00,0x10, -0x50,0x88,0x20,0x00,0x00,0x13,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00, -0x00,0x00,0x01,0x80,0x08,0x00,0x00,0xa0,0x00,0x10,0xc1,0xf0,0xef,0xff,0xff,0xff, -0xfe,0xfd,0xef,0x7f,0xff,0xff,0xbf,0xff,0xf7,0xff,0xef,0xfb,0xfd,0x77,0xef,0xbf, -0xf7,0x7f,0xff,0xff,0xbf,0xd1,0x7f,0xff,0xff,0xf7,0xff,0xff,0xff,0xff,0xaf,0xff, -0xdf,0xf7,0xfb,0xff,0xfd,0xff,0xfc,0xff,0xfd,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff, -0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x3f,0xff,0xff,0xff,0xfe,0xdd,0xff, -0xff,0xff,0xa5,0xfd,0x6f,0x7d,0x6d,0x7f,0x52,0xdf,0x5a,0x4b,0xee,0xb6,0xee,0xf2, -0xbb,0xac,0xa1,0x5b,0x4d,0xd6,0xf7,0xfe,0xb2,0xbd,0x35,0xb5,0xb5,0xdd,0x6f,0x7f, -0xe9,0x5f,0x52,0xdf,0xbd,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff, -0xff,0xdb,0xfe,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfd,0xb5,0xbf,0xf9,0x7f,0x6f,0xff, -0xdb,0xf1,0xfd,0xbf,0xff,0x6f,0xff,0x69,0x7f,0xdb,0xff,0xd3,0xff,0xf6,0xfe,0xf2, -0xff,0xad,0xbf,0xff,0xff,0xff,0xd0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5, -0x30,0x0f,0xff,0xff,0xfd,0x6b,0xca,0xff,0xf0,0x0f,0xd6,0xbf,0xcf,0x3f,0xff,0xff, -0xf1,0xff,0xff,0xff,0xca,0xfe,0xbf,0xff,0xf0,0x05,0xaf,0x0f,0xff,0xfc,0xf0,0xcf, -0xf0,0xff,0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0x30, -0x0f,0xff,0xff,0xfc,0x3f,0xca,0xff,0x0f,0x0f,0xd6,0xbf,0xff,0xff,0xf5,0x5f,0xf1, -0xff,0x8b,0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,0xfc,0xf0,0xcf,0xf0, -0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xcf,0xff, -0xff,0xbf,0x9f,0x3f,0xfe,0xfc,0xff,0x4f,0xff,0xff,0xff,0xff,0xff,0xf7,0xf1,0xff, -0xdf,0xfe,0x7e,0x3f,0x9f,0xf4,0xfc,0x7f,0xfc,0xff,0xff,0x3f,0xff,0x3f,0xfe,0x3f, -0xff,0xff,0xff,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xfb,0xff,0xfe,0xff, -0xff,0xff,0xff,0xbf,0xfb,0xff,0xf8,0xed,0xff,0x8f,0xff,0xbb,0xff,0xb1,0xf3,0xef, -0x8f,0xf7,0xff,0xff,0xdb,0xff,0xff,0xff,0xef,0xbf,0xfd,0x79,0xbf,0xbf,0xff,0xff, -0xff,0xfb,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x00,0x04,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x04,0x08,0x08,0x01,0x01,0x00,0x90, -0x00,0x00,0x00,0x04,0x00,0x08,0x00,0x00,0x00,0x00,0x08,0x00,0x04,0x00,0x00,0x01, -0x3c,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0x9f,0xff,0xaf,0xdf,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, -0xbf,0xef,0xff,0xff,0xff,0xed,0xff,0xff,0xff,0xef,0xff,0xbf,0xff,0xff,0xff,0xc3, -0xf0,0x3f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xfd,0xff,0xff,0xff,0xfb,0xff,0xbb,0xff, -0xff,0xff,0x7f,0xf6,0xff,0x7f,0xfb,0xfd,0xed,0xff,0xf1,0xff,0xfe,0x7f,0xff,0xff, -0xff,0x5f,0xff,0xf7,0xff,0x7e,0xff,0xfd,0xff,0xef,0xff,0xff,0xff,0xef,0xf0,0xf0, -0x8f,0xff,0xff,0xff,0xfe,0xf8,0x30,0x80,0x00,0x04,0x00,0x00,0x40,0x02,0x00,0x03, -0x00,0x05,0x04,0x20,0x00,0x00,0x01,0xd0,0x00,0x81,0x00,0x20,0x04,0x04,0x00,0x00, -0x81,0x04,0x08,0x80,0x10,0x00,0xc0,0x00,0x00,0x00,0x20,0x00,0x08,0xc1,0xf0,0x6f, -0xff,0xff,0xff,0xfe,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xf3,0xfd,0xff,0xed,0xfc, -0xff,0xff,0x9f,0xfb,0xfd,0xff,0xff,0xff,0xf1,0xff,0xff,0x7f,0xfb,0x3e,0xff,0x9f, -0xff,0xff,0xff,0xff,0xfd,0xf9,0xff,0xff,0xff,0xfd,0xff,0xff,0xff,0xf0,0x6f,0xff, -0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff, -0xff,0xfe,0xff,0xff,0xff,0xfd,0xbd,0xff,0xef,0x7c,0xeb,0x7f,0xfb,0xdb,0xfa,0xdc, -0xee,0xf7,0xf6,0xd7,0xf5,0x2d,0xa1,0xbb,0xdd,0xee,0xf7,0x54,0xf7,0xfb,0x2c,0xb5, -0xb4,0xbd,0x6b,0x6f,0xef,0x6f,0xbb,0xdf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff, -0xfe,0xbf,0xff,0xff,0xff,0xfb,0xff,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xff,0xbf,0xef, -0x6f,0xff,0x6f,0xfa,0xdb,0xf1,0xc5,0xbd,0xf5,0x6f,0xff,0x6f,0xca,0xdb,0xff,0xdb, -0xfb,0xf6,0x97,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x9f,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0x7f,0xff,0xff,0xe7,0x63,0xff,0xff, -0xff,0xfc,0x77,0xdf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff, -0xc3,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0x5f,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8b,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xfc,0xff,0xcf,0xf1,0xdb,0xff,0xd6,0xa8,0x3f,0xff,0xff,0x08,0x2f,0xf0,0xff,0xc3, -0xff,0xeb,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xbf,0xff,0xca,0xff,0x9f,0xff,0xfa,0xb9,0xe7, -0x9f,0xf3,0x81,0xff,0xff,0xfc,0x73,0xd7,0xff,0xff,0x77,0xff,0xfd,0xff,0xfc,0xff, -0xff,0xff,0xff,0xcf,0xff,0xff,0xff,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff, -0xff,0xf7,0xde,0xff,0xfe,0x7e,0xff,0xbf,0xff,0xbf,0xf1,0xb3,0xff,0xff,0xe3,0xfb, -0xff,0xe1,0x1f,0x7f,0xff,0xf8,0x78,0xff,0xfb,0x1e,0xff,0xf7,0xfe,0xe7,0xff,0xff, -0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x04,0x00, -0x01,0x80,0x40,0x40,0x20,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00, -0x80,0x00,0x00,0x01,0x3c,0xf0,0xaf,0xff,0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xff, -0xff,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xf7,0xf1, -0xfd,0xff,0xff,0xff,0xdf,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff, -0xff,0xff,0xff,0xdb,0xf0,0x8f,0xff,0xff,0xff,0xfe,0xf0,0xff,0xdf,0xff,0xff,0x7f, -0xff,0xff,0xff,0xbe,0xd7,0xff,0xed,0xbd,0x7e,0xbf,0xfe,0xf6,0x7f,0xbf,0x71,0xff, -0xff,0xda,0xff,0xf9,0xff,0xbf,0x7f,0xfe,0xff,0x6f,0x7f,0xff,0xff,0xff,0xff,0xff, -0x7f,0xff,0xd0,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xf8,0x30,0x42,0x00,0x00,0x00,0x00, -0x80,0xc1,0x00,0x00,0x90,0x00,0xc4,0x00,0x00,0x12,0x20,0x43,0x22,0x81,0x84,0x00, -0x00,0x14,0x00,0x01,0x00,0x08,0x80,0x00,0x02,0x00,0x02,0x00,0x04,0x02,0x00,0x00, -0x10,0xc1,0xf0,0x1f,0xff,0xff,0xff,0xfe,0xff,0xff,0xfd,0xff,0xff,0xdd,0xfe,0xff, -0xb6,0x76,0xe5,0xbc,0xf9,0xf7,0xaf,0x5f,0xbf,0xfc,0xdf,0xcf,0xf1,0xff,0xef,0x79, -0xff,0xbd,0xff,0xef,0xff,0xff,0xf7,0x6f,0x5f,0xff,0xff,0xfd,0xef,0xef,0xbf,0xff, -0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xf0,0xff,0xff,0xff,0xff,0xfe,0xdb,0xff,0xff,0xfd,0x2d,0xff,0x69,0x2a,0xef,0x77, -0xbb,0xdd,0x5a,0xdf,0xf6,0xf6,0xd6,0xf7,0x7d,0xbd,0xd1,0xb2,0x4a,0xd6,0xb2,0xbe, -0x97,0xf5,0xbd,0xb3,0xad,0xff,0xef,0x7f,0x69,0x6b,0xfb,0xdf,0xff,0xff,0xff,0xf0, -0x2f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6,0xfe,0x9f,0xd4,0xbf, -0xed,0xaf,0xff,0x6b,0x6f,0xf7,0xff,0xdd,0xdb,0x31,0xfd,0xbf,0xff,0x6f,0x7f,0xff, -0xff,0xdb,0xff,0xcb,0xdf,0xf6,0xff,0xf6,0xff,0xfd,0xbf,0xfe,0xf7,0xff,0xd0,0x8f, -0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff, -0xa5,0xff,0xff,0xff,0xdf,0xb7,0xff,0xff,0xf1,0xff,0xff,0xff,0xf7,0xe9,0x6a,0xbf, -0xff,0xff,0xfd,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xaf,0xf0,0x4f,0xff, -0xff,0xff,0xfe,0xfe,0xdf,0xff,0xfd,0x1f,0xff,0x46,0x2f,0x9f,0xff,0xff,0xff,0xa5, -0xff,0xff,0xff,0xc0,0x37,0xff,0xff,0xf1,0x99,0x8e,0xdc,0x7f,0xe9,0x6a,0xbf,0xff, -0xf0,0x0f,0xff,0xff,0xfd,0x55,0x57,0xff,0xff,0xff,0xff,0xff,0xf0,0x0f,0xff,0xff, -0xff,0xfe,0xff,0xff,0xff,0xff,0x07,0xff,0xc0,0xbe,0xff,0xff,0xcf,0xef,0x9f,0xff, -0xff,0xfb,0xff,0xe7,0xff,0xff,0xa1,0xe3,0xce,0x3c,0x58,0x3f,0xf3,0xff,0xfd,0xef, -0xf9,0xff,0xff,0xf7,0xf1,0x7f,0xff,0xcb,0xff,0xff,0xff,0xf0,0x2f,0xff,0xff,0xff, -0xfe,0xf5,0x7f,0xff,0xf0,0xff,0xfe,0xff,0xc4,0x75,0xe7,0xb9,0xff,0xff,0xff,0xef, -0xff,0xc7,0x37,0x3b,0xff,0xf0,0x13,0x9e,0x0f,0xf4,0xff,0xfe,0xfb,0xff,0xff,0xf9, -0xfc,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xfa,0xf0,0xef,0xff,0xff,0xff,0xfe, -0xf3,0xc0,0x01,0x00,0x00,0x02,0x00,0x02,0x22,0x00,0x00,0xc0,0x40,0x00,0x40,0x00, -0x04,0x08,0x04,0x0a,0x01,0x01,0x10,0x20,0x20,0x00,0x00,0x04,0x08,0x08,0x04,0x00, -0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x3c,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xfd, -0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xff,0x7f,0xff,0x7f,0xff,0xcf,0x9d,0xff, -0xff,0xf7,0xfd,0xf1,0xff,0xff,0xff,0xee,0xbf,0xff,0xff,0xff,0xff,0xfe,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xf0,0xff, -0xff,0xff,0xf7,0xf7,0xff,0xff,0xfe,0xbf,0xf7,0xff,0xff,0x5b,0xff,0xbf,0xf7,0xff, -0xfd,0x7f,0x71,0xfd,0xff,0xed,0xf7,0xfe,0xef,0xff,0xff,0x7f,0xff,0xff,0xff,0xff, -0xff,0xff,0xef,0xff,0x7f,0xff,0xd0,0xf0,0xff,0xff,0xff,0xff,0xfe,0xf8,0x30,0x11, -0x00,0x48,0x60,0x40,0x82,0x60,0x24,0x60,0x00,0xcc,0x00,0x80,0x04,0x01,0x00,0x00, -0x14,0x01,0x0c,0x04,0x00,0x30,0x00,0x00,0x00,0x08,0x08,0x00,0x01,0x00,0xc2,0x00, -0x00,0x02,0x00,0x80,0x00,0xc1,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff, -0xf7,0x7b,0xff,0xf3,0xeb,0xbf,0xff,0xf7,0xff,0xff,0xff,0xe7,0x5d,0x3f,0xff,0xf6, -0xd1,0xfd,0xff,0xeb,0xf7,0x3d,0xff,0xff,0xff,0x5f,0xff,0x7f,0x7f,0xf3,0xff,0xff, -0xef,0xfd,0xbf,0xff,0xff,0xf0,0x5f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xf0,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xb5,0xdf, -0x6f,0x7d,0x69,0x7f,0xfb,0xdf,0x52,0x5f,0xf6,0xf7,0xfe,0xf6,0xf3,0xbd,0xb1,0xda, -0xcd,0xfe,0xf6,0xee,0xd2,0xbd,0xa5,0xaf,0xbd,0xff,0x6f,0x7c,0xeb,0x2b,0xfa,0xda, -0xff,0xfe,0xdf,0xf0,0x4f,0xff,0xff,0xff,0xfe,0xbf,0xff,0xff,0xff,0xdb,0xff,0xf6, -0xff,0xf6,0xff,0xbd,0xbf,0xcd,0xbf,0xeb,0x6f,0xf7,0x6f,0xdf,0xdb,0x51,0xfd,0xbd, -0xff,0x6f,0xff,0x6f,0xfb,0x5b,0xff,0xdb,0xff,0xf6,0xfe,0xf6,0xfd,0xfd,0xbf,0xfe, -0xf7,0xff,0xd0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xfa,0x50,0xff,0xff,0xff, -0xf0,0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0xfc,0xff,0xff, -0xf7,0xdb,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff, -0xaf,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf5,0xa0,0xff,0xff,0xff,0xf0, -0x6f,0xff,0xff,0xf0,0x96,0xff,0xff,0xc6,0x2b,0xff,0xff,0xf1,0x5a,0xff,0xff,0xff, -0xf3,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xc1,0x4f,0xc3,0xff,0xff,0xff,0xff, -0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0x9f,0xf0,0x7f, -0xff,0xf9,0xfc,0x4f,0xf3,0xff,0x27,0xeb,0xff,0xfc,0x81,0xfc,0x7f,0xfe,0x7b,0xff, -0xf7,0xff,0x12,0x7f,0xff,0xff,0xff,0xff,0x18,0xff,0xff,0xff,0xff,0xff,0xff,0xf0, -0x7f,0xff,0xff,0xff,0xfe,0xf5,0xff,0xff,0xff,0xdf,0xfe,0xff,0xfc,0x7e,0x7f,0xbf, -0xff,0xff,0xaf,0xef,0xff,0xdf,0xdf,0xfb,0xff,0xf1,0xc3,0xfe,0x6f,0xf1,0xcf,0x3f, -0xfb,0xff,0xff,0xcf,0xfe,0xff,0xff,0xfe,0x7f,0xbf,0xff,0xff,0xbf,0xfa,0xf0,0xdf, -0xff,0xff,0xff,0xfe,0xf3,0xc0,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00, -0x20,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00, -0x00,0x00,0x00,0x02,0x00,0x00,0x80,0x00,0x02,0x80,0x00,0x02,0x3c,0xf0,0x2f,0xff, -0xff,0xff,0xfe,0xfd,0xbf,0xff,0xfb,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xf5,0xf1,0xff,0x7f,0xff,0xff,0xff,0xff,0xef,0xff, -0xff,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xdb,0xf0,0x2f,0xff,0xff, -0xff,0xfe,0xf0,0xff,0xff,0xff,0xfb,0xff,0xbf,0xff,0xff,0xff,0xff,0xf7,0xbf,0xfb, -0xff,0xff,0xff,0xdf,0xf7,0xff,0xf1,0xf7,0xbf,0xfb,0xff,0xff,0xff,0x7f,0xde,0xff, -0xff,0xff,0xff,0xff,0xff,0xed,0xf7,0xff,0xff,0x7f,0xd0,0xf0,0x3f,0xff,0xff,0xff, -0xfe,0xf8,0x30,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0xe0,0x00,0x00,0x80, -0x20,0x01,0x01,0x92,0x00,0x01,0x01,0x00,0xe0,0x1c,0x60,0x20,0x30,0x08,0x08,0x00, -0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0xc1,0xf0,0x6f,0xff,0xff,0xff,0xfe, -0xff,0xff,0xff,0xff,0xff,0xdb,0xfe,0xff,0xff,0xdf,0xff,0xfc,0x7f,0xfb,0xbf,0xff, -0xff,0xff,0xff,0xff,0xf1,0xf6,0xff,0xf7,0x7e,0x3f,0xff,0x7f,0xff,0xff,0xff,0xf7, -0xff,0xff,0xff,0xed,0xff,0xdf,0xff,0xb7,0xff,0xf0,0x3f,0xff,0xff,0xff,0xfe,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,0xff,0xfe,0xff,0xff, -0xff,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xbf,0xff,0xdf, -0x57,0xef,0xf1,0xfd,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0xfb,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x7f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff, -0xff,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xdf,0xff, -0xff,0xf1,0xfd,0xff,0x7f,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xfe,0xff,0xff,0xff,0xff,0xf0,0x9f,0xff,0xff,0xff,0xfe,0xf7,0xfd,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbf,0xff,0xff,0xff,0xff,0xff, -0xf1,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xf0,0x6f,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf1, -0xff,0xff,0xfd,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xfb,0x6f,0xff,0xfe,0xbf,0xff,0xf1,0xff, -0xf7,0xff,0xff,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd, -0xff,0xff,0xff,0xf0,0xef,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xfb,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0x57,0xff,0xfd,0xbf,0xff,0xf1,0xff,0xef, -0xfe,0xff,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xff, -0xde,0xff,0xf0,0xcf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xf7,0xdb,0xff,0xdb,0xfd, -0xf6,0xff,0xf6,0xff,0x3c,0xbc,0xbc,0xbf,0xdf,0x6f,0xe7,0x2f,0xf1,0x3c,0xbf,0xfd, -0xbf,0xdf,0x6f,0xff,0x6f,0xf7,0xdb,0xff,0xdb,0xfd,0xf6,0xff,0xf6,0xff,0xff,0xff, -0x02,0x01,0xdf,0xff,0xff,0xff,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, -0xff,0xff,0xff,0xff,0xff,0xff }; diff --git a/trunk/drivers/net/igb/e1000_phy.c b/trunk/drivers/net/igb/e1000_phy.c index de2d48624683..f50fac25be40 100644 --- a/trunk/drivers/net/igb/e1000_phy.c +++ b/trunk/drivers/net/igb/e1000_phy.c @@ -448,8 +448,11 @@ s32 igb_copper_link_setup_igp(struct e1000_hw *hw) goto out; } - /* Wait 15ms for MAC to configure PHY from NVM settings. */ - msleep(15); + /* + * Wait 100ms for MAC to configure PHY from NVM settings, to avoid + * timeout issues when LFS is enabled. + */ + msleep(100); /* * The NVM settings will configure LPLU in D3 for diff --git a/trunk/drivers/net/igb/igb_ethtool.c b/trunk/drivers/net/igb/igb_ethtool.c index fb09c8ad9f0d..27eae49e79c2 100644 --- a/trunk/drivers/net/igb/igb_ethtool.c +++ b/trunk/drivers/net/igb/igb_ethtool.c @@ -1419,7 +1419,6 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; u32 ctrl_reg = 0; - u32 stat_reg = 0; hw->mac.autoneg = false; @@ -1443,18 +1442,11 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ - E1000_CTRL_FD); /* Force Duplex to FULL */ + E1000_CTRL_FD | /* Force Duplex to FULL */ + E1000_CTRL_SLU); /* Set link up enable bit */ - if (hw->phy.media_type == e1000_media_type_copper && - hw->phy.type == e1000_phy_m88) + if (hw->phy.type == e1000_phy_m88) ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ - else { - /* Set the ILOS bit on the fiber Nic if half duplex link is - * detected. */ - stat_reg = rd32(E1000_STATUS); - if ((stat_reg & E1000_STATUS_FD) == 0) - ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); - } wr32(E1000_CTRL, ctrl_reg); diff --git a/trunk/drivers/net/igb/igb_main.c b/trunk/drivers/net/igb/igb_main.c index ca842163dce4..03aa9593dd9e 100644 --- a/trunk/drivers/net/igb/igb_main.c +++ b/trunk/drivers/net/igb/igb_main.c @@ -135,8 +135,8 @@ static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int); static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *); static void igb_restore_vf_multicasts(struct igb_adapter *adapter); -static int igb_suspend(struct pci_dev *, pm_message_t); #ifdef CONFIG_PM +static int igb_suspend(struct pci_dev *, pm_message_t); static int igb_resume(struct pci_dev *); #endif static void igb_shutdown(struct pci_dev *); @@ -420,6 +420,9 @@ static void igb_free_queues(struct igb_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) netif_napi_del(&adapter->rx_ring[i].napi); + adapter->num_rx_queues = 0; + adapter->num_tx_queues = 0; + kfree(adapter->tx_ring); kfree(adapter->rx_ring); } @@ -1476,9 +1479,10 @@ static int __devinit igb_probe(struct pci_dev *pdev, netdev->name, ((hw->bus.speed == e1000_bus_speed_2500) ? "2.5Gb/s" : "unknown"), - ((hw->bus.width == e1000_bus_width_pcie_x4) - ? "Width x4" : (hw->bus.width == e1000_bus_width_pcie_x1) - ? "Width x1" : "unknown"), + ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : + (hw->bus.width == e1000_bus_width_pcie_x2) ? "Width x2" : + (hw->bus.width == e1000_bus_width_pcie_x1) ? "Width x1" : + "unknown"), netdev->dev_addr); igb_read_part_num(hw, &part_num); @@ -5056,7 +5060,7 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) return 0; } -static int igb_suspend(struct pci_dev *pdev, pm_message_t state) +static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake) { struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); @@ -5115,15 +5119,9 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state) wr32(E1000_WUFC, 0); } - /* make sure adapter isn't asleep if manageability/wol is enabled */ - if (wufc || adapter->en_mng_pt) { - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); - } else { + *enable_wake = wufc || adapter->en_mng_pt; + if (!*enable_wake) igb_shutdown_fiber_serdes_link_82575(hw); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); - } /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ @@ -5131,12 +5129,29 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state) pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; } #ifdef CONFIG_PM +static int igb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int retval; + bool wake; + + retval = __igb_shutdown(pdev, &wake); + if (retval) + return retval; + + if (wake) { + pci_prepare_to_sleep(pdev); + } else { + pci_wake_from_d3(pdev, false); + pci_set_power_state(pdev, PCI_D3hot); + } + + return 0; +} + static int igb_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -5189,7 +5204,14 @@ static int igb_resume(struct pci_dev *pdev) static void igb_shutdown(struct pci_dev *pdev) { - igb_suspend(pdev, PMSG_SUSPEND); + bool wake; + + __igb_shutdown(pdev, &wake); + + if (system_state == SYSTEM_POWER_OFF) { + pci_wake_from_d3(pdev, wake); + pci_set_power_state(pdev, PCI_D3hot); + } } #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/trunk/drivers/net/ixgbe/ixgbe_82598.c b/trunk/drivers/net/ixgbe/ixgbe_82598.c index ed265a7a898f..de4db0dc7879 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_82598.c +++ b/trunk/drivers/net/ixgbe/ixgbe_82598.c @@ -411,7 +411,8 @@ static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) /* Decide whether to use autoneg or not. */ hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (hw->phy.multispeed_fiber && (speed == IXGBE_LINK_SPEED_1GB_FULL)) + if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber && + (speed == IXGBE_LINK_SPEED_1GB_FULL)) ret_val = ixgbe_fc_autoneg(hw); if (ret_val) diff --git a/trunk/drivers/net/ixgbe/ixgbe_common.c b/trunk/drivers/net/ixgbe/ixgbe_common.c index 8cfd3fd309a0..63ab6671d08e 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_common.c +++ b/trunk/drivers/net/ixgbe/ixgbe_common.c @@ -1937,7 +1937,8 @@ s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num) /* Decide whether to use autoneg or not. */ hw->mac.ops.check_link(hw, &speed, &link_up, false); - if (hw->phy.multispeed_fiber && (speed == IXGBE_LINK_SPEED_1GB_FULL)) + if (!hw->fc.disable_fc_autoneg && hw->phy.multispeed_fiber && + (speed == IXGBE_LINK_SPEED_1GB_FULL)) ret_val = ixgbe_fc_autoneg(hw); if (ret_val) diff --git a/trunk/drivers/net/ixgbe/ixgbe_common.h b/trunk/drivers/net/ixgbe/ixgbe_common.h index 7e94d6d399ab..24f73e719c3f 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_common.h +++ b/trunk/drivers/net/ixgbe/ixgbe_common.h @@ -96,14 +96,11 @@ s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val); #define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS) #ifdef DEBUG +extern char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw); #define hw_dbg(hw, format, arg...) \ -printk(KERN_DEBUG, "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg); + printk(KERN_DEBUG "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg) #else -static inline int __attribute__ ((format (printf, 2, 3))) -hw_dbg(struct ixgbe_hw *hw, const char *format, ...) -{ - return 0; -} +#define hw_dbg(hw, format, arg...) do {} while (0) #endif #endif /* IXGBE_COMMON */ diff --git a/trunk/drivers/net/ixgbe/ixgbe_dcb_nl.c b/trunk/drivers/net/ixgbe/ixgbe_dcb_nl.c index 0a8731f1f237..bd0a0c276952 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/trunk/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -90,6 +90,8 @@ int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc; } + dst_dcb_cfg->pfc_mode_enable = src_dcb_cfg->pfc_mode_enable; + return 0; } @@ -298,8 +300,10 @@ static void ixgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority, adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting; if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc != - adapter->dcb_cfg.tc_config[priority].dcb_pfc) + adapter->dcb_cfg.tc_config[priority].dcb_pfc) { adapter->dcb_set_bitmap |= BIT_PFC; + adapter->temp_dcb_cfg.pfc_mode_enable = true; + } } static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, diff --git a/trunk/drivers/net/ixgbe/ixgbe_ethtool.c b/trunk/drivers/net/ixgbe/ixgbe_ethtool.c index 18ecba7f6ecb..aafc120f164e 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/trunk/drivers/net/ixgbe/ixgbe_ethtool.c @@ -129,6 +129,15 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->advertising |= ADVERTISED_10000baseT_Full; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) ecmd->advertising |= ADVERTISED_1000baseT_Full; + /* + * It's possible that phy.autoneg_advertised may not be + * set yet. If so display what the default would be - + * both 1G and 10G supported. + */ + if (!(ecmd->advertising & (ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full))) + ecmd->advertising |= (ADVERTISED_10000baseT_Full | + ADVERTISED_1000baseT_Full); ecmd->port = PORT_TP; } else if (hw->phy.media_type == ixgbe_media_type_backplane) { @@ -225,7 +234,16 @@ static void ixgbe_get_pauseparam(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - pause->autoneg = (hw->fc.current_mode == ixgbe_fc_full ? 1 : 0); + /* + * Flow Control Autoneg isn't on if + * - we didn't ask for it OR + * - it failed, we know this by tx & rx being off + */ + if (hw->fc.disable_fc_autoneg || + (hw->fc.current_mode == ixgbe_fc_none)) + pause->autoneg = 0; + else + pause->autoneg = 1; if (hw->fc.current_mode == ixgbe_fc_rx_pause) { pause->rx_pause = 1; @@ -243,8 +261,12 @@ static int ixgbe_set_pauseparam(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - if ((pause->autoneg == AUTONEG_ENABLE) || - (pause->rx_pause && pause->tx_pause)) + if (pause->autoneg != AUTONEG_ENABLE) + hw->fc.disable_fc_autoneg = true; + else + hw->fc.disable_fc_autoneg = false; + + if (pause->rx_pause && pause->tx_pause) hw->fc.requested_mode = ixgbe_fc_full; else if (pause->rx_pause && !pause->tx_pause) hw->fc.requested_mode = ixgbe_fc_rx_pause; @@ -712,9 +734,10 @@ static int ixgbe_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - struct ixgbe_ring *temp_ring; + struct ixgbe_ring *temp_tx_ring, *temp_rx_ring; int i, err; u32 new_rx_count, new_tx_count; + bool need_update = false; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; @@ -733,80 +756,94 @@ static int ixgbe_set_ringparam(struct net_device *netdev, return 0; } - temp_ring = kcalloc(adapter->num_tx_queues, - sizeof(struct ixgbe_ring), GFP_KERNEL); - if (!temp_ring) - return -ENOMEM; - while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); - if (new_tx_count != adapter->tx_ring->count) { + temp_tx_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!temp_tx_ring) { + err = -ENOMEM; + goto err_setup; + } + + if (new_tx_count != adapter->tx_ring_count) { + memcpy(temp_tx_ring, adapter->tx_ring, + adapter->num_tx_queues * sizeof(struct ixgbe_ring)); for (i = 0; i < adapter->num_tx_queues; i++) { - temp_ring[i].count = new_tx_count; - err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); + temp_tx_ring[i].count = new_tx_count; + err = ixgbe_setup_tx_resources(adapter, + &temp_tx_ring[i]); if (err) { while (i) { i--; ixgbe_free_tx_resources(adapter, - &temp_ring[i]); + &temp_tx_ring[i]); } goto err_setup; } - temp_ring[i].v_idx = adapter->tx_ring[i].v_idx; + temp_tx_ring[i].v_idx = adapter->tx_ring[i].v_idx; } - if (netif_running(netdev)) - netdev->netdev_ops->ndo_stop(netdev); - ixgbe_reset_interrupt_capability(adapter); - ixgbe_napi_del_all(adapter); - INIT_LIST_HEAD(&netdev->napi_list); - kfree(adapter->tx_ring); - adapter->tx_ring = temp_ring; - temp_ring = NULL; - adapter->tx_ring_count = new_tx_count; + need_update = true; } - temp_ring = kcalloc(adapter->num_rx_queues, - sizeof(struct ixgbe_ring), GFP_KERNEL); - if (!temp_ring) { - if (netif_running(netdev)) - netdev->netdev_ops->ndo_open(netdev); - return -ENOMEM; + temp_rx_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); + if ((!temp_rx_ring) && (need_update)) { + for (i = 0; i < adapter->num_tx_queues; i++) + ixgbe_free_tx_resources(adapter, &temp_tx_ring[i]); + kfree(temp_tx_ring); + err = -ENOMEM; + goto err_setup; } - if (new_rx_count != adapter->rx_ring->count) { + if (new_rx_count != adapter->rx_ring_count) { + memcpy(temp_rx_ring, adapter->rx_ring, + adapter->num_rx_queues * sizeof(struct ixgbe_ring)); for (i = 0; i < adapter->num_rx_queues; i++) { - temp_ring[i].count = new_rx_count; - err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); + temp_rx_ring[i].count = new_rx_count; + err = ixgbe_setup_rx_resources(adapter, + &temp_rx_ring[i]); if (err) { while (i) { i--; ixgbe_free_rx_resources(adapter, - &temp_ring[i]); + &temp_rx_ring[i]); } goto err_setup; } - temp_ring[i].v_idx = adapter->rx_ring[i].v_idx; + temp_rx_ring[i].v_idx = adapter->rx_ring[i].v_idx; } + need_update = true; + } + + /* if rings need to be updated, here's the place to do it in one shot */ + if (need_update) { if (netif_running(netdev)) - netdev->netdev_ops->ndo_stop(netdev); - ixgbe_reset_interrupt_capability(adapter); - ixgbe_napi_del_all(adapter); - INIT_LIST_HEAD(&netdev->napi_list); - kfree(adapter->rx_ring); - adapter->rx_ring = temp_ring; - temp_ring = NULL; - - adapter->rx_ring_count = new_rx_count; + ixgbe_down(adapter); + + /* tx */ + if (new_tx_count != adapter->tx_ring_count) { + kfree(adapter->tx_ring); + adapter->tx_ring = temp_tx_ring; + temp_tx_ring = NULL; + adapter->tx_ring_count = new_tx_count; + } + + /* rx */ + if (new_rx_count != adapter->rx_ring_count) { + kfree(adapter->rx_ring); + adapter->rx_ring = temp_rx_ring; + temp_rx_ring = NULL; + adapter->rx_ring_count = new_rx_count; + } } /* success! */ err = 0; -err_setup: - ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) - netdev->netdev_ops->ndo_open(netdev); + ixgbe_up(adapter); +err_setup: clear_bit(__IXGBE_RESETTING, &adapter->state); return err; } diff --git a/trunk/drivers/net/ixgbe/ixgbe_main.c b/trunk/drivers/net/ixgbe/ixgbe_main.c index 79aa811c403c..286ecc0e6ab7 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_main.c +++ b/trunk/drivers/net/ixgbe/ixgbe_main.c @@ -187,15 +187,14 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, struct ixgbe_tx_buffer *tx_buffer_info) { - if (tx_buffer_info->dma) { - pci_unmap_page(adapter->pdev, tx_buffer_info->dma, - tx_buffer_info->length, PCI_DMA_TODEVICE); - tx_buffer_info->dma = 0; - } + tx_buffer_info->dma = 0; if (tx_buffer_info->skb) { + skb_dma_unmap(&adapter->pdev->dev, tx_buffer_info->skb, + DMA_TO_DEVICE); dev_kfree_skb_any(tx_buffer_info->skb); tx_buffer_info->skb = NULL; } + tx_buffer_info->time_stamp = 0; /* tx_buffer_info must be completely set up in the transmit path */ } @@ -204,15 +203,11 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter, unsigned int eop) { struct ixgbe_hw *hw = &adapter->hw; - u32 head, tail; /* Detect a transmit hang in hardware, this serializes the * check with the clearing of time_stamp and movement of eop */ - head = IXGBE_READ_REG(hw, tx_ring->head); - tail = IXGBE_READ_REG(hw, tx_ring->tail); adapter->detect_tx_hung = false; - if ((head != tail) && - tx_ring->tx_buffer_info[eop].time_stamp && + if (tx_ring->tx_buffer_info[eop].time_stamp && time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) && !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) { /* detected Tx unit hang */ @@ -227,7 +222,8 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter, " time_stamp <%lx>\n" " jiffies <%lx>\n", tx_ring->queue_index, - head, tail, + IXGBE_READ_REG(hw, tx_ring->head), + IXGBE_READ_REG(hw, tx_ring->tail), tx_ring->next_to_use, eop, tx_ring->tx_buffer_info[eop].time_stamp, jiffies); return true; @@ -2934,6 +2930,7 @@ static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter) **/ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) { + struct ixgbe_hw *hw = &adapter->hw; int err = 0; int vector, v_budget; @@ -2948,12 +2945,12 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) /* * At the same time, hardware can only support a maximum of - * MAX_MSIX_COUNT vectors. With features such as RSS and VMDq, - * we can easily reach upwards of 64 Rx descriptor queues and - * 32 Tx queues. Thus, we cap it off in those rare cases where - * the cpu count also exceeds our vector limit. + * hw.mac->max_msix_vectors vectors. With features + * such as RSS and VMDq, we can easily surpass the number of Rx and Tx + * descriptor queues supported by our device. Thus, we cap it off in + * those rare cases where the cpu count also exceeds our vector limit. */ - v_budget = min(v_budget, MAX_MSIX_COUNT); + v_budget = min(v_budget, (int)hw->mac.max_msix_vectors); /* A failure in MSI-X entry allocation isn't fatal, but it does * mean we disable MSI-X capabilities of the adapter. */ @@ -3169,11 +3166,13 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) #endif /* default flow control settings */ - hw->fc.requested_mode = ixgbe_fc_none; + hw->fc.requested_mode = ixgbe_fc_full; + hw->fc.current_mode = ixgbe_fc_full; /* init for ethtool output */ hw->fc.high_water = IXGBE_DEFAULT_FCRTH; hw->fc.low_water = IXGBE_DEFAULT_FCRTL; hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE; hw->fc.send_xon = true; + hw->fc.disable_fc_autoneg = false; /* enable itr by default in dynamic mode */ adapter->itr_setting = 1; @@ -3489,10 +3488,10 @@ static int ixgbe_open(struct net_device *netdev) ixgbe_release_hw_control(adapter); ixgbe_free_irq(adapter); err_req_irq: - ixgbe_free_all_rx_resources(adapter); err_setup_rx: - ixgbe_free_all_tx_resources(adapter); + ixgbe_free_all_rx_resources(adapter); err_setup_tx: + ixgbe_free_all_tx_resources(adapter); ixgbe_reset(adapter); return err; @@ -4163,32 +4162,39 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, struct sk_buff *skb, unsigned int first) { struct ixgbe_tx_buffer *tx_buffer_info; - unsigned int len = skb->len; + unsigned int len = skb_headlen(skb); unsigned int offset = 0, size, count = 0, i; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; - - len -= skb->data_len; + dma_addr_t *map; i = tx_ring->next_to_use; + if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) { + dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); + return 0; + } + + map = skb_shinfo(skb)->dma_maps; + while (len) { tx_buffer_info = &tx_ring->tx_buffer_info[i]; size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = pci_map_single(adapter->pdev, - skb->data + offset, - size, PCI_DMA_TODEVICE); + tx_buffer_info->dma = map[0] + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; len -= size; offset += size; count++; - i++; - if (i == tx_ring->count) - i = 0; + + if (len) { + i++; + if (i == tx_ring->count) + i = 0; + } } for (f = 0; f < nr_frags; f++) { @@ -4196,33 +4202,27 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, frag = &skb_shinfo(skb)->frags[f]; len = frag->size; - offset = frag->page_offset; + offset = 0; while (len) { + i++; + if (i == tx_ring->count) + i = 0; + tx_buffer_info = &tx_ring->tx_buffer_info[i]; size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = pci_map_page(adapter->pdev, - frag->page, - offset, - size, - PCI_DMA_TODEVICE); + tx_buffer_info->dma = map[f + 1] + offset; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; len -= size; offset += size; count++; - i++; - if (i == tx_ring->count) - i = 0; } } - if (i == 0) - i = tx_ring->count - 1; - else - i = i - 1; + tx_ring->tx_buffer_info[i].skb = skb; tx_ring->tx_buffer_info[first].next_to_watch = i; @@ -4388,13 +4388,19 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) (skb->ip_summed == CHECKSUM_PARTIAL)) tx_flags |= IXGBE_TX_FLAGS_CSUM; - ixgbe_tx_queue(adapter, tx_ring, tx_flags, - ixgbe_tx_map(adapter, tx_ring, skb, first), - skb->len, hdr_len); + count = ixgbe_tx_map(adapter, tx_ring, skb, first); - netdev->trans_start = jiffies; + if (count) { + ixgbe_tx_queue(adapter, tx_ring, tx_flags, count, skb->len, + hdr_len); + netdev->trans_start = jiffies; + ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); - ixgbe_maybe_stop_tx(netdev, tx_ring, DESC_NEEDED); + } else { + dev_kfree_skb_any(skb); + tx_ring->tx_buffer_info[first].time_stamp = 0; + tx_ring->next_to_use = first; + } return NETDEV_TX_OK; } @@ -4987,8 +4993,20 @@ static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event, return ret_val ? NOTIFY_BAD : NOTIFY_DONE; } + #endif /* CONFIG_IXGBE_DCA */ +#ifdef DEBUG +/** + * ixgbe_get_hw_dev_name - return device name string + * used by hardware layer to print debugging information + **/ +char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw) +{ + struct ixgbe_adapter *adapter = hw->back; + return adapter->netdev->name; +} +#endif module_exit(ixgbe_exit_module); /* ixgbe_main.c */ diff --git a/trunk/drivers/net/ixgbe/ixgbe_type.h b/trunk/drivers/net/ixgbe/ixgbe_type.h index 2b2ecba7b609..030ff0a9ea67 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_type.h +++ b/trunk/drivers/net/ixgbe/ixgbe_type.h @@ -2005,6 +2005,7 @@ struct ixgbe_fc_info { u16 pause_time; /* Flow Control Pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ + bool disable_fc_autoneg; /* Turn off autoneg FC mode */ enum ixgbe_fc_mode current_mode; /* FC mode in effect */ enum ixgbe_fc_mode requested_mode; /* FC mode requested by caller */ }; diff --git a/trunk/drivers/net/mlx4/en_netdev.c b/trunk/drivers/net/mlx4/en_netdev.c index 9f6644a44030..303c23de6cac 100644 --- a/trunk/drivers/net/mlx4/en_netdev.c +++ b/trunk/drivers/net/mlx4/en_netdev.c @@ -505,7 +505,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) static void mlx4_en_do_get_stats(struct work_struct *work) { - struct delayed_work *delay = container_of(work, struct delayed_work, work); + struct delayed_work *delay = to_delayed_work(work); struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, stats_task); struct mlx4_en_dev *mdev = priv->mdev; diff --git a/trunk/drivers/net/mlx4/en_rx.c b/trunk/drivers/net/mlx4/en_rx.c index a4130e764991..7e40741fb7d8 100644 --- a/trunk/drivers/net/mlx4/en_rx.c +++ b/trunk/drivers/net/mlx4/en_rx.c @@ -298,7 +298,7 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, void mlx4_en_rx_refill(struct work_struct *work) { - struct delayed_work *delay = container_of(work, struct delayed_work, work); + struct delayed_work *delay = to_delayed_work(work); struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, refill_task); struct mlx4_en_dev *mdev = priv->mdev; diff --git a/trunk/drivers/net/mlx4/sense.c b/trunk/drivers/net/mlx4/sense.c index 6d5089ecb5af..f36ae691cab3 100644 --- a/trunk/drivers/net/mlx4/sense.c +++ b/trunk/drivers/net/mlx4/sense.c @@ -103,7 +103,7 @@ void mlx4_do_sense_ports(struct mlx4_dev *dev, static void mlx4_sense_port(struct work_struct *work) { - struct delayed_work *delay = container_of(work, struct delayed_work, work); + struct delayed_work *delay = to_delayed_work(work); struct mlx4_sense *sense = container_of(delay, struct mlx4_sense, sense_poll); struct mlx4_dev *dev = sense->dev; diff --git a/trunk/drivers/net/pcmcia/ositech.h b/trunk/drivers/net/pcmcia/ositech.h deleted file mode 100644 index 4126efc355bd..000000000000 --- a/trunk/drivers/net/pcmcia/ositech.h +++ /dev/null @@ -1,358 +0,0 @@ -/* - This file contains the firmware of Seven of Diamonds from OSITECH. - (Special thanks to Kevin MacPherson of OSITECH) - - This software may be used and distributed according to the terms of - the GNU General Public License, incorporated herein by reference. -*/ - - static const u_char __Xilinx7OD[] = { - 0xFF, 0x04, 0xA0, 0x36, 0xF3, 0xEC, 0xFF, 0xFF, 0xFF, 0xDF, 0xFB, 0xFF, - 0xF3, 0xFF, 0xFF, 0xFF, - 0xEF, 0x3F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7F, 0xFE, 0xFF, - 0xCE, 0xFE, 0xFE, 0xFE, - 0xFE, 0xDE, 0xBD, 0xDD, 0xFD, 0xFF, 0xFD, 0xCF, 0xF7, 0xBF, 0x7F, 0xFF, - 0x7F, 0x3F, 0xFE, 0xBF, - 0xFF, 0xFF, 0xFF, 0xBC, 0xFF, 0xFF, 0xBD, 0xB5, 0x7F, 0x7F, 0xBF, 0xBF, - 0x7F, 0xFF, 0xEF, 0xFF, - 0xFF, 0xFF, 0xFB, 0xFF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDE, - 0xFE, 0xFE, 0xFA, 0xDE, - 0xBD, 0xFD, 0xED, 0xFD, 0xFD, 0xCF, 0xEF, 0xEF, 0xEF, 0xEF, 0xC7, 0xDF, - 0xDF, 0xDF, 0xDF, 0xDF, - 0xFF, 0x7E, 0xFE, 0xFD, 0x7D, 0x6D, 0xEE, 0xFE, 0x7C, 0xFB, 0xF4, 0xFB, - 0xCF, 0xDB, 0xDF, 0xFF, - 0xFF, 0xBB, 0x7F, 0xFF, 0x7F, 0xFF, 0xF7, 0xFF, 0x9E, 0xBF, 0x3B, 0xBF, - 0xBF, 0x7F, 0x7F, 0x7F, - 0x7E, 0x6F, 0xDF, 0xEF, 0xF5, 0xF6, 0xFD, 0xF6, 0xF5, 0xED, 0xEB, 0xFF, - 0xEF, 0xEF, 0xEF, 0x7E, - 0x7F, 0x7F, 0x6F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xEF, 0xBF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0x1F, 0x1F, 0xEE, 0xFF, 0xBC, - 0xB7, 0xFF, 0xDF, 0xFF, - 0xDF, 0xEF, 0x3B, 0xE3, 0xD3, 0xFF, 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, - 0xFF, 0xBA, 0xBF, 0x2D, - 0xDB, 0xBD, 0xFD, 0xDB, 0xDF, 0xFA, 0xFB, 0xFF, 0xEF, 0xFB, 0xDB, 0xF3, - 0xFF, 0xDF, 0xFD, 0x7F, - 0xEF, 0xFB, 0xFF, 0xFF, 0xBE, 0xBF, 0x27, 0xBA, 0xFE, 0xFB, 0xDF, 0xFF, - 0xF6, 0xFF, 0xFF, 0xEF, - 0xFB, 0xDB, 0xF3, 0xD9, 0x9A, 0x3F, 0xFF, 0xAF, 0xBF, 0xFF, 0xFF, 0xBE, - 0x3F, 0x37, 0xBD, 0x96, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE, 0xFB, 0xF3, 0xF3, 0xEB, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF7, 0xFA, 0xBC, 0xAE, 0xFE, 0xBE, 0xFE, 0xBB, 0x7F, 0xFD, 0xFF, - 0x7F, 0xEF, 0xF7, 0xFB, - 0xBB, 0xD7, 0xF7, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xBC, 0xED, 0xFD, - 0xBD, 0x9D, 0x7D, 0x7B, - 0xFB, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF7, - 0xAA, 0xB9, 0xBF, 0x8F, 0xBF, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xCF, - 0xFB, 0xEB, 0xCB, 0xEB, - 0xEE, 0xFF, 0xFF, 0xD7, 0xFF, 0xFF, 0xFF, 0x3E, 0x33, 0x3F, 0x1C, 0x7C, - 0xFC, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xCF, 0xD3, 0xF3, 0xE3, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xEB, 0xFE, 0x35, - 0x3F, 0x3D, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0x6F, 0xE3, - 0xE3, 0xE3, 0xEF, 0xFF, - 0xFF, 0xDF, 0xFF, 0xFF, 0xF7, 0xFE, 0x3E, 0x5E, 0xFE, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFD, 0xFF, 0xFF, - 0xAF, 0xCF, 0xF2, 0xCB, 0xCF, 0x8E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, - 0xFC, 0x3E, 0x1F, 0x9E, - 0xAD, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xB3, 0xF7, 0xE7, - 0xF7, 0xFA, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xEE, 0xEB, 0xAB, 0xAF, 0x9F, 0xE3, 0x7F, 0xFF, 0xDE, - 0xFF, 0x7F, 0xEE, 0xFF, - 0xFF, 0xFB, 0x3A, 0xFA, 0xFF, 0xF2, 0x77, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF, - 0xFE, 0xBD, 0xAE, 0xDE, - 0x7D, 0x7D, 0xFD, 0xFF, 0xBF, 0xEE, 0xFF, 0xFD, 0xFF, 0xDB, 0xFB, 0xFF, - 0xF7, 0xEF, 0xFB, 0xFF, - 0xFF, 0xFE, 0xFF, 0x2D, 0xAF, 0xB9, 0xFD, 0x79, 0xFB, 0xFA, 0xFF, 0xBF, - 0xEF, 0xFF, 0xFF, 0x91, - 0xFA, 0xFB, 0xDF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF, 0x37, 0xBF, - 0xBF, 0xFF, 0x7F, 0x7F, - 0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xF3, 0xFB, 0xFB, 0xFF, 0xF5, 0xEF, - 0xFF, 0xFF, 0xF7, 0xFA, - 0xFF, 0xFF, 0xEE, 0xFA, 0xFE, 0xFB, 0x55, 0xDD, 0xFF, 0x7F, 0xAF, 0xFE, - 0xFF, 0xFB, 0xFB, 0xF5, - 0xFF, 0xF7, 0xEF, 0xFF, 0xFF, 0xFF, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, - 0x7B, 0x7B, 0x7B, 0x7B, - 0xFB, 0xAE, 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF7, 0xDA, 0xB7, 0x61, - 0xFF, 0xB9, 0x59, 0xF3, 0x73, 0xF3, 0xDF, 0x7F, 0x6F, 0xDF, 0xEF, 0xF7, - 0xEB, 0xEB, 0xD7, 0xFF, - 0xD7, 0xFF, 0xFF, 0xF7, 0xFE, 0x7F, 0xFB, 0x3E, 0x38, 0x73, 0xF6, 0x7F, - 0xFC, 0xFF, 0xFF, 0xCF, - 0xFF, 0xB7, 0xFB, 0xB3, 0xB3, 0x67, 0xFF, 0xE7, 0xFD, 0xFF, 0xEF, 0xF6, - 0x7F, 0xB7, 0xBC, 0xF5, - 0x7B, 0xF6, 0xF7, 0xF5, 0xFF, 0xFF, 0xEF, 0xFF, 0xF7, 0xFF, 0xF7, 0xCE, - 0xE7, 0xFF, 0x9F, 0xFF, - 0xFF, 0xF5, 0xFE, 0x7D, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xEF, 0xFF, 0xF6, - 0xCB, 0xDB, 0xEE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xBE, - 0x1E, 0x3E, 0xFE, 0xFF, - 0x7D, 0xFE, 0xFF, 0xFF, 0xEF, 0xBF, 0xE7, 0xFF, 0xE3, 0xE3, 0xFF, 0xDF, - 0xE7, 0xFF, 0xFF, 0xFF, - 0xB8, 0xEF, 0xB7, 0x2F, 0xEE, 0xFF, 0xDF, 0xFF, 0xBF, 0xFF, 0x7F, 0xEF, - 0xEB, 0xBF, 0xA3, 0xD3, - 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xFD, 0x3F, 0xCF, 0xFD, - 0xFB, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xAF, 0xFB, 0xBF, 0xBB, 0xBF, 0xDB, 0xFD, 0xFB, 0xFF, 0xFF, - 0xFF, 0xFF, 0x3E, 0xFE, - 0x3F, 0xBA, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xEF, 0xC3, 0x7F, - 0xB2, 0x9B, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0x3C, 0xFF, 0x3F, 0x3C, 0xFF, 0xFE, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xAF, 0xF3, 0xFE, 0xF3, 0xE3, 0xEB, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xF7, - 0x9A, 0xFE, 0xAF, 0x9E, - 0xBE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0x7B, 0xEF, 0xF7, 0xBF, 0xFB, 0xFB, - 0xFB, 0xFF, 0xFF, 0x7F, - 0xFF, 0xFF, 0xFF, 0xBC, 0xBD, 0xFD, 0xBD, 0xDD, 0x7D, 0x7B, 0x7B, 0x7B, - 0x7B, 0xFB, 0xAE, 0xFF, - 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0x9A, 0xFF, - 0x9F, 0xFF, 0xAF, 0xEF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xCF, 0xF3, 0xFF, 0xEB, 0xFF, 0xEB, 0xFF, - 0xFF, 0xBF, 0xFF, 0xFF, - 0xEF, 0xFE, 0xFF, 0x37, 0xFC, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xCF, 0xEF, 0xFD, 0xF3, - 0xFF, 0xEE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0xFD, 0x2F, 0xFD, - 0xFF, 0xFD, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xEF, 0xCF, 0xFF, 0xF3, 0xBF, 0x69, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, - 0xFB, 0x9F, 0xFF, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x87, - 0xFE, 0xDA, 0xEF, 0xCF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xBF, 0xEF, 0xEF, 0xFD, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xEF, 0xFD, 0xFF, 0x7B, 0xFF, 0xEB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, - 0xEB, 0xF8, 0xFF, 0xEF, - 0xAF, 0xFF, 0xFF, 0xBD, 0xFF, 0xFF, 0xFF, 0x7F, 0xEE, 0x7F, 0xEF, 0xFF, - 0xBB, 0xFF, 0xBF, 0xFB, - 0xFF, 0xFF, 0xFF, 0xF7, 0xF6, 0xFB, 0xBD, 0xFD, 0xDD, 0xF5, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xAF, - 0xFF, 0x5F, 0xF5, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, - 0xF3, 0xFF, 0xDE, 0xFE, - 0xEF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xDE, 0xDF, 0x5F, 0xDF, - 0xFD, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, - 0xFF, 0xAF, 0xFF, 0xFF, - 0xEF, 0xED, 0xFF, 0xDF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xDA, 0xBD, 0xBE, - 0xAE, 0xFE, 0x7F, 0xFD, - 0xDF, 0xFF, 0xFF, 0x7F, 0xEF, 0xFF, 0xFB, 0xFB, 0xFB, 0x7F, 0xF7, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF7, - 0xBC, 0xFD, 0xBD, 0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE, - 0xFF, 0xFF, 0xFD, 0xFF, - 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x9F, 0xBF, 0xBF, 0xCF, - 0x7F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xAF, 0xFF, 0xEB, 0xEB, 0xEB, 0xFF, 0xD7, 0xFE, 0xFF, 0xFF, - 0xBF, 0xE7, 0xFE, 0xBF, - 0x7F, 0xFC, 0xFF, 0xFF, 0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFB, - 0xFB, 0xFF, 0xFF, 0xDD, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBD, 0xDF, 0x9D, 0xFD, 0xDF, 0xB9, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xEF, 0xFF, 0xFB, 0xEF, 0xEB, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF6, 0x9F, 0xFF, 0xFC, - 0xFE, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xDF, 0xFA, 0xCD, 0xCF, - 0xBF, 0x9F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF7, 0xFE, 0xBF, 0xFF, 0xDF, 0xEF, 0x5F, 0xFF, 0xFF, 0xFF, - 0xFF, 0x7F, 0x6F, 0xFF, - 0xBB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0xFF, - 0x5F, 0xFF, 0xBF, 0xBF, - 0xF9, 0xFF, 0xFF, 0xFF, 0x7F, 0x6E, 0x7B, 0xFF, 0xEF, 0xFD, 0xEB, 0xDF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xF7, 0xB6, 0x3E, 0xFC, 0xFD, 0xBF, 0x7E, 0xFB, 0xFF, 0xFF, 0xFF, 0xF7, - 0xEF, 0xF7, 0xF3, 0xF7, - 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0x35, 0x79, 0xFF, - 0xBF, 0xFC, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xEF, 0xFB, 0x53, 0xDF, 0xFF, 0xEB, 0xBF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xBC, - 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF5, - 0xFF, 0xF7, 0xFF, 0xFB, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xAA, 0xEE, 0xFE, 0x3F, 0x7D, - 0xFD, 0xFF, 0xFF, 0xFF, - 0x7F, 0xAF, 0x77, 0xFB, 0xFB, 0xFF, 0xFB, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF7, 0xBE, 0xBD, 0xBD, - 0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE, 0xFF, 0xEF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFC, - 0xFF, 0xFF, 0xFF, 0xFF, 0x9A, 0xD9, 0xB8, 0xFF, 0xFF, 0x79, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xCF, - 0xFB, 0xFF, 0xEB, 0xFF, 0xEB, 0xD7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xDE, - 0xF8, 0xFB, 0xFE, 0x3F, - 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xAD, 0xBF, 0xFA, 0xFF, 0x73, - 0xDF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x3A, 0xF5, 0xB7, 0xFC, 0x3F, 0xF9, 0xFD, 0xFF, 0xFF, 0xFF, - 0x7F, 0xEF, 0xF3, 0xFF, - 0xBF, 0xFE, 0xF3, 0x9F, 0xFE, 0xFF, 0xFF, 0xFF, 0xF7, 0x3E, 0xFF, 0xFF, - 0xFF, 0xBF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xD3, 0xFE, 0xDB, 0xFF, 0xDB, 0xDF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x3E, 0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, - 0xF3, 0xFF, 0xED, 0xFF, - 0xF7, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF6, 0x3C, 0xFE, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x9F, 0xEF, 0xEF, 0xD1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x7E, 0xBF, - 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBB, 0xEF, 0xDF, 0xF1, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x3E, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xBF, - 0xEF, 0xFD, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, - 0xFC, 0x3E, 0xFE, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2E, 0xEF, 0xF3, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF7, 0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x7F, 0xAF, 0xFB, - 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xF2, 0xD6, 0xED, - 0xBD, 0xBD, 0xBD, 0x7D, - 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x92, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, - 0xAF, 0xEB, 0xEB, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFE, 0x2E, 0xFE, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x4F, 0xEF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, - 0x3C, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xCE, - 0xC3, 0xFD, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xEF, 0xCF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF7, 0xEE, 0x3E, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xDF, 0xE2, 0xFF, - 0xFF, 0xFF, 0xFB, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0xBE, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x7F, 0xEE, - 0x5F, 0xE6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, - 0x7D, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xBF, 0xF7, 0x36, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xEF, 0xD3, 0xF6, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x7F, 0xEE, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xEF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, - 0xFB, 0xFA, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xD6, 0xFD, 0xBD, 0xBD, 0xBD, - 0x7D, 0x7B, 0x7B, 0x7B, - 0x7B, 0xFB, 0xAE, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF7, 0xBA, 0xBF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xEB, 0x6B, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0x4F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, - 0x3E, 0x6E, 0xFC, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xC3, 0xC9, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x3E, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xEF, 0xFB, - 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, - 0xFE, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0xEF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFB, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF6, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, - 0xEF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFE, 0xFF, 0xF7, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x7F, 0xFA, 0xEF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE7, 0xFF, 0xFE, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xEF, 0xBF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xA7, 0xFF, 0xFC, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x7F, - 0xFE, 0xAE, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, - 0xF7, 0xFA, 0xFF, 0xFD, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, - 0x7B, 0x7B, 0xFB, 0xAF, - 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xCF, 0xFE, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE7, 0xF2, 0xFC, - 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAE, 0xEF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7E, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, - 0xFE, 0xFE, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xEF, 0xDD, 0xFE, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xAF, 0xEF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xFE, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xF6, 0x9C, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, - 0xAE, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7A, 0xFF, 0xFF, 0xFF, - 0xFF, 0xDF, 0xFF, 0xFF, - 0xFF, 0xFF, 0x6F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xF7, 0xFE, - 0xFE, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xEB, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x9E, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xEF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFE, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xCB, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFD, - 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xEF, - 0xEF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFB, 0xAF, 0x7F, 0xFF, - 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xBF, 0xFF, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x7F, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF7, 0xBC, 0xBD, - 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x7F, - 0xAF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, - 0xFE, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, - 0xFF, 0xFF, 0xEF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xBF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xEF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFE, 0xFF, 0x9F, 0x9F, - 0x9F, 0x3F, 0x3F, 0x3F, - 0x3F, 0x3F, 0xFF, 0xEF, 0xDF, 0xDF, 0xDF, 0xDF, 0xCF, 0xB7, 0xBF, 0xBF, - 0xBF, 0xBF, 0xFF, 0xBC, - 0xB9, 0x9D, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xEF, 0xD7, - 0xF5, 0xF3, 0xF1, 0xD1, - 0x65, 0xE3, 0xE3, 0xE3, 0xA3, 0xFF, 0xFE, 0x7F, 0xFE, 0xDE, 0xDE, 0xFF, - 0xBD, 0xBD, 0xBD, 0xBD, - 0xDF, 0xEF, 0xFB, 0xF7, 0xF3, 0xF3, 0xF3, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, - 0xFB, 0xFE, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - - }; diff --git a/trunk/drivers/net/pcmcia/smc91c92_cs.c b/trunk/drivers/net/pcmcia/smc91c92_cs.c index 774232c13b31..48dbb35747d8 100644 --- a/trunk/drivers/net/pcmcia/smc91c92_cs.c +++ b/trunk/drivers/net/pcmcia/smc91c92_cs.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -55,17 +56,18 @@ #include #include -/* Ositech Seven of Diamonds firmware */ -#include "ositech.h" - /*====================================================================*/ static const char *if_names[] = { "auto", "10baseT", "10base2"}; +/* Firmware name */ +#define FIRMWARE_NAME "ositech/Xilinx7OD.bin" + /* Module parameters */ MODULE_DESCRIPTION("SMC 91c92 series PCMCIA ethernet driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(FIRMWARE_NAME); #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) @@ -771,6 +773,26 @@ static int osi_config(struct pcmcia_device *link) return i; } +static int osi_load_firmware(struct pcmcia_device *link) +{ + const struct firmware *fw; + int i, err; + + err = request_firmware(&fw, FIRMWARE_NAME, &link->dev); + if (err) { + pr_err("Failed to load firmware \"%s\"\n", FIRMWARE_NAME); + return err; + } + + /* Download the Seven of Diamonds firmware */ + for (i = 0; i < fw->size; i++) { + outb(fw->data[i], link->io.BasePort1 + 2); + udelay(50); + } + release_firmware(fw); + return err; +} + static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) { struct net_device *dev = link->priv; @@ -811,11 +833,9 @@ static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) (cardid == PRODID_OSITECH_SEVEN)) || ((manfid == MANFID_PSION) && (cardid == PRODID_PSION_NET100))) { - /* Download the Seven of Diamonds firmware */ - for (i = 0; i < sizeof(__Xilinx7OD); i++) { - outb(__Xilinx7OD[i], link->io.BasePort1+2); - udelay(50); - } + rc = osi_load_firmware(link); + if (rc) + goto free_cfg_mem; } else if (manfid == MANFID_OSITECH) { /* Make sure both functions are powered up */ set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR); @@ -862,10 +882,10 @@ static int smc91c92_resume(struct pcmcia_device *link) (smc->cardid == PRODID_OSITECH_SEVEN)) || ((smc->manfid == MANFID_PSION) && (smc->cardid == PRODID_PSION_NET100))) { - /* Download the Seven of Diamonds firmware */ - for (i = 0; i < sizeof(__Xilinx7OD); i++) { - outb(__Xilinx7OD[i], link->io.BasePort1+2); - udelay(50); + i = osi_load_firmware(link); + if (i) { + pr_err("smc91c92_cs: Failed to load firmware\n"); + return i; } } if (link->open) { diff --git a/trunk/drivers/net/phy/phy.c b/trunk/drivers/net/phy/phy.c index 58b73b08dde0..3ff1f425f1bb 100644 --- a/trunk/drivers/net/phy/phy.c +++ b/trunk/drivers/net/phy/phy.c @@ -757,8 +757,7 @@ EXPORT_SYMBOL(phy_start); */ static void phy_state_machine(struct work_struct *work) { - struct delayed_work *dwork = - container_of(work, struct delayed_work, work); + struct delayed_work *dwork = to_delayed_work(work); struct phy_device *phydev = container_of(dwork, struct phy_device, state_queue); int needs_aneg = 0; diff --git a/trunk/drivers/net/qlge/qlge_ethtool.c b/trunk/drivers/net/qlge/qlge_ethtool.c index a50078627fb6..913b2a5fafc9 100644 --- a/trunk/drivers/net/qlge/qlge_ethtool.c +++ b/trunk/drivers/net/qlge/qlge_ethtool.c @@ -33,7 +33,6 @@ #include #include -#include #include "qlge.h" diff --git a/trunk/drivers/net/r8169.c b/trunk/drivers/net/r8169.c index 06c535222666..e1a638a05f86 100644 --- a/trunk/drivers/net/r8169.c +++ b/trunk/drivers/net/r8169.c @@ -2075,8 +2075,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!tp->pcie_cap && netif_msg_probe(tp)) dev_info(&pdev->dev, "no PCI Express capability\n"); - /* Unneeded ? Don't mess with Mrs. Murphy. */ - rtl8169_irq_mask_and_ack(ioaddr); + RTL_W16(IntrMask, 0x0000); /* Soft reset the chip. */ RTL_W8(ChipCmd, CmdReset); @@ -2088,6 +2087,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) msleep_interruptible(1); } + RTL_W16(IntrStatus, 0xffff); + /* Identify chip attached to board */ rtl8169_get_mac_version(tp, ioaddr); diff --git a/trunk/drivers/net/sfc/efx.c b/trunk/drivers/net/sfc/efx.c index 00c23b1babca..dee23b159df2 100644 --- a/trunk/drivers/net/sfc/efx.c +++ b/trunk/drivers/net/sfc/efx.c @@ -448,6 +448,9 @@ static void efx_init_channels(struct efx_nic *efx) WARN_ON(channel->rx_pkt != NULL); efx_rx_strategy(channel); + + netif_napi_add(channel->napi_dev, &channel->napi_str, + efx_poll, napi_weight); } } @@ -462,10 +465,6 @@ static void efx_start_channel(struct efx_channel *channel) EFX_LOG(channel->efx, "starting chan %d\n", channel->channel); - if (!(channel->efx->net_dev->flags & IFF_UP)) - netif_napi_add(channel->napi_dev, &channel->napi_str, - efx_poll, napi_weight); - /* The interrupt handler for this channel may set work_pending * as soon as we enable it. Make sure it's cleared before * then. Similarly, make sure it sees the enabled flag set. */ diff --git a/trunk/drivers/net/tc35815.c b/trunk/drivers/net/tc35815.c index b52a1c088f37..d91e95b237b7 100644 --- a/trunk/drivers/net/tc35815.c +++ b/trunk/drivers/net/tc35815.c @@ -1908,7 +1908,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget) do { tc_writel(status, &tr->Int_Src); /* write to clear */ - handled = tc35815_do_interrupt(dev, status, limit); + handled = tc35815_do_interrupt(dev, status, budget - received); if (handled >= 0) { received += handled; if (received >= budget) diff --git a/trunk/drivers/net/tokenring/3c359.c b/trunk/drivers/net/tokenring/3c359.c index 4a65fc2dd928..534c0f38483c 100644 --- a/trunk/drivers/net/tokenring/3c359.c +++ b/trunk/drivers/net/tokenring/3c359.c @@ -62,6 +62,7 @@ #include #include #include +#include #include @@ -73,8 +74,10 @@ static char version[] __devinitdata = "3c359.c v1.2.0 2/17/01 - Mike Phillips (mikep@linuxtr.net)" ; +#define FW_NAME "3com/3C359.bin" MODULE_AUTHOR("Mike Phillips ") ; MODULE_DESCRIPTION("3Com 3C359 Velocity XL Token Ring Adapter Driver \n") ; +MODULE_FIRMWARE(FW_NAME); /* Module paramters */ @@ -114,8 +117,6 @@ MODULE_PARM_DESC(message_level, "3c359: Level of reported messages") ; * will be stuck with 1555 lines of hex #'s in the code. */ -#include "3c359_microcode.h" - static struct pci_device_id xl_pci_tbl[] = { {PCI_VENDOR_ID_3COM,PCI_DEVICE_ID_3COM_3C359, PCI_ANY_ID, PCI_ANY_ID, }, @@ -364,10 +365,30 @@ static int __devinit xl_probe(struct pci_dev *pdev, return 0; } +static int xl_init_firmware(struct xl_private *xl_priv) +{ + int err; + + err = request_firmware(&xl_priv->fw, FW_NAME, &xl_priv->pdev->dev); + if (err) { + printk(KERN_ERR "Failed to load firmware \"%s\"\n", FW_NAME); + return err; + } + + if (xl_priv->fw->size < 16) { + printk(KERN_ERR "Bogus length %zu in \"%s\"\n", + xl_priv->fw->size, FW_NAME); + release_firmware(xl_priv->fw); + err = -EINVAL; + } + + return err; +} static int __devinit xl_init(struct net_device *dev) { struct xl_private *xl_priv = netdev_priv(dev); + int err; printk(KERN_INFO "%s \n", version); printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n", @@ -375,8 +396,11 @@ static int __devinit xl_init(struct net_device *dev) spin_lock_init(&xl_priv->xl_lock) ; - return xl_hw_reset(dev) ; + err = xl_init_firmware(xl_priv); + if (err == 0) + err = xl_hw_reset(dev); + return err; } @@ -386,7 +410,7 @@ static int __devinit xl_init(struct net_device *dev) */ static int xl_hw_reset(struct net_device *dev) -{ +{ struct xl_private *xl_priv = netdev_priv(dev); u8 __iomem *xl_mmio = xl_priv->xl_mmio ; unsigned long t ; @@ -396,6 +420,9 @@ static int xl_hw_reset(struct net_device *dev) u16 start ; int j ; + if (xl_priv->fw == NULL) + return -EINVAL; + /* * Reset the card. If the card has got the microcode on board, we have * missed the initialization interrupt, so we must always do this. @@ -458,25 +485,30 @@ static int xl_hw_reset(struct net_device *dev) /* * Now to write the microcode into the shared ram - * The microcode must finish at position 0xFFFF, so we must subtract - * to get the start position for the code + * The microcode must finish at position 0xFFFF, + * so we must subtract to get the start position for the code + * + * Looks strange but ensures compiler only uses + * 16 bit unsigned int */ + start = (0xFFFF - (xl_priv->fw->size) + 1) ; - start = (0xFFFF - (mc_size) + 1 ) ; /* Looks strange but ensures compiler only uses 16 bit unsigned int for this */ - printk(KERN_INFO "3C359: Uploading Microcode: "); - - for (i = start, j = 0; j < mc_size; i++, j++) { - writel(MEM_BYTE_WRITE | 0XD0000 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(microcode[j],xl_mmio + MMIO_MACDATA) ; + + for (i = start, j = 0; j < xl_priv->fw->size; i++, j++) { + writel(MEM_BYTE_WRITE | 0XD0000 | i, + xl_mmio + MMIO_MAC_ACCESS_CMD); + writeb(xl_priv->fw->data[j], xl_mmio + MMIO_MACDATA); if (j % 1024 == 0) printk("."); } printk("\n") ; - for (i=0;i < 16; i++) { - writel( (MEM_BYTE_WRITE | 0xDFFF0) + i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - writeb(microcode[mc_size - 16 + i], xl_mmio + MMIO_MACDATA) ; + for (i = 0; i < 16; i++) { + writel((MEM_BYTE_WRITE | 0xDFFF0) + i, + xl_mmio + MMIO_MAC_ACCESS_CMD); + writeb(xl_priv->fw->data[xl_priv->fw->size - 16 + i], + xl_mmio + MMIO_MACDATA); } /* @@ -1782,6 +1814,7 @@ static void __devexit xl_remove_one (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct xl_private *xl_priv=netdev_priv(dev); + release_firmware(xl_priv->fw); unregister_netdev(dev); iounmap(xl_priv->xl_mmio) ; pci_release_regions(pdev) ; diff --git a/trunk/drivers/net/tokenring/3c359.h b/trunk/drivers/net/tokenring/3c359.h index 66b1ff603234..bcb1a6b4a4c7 100644 --- a/trunk/drivers/net/tokenring/3c359.h +++ b/trunk/drivers/net/tokenring/3c359.h @@ -284,5 +284,8 @@ struct xl_private { u8 xl_laa[6] ; u32 rx_ring_dma_addr ; u32 tx_ring_dma_addr ; + + /* firmware section */ + const struct firmware *fw; }; diff --git a/trunk/drivers/net/tokenring/3c359_microcode.h b/trunk/drivers/net/tokenring/3c359_microcode.h deleted file mode 100644 index 0400c029c077..000000000000 --- a/trunk/drivers/net/tokenring/3c359_microcode.h +++ /dev/null @@ -1,1581 +0,0 @@ - -/* - * The firmware this driver downloads into the tokenring card is a - * separate program and is not GPL'd source code, even though the Linux - * side driver and the routine that loads this data into the card are. - * - * This firmware is licensed to you strictly for use in conjunction - * with the use of 3Com 3C359 TokenRing adapters. There is no - * waranty expressed or implied about its fitness for any purpose. - */ - -/* 3c359_microcode.mac: 3Com 3C359 Tokenring microcode. - * - * Notes: - * - Loaded from xl_init upon adapter initialization. - * - * Available from 3Com as part of their standard 3C359 driver. - * - * mc_size *must* must match the microcode being used, each version is a - * different length. - */ - -static int mc_size = 24880 ; - -static const u8 microcode[] = { - 0xfe,0x3a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x33,0x2f,0x30,0x32,0x2f,0x39,0x39,0x20,0x31 -,0x37,0x3a,0x31,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46 -,0x00,0x00,0x07,0xff,0x02,0x00,0xfe,0x9f,0x06,0x00,0x00,0x7c,0x48,0x00,0x00,0x70 -,0x82,0x00,0xff,0xff,0x86,0x00,0xff,0xff,0x88,0x00,0xff,0xff,0x9a,0x00,0xff,0xff -,0xff,0xff,0x11,0x00,0xc0,0x00,0xff,0xff,0xff,0xff,0x11,0x22,0x33,0x44,0x55,0x66 -,0x33,0x43,0x4f,0x4d,0x20,0x42,0x41,0x42,0x45,0x11,0x40,0xc0,0x00,0xff,0xff,0xff -,0xff,0x11,0x22,0x33,0x44,0x55,0x66,0x53,0x74,0x61,0x72,0x74,0x20,0x6f,0x66,0x20 -,0x4c,0x4c,0x43,0x20,0x66,0x72,0x61,0x6d,0x65,0x2e,0x20,0x20,0x54,0x6f,0x74,0x61 -,0x6c,0x20,0x64,0x61,0x74,0x61,0x20,0x73,0x69,0x7a,0x65,0x20,0x69,0x73,0x20,0x78 -,0x78,0x78,0x20,0x20,0x20,0x42,0x41,0x42,0x45,0xe8,0xd2,0x01,0x83,0x3e,0xf7,0x34 -,0x00,0x75,0x21,0xe8,0x41,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75,0x17,0xe8,0x82,0x00 -,0x83,0x3e,0xf7,0x34,0x00,0x75,0x0d,0xe8,0xbf,0x00,0x83,0x3e,0xf7,0x34,0x00,0x75 -,0x03,0xe8,0x41,0x02,0xc3,0x1e,0xb8,0x00,0xf0,0x8e,0xd8,0x33,0xf6,0xb9,0x00,0x80 -,0x33,0xdb,0xad,0x03,0xd8,0xe2,0xfb,0x1f,0xb8,0x00,0x00,0x83,0xfb,0x00,0x74,0x03 -,0xb8,0x22,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x56,0x00,0xb0,0xff,0xee,0x33,0xc0 -,0x8e,0xc0,0x33,0xf6,0xb9,0xff,0x7f,0x83,0x3e,0xff,0x34,0x00,0x74,0x08,0x8d,0x3e -,0x30,0x61,0xd1,0xef,0x2b,0xcf,0x26,0x8b,0x1c,0x26,0xc7,0x04,0xff,0xff,0x26,0x83 -,0x3c,0xff,0x75,0x17,0x26,0xc7,0x04,0x00,0x00,0x26,0x83,0x3c,0x00,0x75,0x0c,0x26 -,0x89,0x1c,0x46,0x46,0xe2,0xe0,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x24,0x00,0xa3,0xf7 -,0x34,0xc3,0xfa,0xb4,0xd7,0x9e,0x73,0x3a,0x75,0x38,0x79,0x36,0x7b,0x34,0x9f,0xb1 -,0x05,0xd2,0xec,0x73,0x2d,0xb0,0x40,0xd0,0xe0,0x71,0x27,0x79,0x25,0xd0,0xe0,0x73 -,0x21,0x7b,0x1f,0x32,0xc0,0x75,0x1b,0x32,0xe4,0x9e,0x72,0x16,0x74,0x14,0x78,0x12 -,0x7a,0x10,0x9f,0xd2,0xec,0x72,0x0b,0xd0,0xe4,0x70,0x07,0x75,0x05,0xb8,0x00,0x00 -,0xeb,0x03,0xb8,0x26,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0xba,0x5a,0x00,0x33,0xc0,0xef -,0xef,0xef,0xef,0xb0,0x00,0xe6,0x56,0xb0,0x00,0xe6,0x54,0xba,0x52,0x00,0xb8,0x01 -,0x01,0xef,0xe8,0xca,0x00,0x3c,0x01,0x75,0x7f,0xe8,0x83,0x00,0xba,0x52,0x00,0xb8 -,0x02,0x02,0xef,0xe8,0xb9,0x00,0x3c,0x02,0x75,0x6e,0xe8,0x7a,0x00,0xba,0x52,0x00 -,0xb8,0x04,0x04,0xef,0xe8,0xa8,0x00,0x3c,0x04,0x75,0x5d,0xe8,0x71,0x00,0xba,0x52 -,0x00,0xb8,0x08,0x08,0xef,0xe8,0x97,0x00,0x3c,0x08,0x75,0x4c,0xe8,0x68,0x00,0xba -,0x52,0x00,0xb8,0x10,0x10,0xef,0xe8,0x86,0x00,0x3c,0x10,0x75,0x3b,0xe8,0x5f,0x00 -,0xba,0x52,0x00,0xb8,0x20,0x20,0xef,0xe8,0x75,0x00,0x3c,0x20,0x75,0x2a,0xe8,0x56 -,0x00,0xba,0x52,0x00,0xb8,0x40,0x40,0xef,0xe8,0x64,0x00,0x3c,0x40,0x75,0x19,0xe8 -,0x4d,0x00,0xba,0x52,0x00,0xb8,0x80,0x80,0xef,0xe8,0x53,0x00,0x3c,0x80,0x75,0x08 -,0xe8,0x44,0x00,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x28,0x00,0xa3,0xf7,0x34,0xc3,0xba -,0x5a,0x00,0xb8,0x00,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x01,0x80,0xef,0xc3,0xba -,0x5a,0x00,0xb8,0x02,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x03,0x80,0xef,0xc3,0xba -,0x5a,0x00,0xb8,0x04,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x05,0x80,0xef,0xc3,0xba -,0x5a,0x00,0xb8,0x06,0x80,0xef,0xc3,0xba,0x5a,0x00,0xb8,0x07,0x80,0xef,0xc3,0xb9 -,0xff,0xff,0xe4,0x58,0xe4,0x54,0x3c,0x00,0x75,0x03,0x49,0x75,0xf7,0xc3,0xfa,0x32 -,0xc0,0xe6,0x56,0xe4,0x56,0x3c,0x00,0x74,0x03,0xe9,0x82,0x00,0xb0,0xff,0xe6,0x56 -,0xe4,0x56,0x3c,0xff,0x75,0x78,0xba,0x52,0x00,0xb8,0xff,0xff,0xef,0xed,0x3c,0xff -,0x75,0x6c,0xb8,0x00,0xff,0xef,0xed,0x3c,0x00,0x75,0x63,0xb0,0xff,0xe6,0x54,0xe4 -,0x54,0x3c,0xff,0x75,0x59,0x32,0xc0,0xe6,0x54,0xe4,0x54,0x3c,0x00,0x75,0x4f,0xb0 -,0x0f,0xe6,0x50,0xe4,0x50,0x24,0x0f,0x3c,0x0f,0x75,0x43,0xb0,0x00,0xe6,0x50,0xe4 -,0x50,0x24,0x0f,0x3c,0x00,0x75,0x37,0x8c,0xc8,0x8e,0xc0,0xbe,0x70,0x00,0x26,0x8b -,0x14,0x26,0x8b,0x5c,0x02,0xb8,0x00,0x00,0xef,0xed,0x23,0xc3,0x3d,0x00,0x00,0x75 -,0x1d,0xb8,0xff,0xff,0x23,0xc3,0xef,0x8b,0xc8,0xed,0x23,0xc3,0x3b,0xc1,0x75,0x0e -,0x83,0xc6,0x04,0x26,0x83,0x3c,0xff,0x75,0xd5,0xb8,0x00,0x00,0xeb,0x03,0xb8,0x2a -,0x00,0xa3,0xf7,0x34,0xc3,0xfa,0x33,0xc0,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xab -,0xbf,0x00,0x30,0xb9,0x17,0x00,0xf3,0xab,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xab -,0xbf,0x00,0x32,0xb9,0x40,0x00,0xf3,0xab,0xfc,0x1e,0x8c,0xc8,0x8e,0xd8,0x33,0xc0 -,0x8e,0xc0,0xbe,0x92,0x00,0xbf,0x00,0x20,0xb9,0x17,0x00,0xf3,0xa4,0xbe,0xa9,0x00 -,0xbf,0x00,0x22,0xb9,0x40,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0xfb,0x34,0x64,0x00,0xba -,0x08,0x00,0xb8,0x0f,0x00,0xef,0xe8,0x82,0x01,0xe8,0x9b,0x01,0x72,0x0d,0xc7,0x06 -,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34,0x04,0x00,0xc3,0xba,0x0a,0x00,0x33,0xc0 -,0xef,0xe8,0x98,0x01,0xe8,0xb5,0x01,0xb8,0x17,0x00,0xba,0x9c,0x00,0xef,0xb8,0x00 -,0x10,0xba,0x9a,0x00,0xef,0xb8,0x17,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x8c -,0x00,0xef,0xb8,0x00,0x18,0xba,0x86,0x00,0xef,0xb8,0x0c,0x00,0xba,0x82,0x00,0xef -,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x02,0x00,0xef,0xba,0x06,0x00,0x33,0xc0 -,0xef,0xba,0x04,0x00,0xb8,0x60,0x00,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba -,0x80,0x00,0xb9,0xff,0xff,0xed,0xa9,0x01,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x3e,0xba -,0x0a,0x00,0xed,0xa9,0x00,0x40,0x74,0x35,0xa9,0x00,0x20,0x74,0x30,0x33,0xc0,0xef -,0x51,0xb9,0xc8,0x00,0xe2,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x30,0x83 -,0xf9,0x17,0x75,0x18,0x49,0x49,0xbe,0x02,0x20,0xbf,0x06,0x30,0xf3,0xa6,0x1f,0x23 -,0xc9,0x75,0x0a,0xff,0x0e,0xfb,0x34,0x74,0x12,0xe9,0x4d,0xff,0x1f,0xb8,0x2c,0x00 -,0xbb,0x00,0x00,0xa3,0xf7,0x34,0x89,0x1e,0xf9,0x34,0xc3,0xc7,0x06,0xfb,0x34,0x64 -,0x00,0xe8,0xd3,0x00,0x72,0x0d,0xc7,0x06,0xf7,0x34,0x2c,0x00,0xc7,0x06,0xf9,0x34 -,0x04,0x00,0xc3,0xe8,0xd6,0x00,0xe8,0xf3,0x00,0xb8,0x03,0x00,0xba,0x82,0x00,0xef -,0xb8,0x40,0x80,0xba,0x98,0x00,0xef,0xb8,0x00,0x11,0xba,0x96,0x00,0xef,0xb8,0x40 -,0x00,0xa9,0x01,0x00,0x74,0x01,0x40,0xba,0x92,0x00,0xef,0xb8,0x00,0x19,0xba,0x8e -,0x00,0xef,0xba,0x02,0x00,0xed,0x25,0xf9,0xff,0x0d,0x06,0x00,0xef,0xba,0x06,0x00 -,0x33,0xc0,0xef,0xba,0x00,0x00,0xb8,0x18,0x00,0xef,0xba,0x80,0x00,0xb9,0xff,0xff -,0xed,0xa9,0x20,0x00,0x75,0x04,0xe2,0xf8,0xeb,0x43,0xba,0x0a,0x00,0xed,0xa9,0x00 -,0x40,0x74,0x3a,0xa9,0x00,0x20,0x74,0x35,0x33,0xc0,0xef,0x51,0xb9,0xc8,0x00,0xe2 -,0xfe,0x59,0x1e,0x06,0x1f,0x26,0x8b,0x0e,0x02,0x32,0x83,0xf9,0x40,0x75,0x1d,0x49 -,0x49,0xbe,0x02,0x22,0xbf,0x06,0x32,0xf3,0xa6,0x1f,0x23,0xc9,0x75,0x0f,0xff,0x0e -,0xfb,0x34,0x74,0x03,0xe9,0x5a,0xff,0xb8,0x00,0x00,0xeb,0x0b,0x1f,0xb8,0x2c,0x00 -,0xbb,0x02,0x00,0x89,0x1e,0xf9,0x34,0xa3,0xf7,0x34,0xc3,0xba,0x02,0x00,0xb8,0x00 -,0x9c,0xef,0xba,0x00,0x00,0xb8,0x00,0x84,0xef,0x33,0xc0,0xef,0xba,0x0a,0x00,0xef -,0xba,0x0e,0x00,0x33,0xc0,0xef,0xc3,0xba,0x0a,0x00,0xb9,0xff,0xff,0xed,0x25,0x00 -,0x60,0x3d,0x00,0x60,0x74,0x04,0xe2,0xf5,0xf8,0xc3,0xf9,0xc3,0xb0,0x00,0xe6,0x56 -,0xb8,0x00,0xff,0xba,0x52,0x00,0xef,0xb9,0xff,0xff,0xba,0x58,0x00,0xed,0x25,0xef -,0x00,0x74,0x08,0xba,0x5a,0x00,0x33,0xc0,0xef,0xe2,0xef,0xc3,0xba,0x80,0x00,0xed -,0xba,0x84,0x00,0xef,0xba,0x80,0x00,0xed,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0xc6,0x06,0xec,0x34,0x15,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0x1e,0x8c,0xc8,0xbe,0x40 -,0x54,0xbf,0x60,0xfe,0x8e,0xd8,0xb9,0x10,0x00,0xf3,0xa4,0x1f,0xc7,0x06,0x80,0x36 -,0x10,0x35,0xc7,0x06,0x8c,0x36,0x30,0x35,0x8d,0x06,0x38,0x35,0xa3,0x30,0x35,0xa3 -,0x32,0x35,0x05,0x33,0x01,0xa3,0x34,0x35,0xc7,0x06,0x36,0x35,0x50,0x01,0xc7,0x06 -,0x84,0x36,0x80,0xfe,0xc7,0x06,0x88,0x36,0xc0,0xfe,0xc6,0x06,0xc2,0xfe,0xff,0xc6 -,0x06,0x93,0x36,0x80,0xc6,0x06,0x92,0x36,0x00,0xc6,0x06,0x80,0xfe,0x80,0xc7,0x06 -,0x82,0xfe,0x54,0x50,0xc7,0x06,0x84,0xfe,0x2b,0x4d,0xe5,0xce,0xa9,0x02,0x00,0x75 -,0x08,0xc6,0x06,0x81,0xfe,0x23,0xe9,0x05,0x00,0xc6,0x06,0x81,0xfe,0x22,0xa1,0xf7 -,0x34,0xa3,0x86,0xfe,0xb8,0x48,0x34,0x86,0xe0,0xa3,0x88,0xfe,0x8d,0x06,0x4e,0x34 -,0x86,0xe0,0xa3,0x8a,0xfe,0xb8,0x58,0x34,0x86,0xe0,0xa3,0x8c,0xfe,0xb8,0x9c,0x34 -,0x86,0xe0,0xa3,0x8e,0xfe,0x8d,0x06,0x20,0x03,0x86,0xe0,0xa3,0x90,0xfe,0x33,0xc0 -,0xba,0x72,0x00,0xef,0x33,0xc0,0xba,0x74,0x00,0xef,0xba,0x76,0x00,0xef,0xb8,0x80 -,0xfe,0x86,0xe0,0xba,0x72,0x00,0xef,0xe8,0xbf,0x07,0xba,0x0c,0x01,0xb8,0x40,0x40 -,0xef,0xed,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0xb9 -,0x0a,0x00,0xe8,0x94,0x00,0xba,0x6a,0x00,0xb8,0x03,0x00,0xc1,0xe0,0x08,0xef,0xa1 -,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33,0xc1 -,0xe8,0x04,0xcd,0x39,0xc7,0x06,0x90,0x36,0xff,0xff,0xe9,0xe3,0x00,0x63,0x0d,0x66 -,0x0d,0x66,0x0d,0x8a,0x0d,0xe6,0x0e,0x75,0x12,0x2e,0x0f,0x03,0x0f,0x50,0x0f,0x60 -,0x0d,0x60,0x0d,0x60,0x0d,0xed,0x0f,0xe9,0x12,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 -,0x0d,0x60,0x0d,0x22,0x10,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xfe,0x10,0x60 -,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0xaf,0x0f,0x32,0x10,0x37 -,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 -,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60,0x0d,0x60 -,0x0d,0x64,0x0e,0x00,0x0f,0x95,0x09,0x60,0x0a,0x49,0xbb,0xff,0xff,0xba,0x6a,0x00 -,0xed,0xa9,0x00,0x20,0x74,0x38,0x80,0x3e,0x80,0xfe,0x12,0x75,0x31,0xe8,0x4a,0x00 -,0xa1,0x32,0x34,0xa3,0xa2,0x33,0xc7,0x06,0xa6,0x33,0x04,0x00,0x8d,0x06,0xa0,0x33 -,0xc1,0xe8,0x04,0xcd,0x39,0xe8,0x22,0x00,0xc7,0x06,0xf3,0x34,0x46,0x00,0xc7,0x06 -,0xf5,0x34,0xff,0xff,0xc7,0x06,0x90,0x36,0xff,0xff,0x58,0xe9,0x32,0x00,0x4b,0x83 -,0xfb,0x00,0x75,0xb9,0x83,0xf9,0x00,0x75,0xb0,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03 -,0x00,0xc1,0xe0,0x08,0x0d,0x03,0x00,0xef,0x5a,0xc3,0x52,0xba,0x6a,0x00,0xb8,0x03 -,0x00,0xc1,0xe0,0x08,0xef,0x5a,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x68,0x80,0x07,0xa1,0x90,0x36,0xcd,0x35,0x8b,0x36,0x24,0x02,0x2e,0xff,0xa4,0x35 -,0x0a,0xfa,0x8a,0x26,0x94,0x36,0x88,0x26,0xe8,0x34,0xc6,0x06,0x94,0x36,0x00,0xfb -,0x22,0xe4,0x75,0x01,0xc3,0xf6,0xc4,0x20,0x74,0x7d,0xf6,0xc4,0x08,0x74,0x05,0x80 -,0x0e,0x92,0x36,0x04,0x80,0x26,0xe8,0x34,0xd7,0xc4,0x1e,0x84,0x36,0x26,0x8b,0x37 -,0x81,0xe6,0xff,0x00,0x83,0xfe,0x20,0x76,0x05,0xb0,0x01,0xe9,0x28,0x00,0x53,0x06 -,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0x07,0x5b,0x26,0x88,0x47,0x02,0x3c,0xff,0x74 -,0x07,0x3c,0xfe,0x75,0x11,0xe9,0x3b,0x00,0xf6,0x06,0x92,0x36,0x08,0x75,0x34,0xf6 -,0x06,0x92,0x36,0x04,0x74,0x2d,0x80,0x26,0x92,0x36,0xf3,0x80,0x3e,0x95,0x36,0x00 -,0x75,0x21,0x26,0x80,0x3f,0x05,0x75,0x13,0xc6,0x06,0x95,0x36,0x00,0x26,0x80,0x7f -,0x06,0x00,0x74,0x07,0x26,0x8b,0x47,0x04,0xa2,0x95,0x36,0xba,0x0c,0x01,0xb8,0x40 -,0x40,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x10,0x75,0x03,0xe9,0x5b,0x00,0xf6 -,0xc4,0x04,0x74,0x05,0x80,0x0e,0x92,0x36,0x01,0x80,0x26,0xe8,0x34,0xeb,0xc4,0x3e -,0x88,0x36,0x26,0x8b,0x35,0x83,0xe6,0x7f,0x83,0xfe,0x12,0x72,0x08,0x26,0xc6,0x45 -,0x02,0x01,0xe9,0x24,0x00,0x83,0xc6,0x20,0xd1,0xe6,0x2e,0xff,0x94,0x9d,0x06,0xc4 -,0x3e,0x88,0x36,0x26,0x88,0x45,0x02,0x3c,0xff,0x75,0x0e,0xf6,0x06,0x92,0x36,0x01 -,0x74,0x14,0xf6,0x06,0x92,0x36,0x02,0x75,0x0d,0x80,0x26,0x92,0x36,0xfc,0xba,0x0c -,0x01,0xb8,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x08,0x74,0x22,0x80 -,0x26,0xe8,0x34,0xf7,0x80,0x0e,0x92,0x36,0x04,0xf6,0x06,0x92,0x36,0x08,0x74,0x11 -,0x80,0x26,0x92,0x36,0xf3,0xba,0x0c,0x01,0xb8,0x40,0x40,0xef,0xed,0x8a,0x26,0xe8 -,0x34,0xf6,0xc4,0x04,0x74,0x22,0x80,0x26,0xe8,0x34,0xfb,0x80,0x0e,0x92,0x36,0x01 -,0xf6,0x06,0x92,0x36,0x02,0x75,0x11,0x80,0x26,0x92,0x36,0xfe,0xba,0x0c,0x01,0xb8 -,0x20,0x20,0xef,0xed,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x01,0x74,0x67,0x80,0x26,0xe8 -,0x34,0xfe,0x80,0x3e,0xe8,0xff,0x00,0x74,0x39,0x80,0x3e,0xe8,0xff,0x04,0x74,0x32 -,0x80,0x3e,0xe8,0xff,0x01,0x75,0x21,0xe5,0x80,0xa9,0x00,0x07,0x74,0x0a,0xba,0x9e -,0x00,0xb8,0x00,0x02,0xef,0xe9,0xef,0xff,0xc6,0x06,0xe8,0xff,0x03,0xba,0x0c,0x01 -,0xb8,0x08,0x08,0xef,0xed,0xe9,0x28,0x00,0x80,0x3e,0xe8,0xff,0x03,0x74,0x06,0xe9 -,0x1e,0x00,0xe9,0x00,0x00,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0xe5,0x00,0x0d -,0x18,0x00,0xe7,0x00,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xc6,0x06,0xe8,0xff,0x04 -,0x8a,0x26,0xe8,0x34,0xf6,0xc4,0x02,0x74,0x0d,0x80,0x26,0xe8,0x34,0xfd,0x80,0x26 -,0x92,0x36,0xbf,0xe8,0x4f,0x0b,0xfa,0xa0,0xe8,0x34,0x08,0x06,0x94,0x36,0xc6,0x06 -,0xe8,0x34,0x00,0xfb,0xc3,0xe8,0xe7,0x0f,0xc4,0x1e,0x84,0x36,0x2e,0xff,0x16,0x01 -,0x07,0x26,0x88,0x47,0x02,0xe9,0x7e,0xfe,0xe8,0x2d,0x10,0xc4,0x1e,0x84,0x36,0x2e -,0xff,0x16,0x03,0x07,0x26,0x88,0x47,0x02,0xe9,0x6b,0xfe,0x8e,0x06,0x26,0x02,0x2e -,0xff,0x16,0x07,0x07,0xc3,0xc3,0x83,0x3e,0xf5,0x34,0x00,0x74,0x0f,0xff,0x0e,0xf3 -,0x34,0x75,0x09,0xe8,0xc4,0xfd,0xc7,0x06,0xf5,0x34,0x00,0x00,0xf6,0x06,0x93,0x36 -,0x20,0x74,0x30,0xa1,0xc2,0x34,0x3b,0x06,0xe9,0x34,0xa3,0xe9,0x34,0x74,0x24,0x80 -,0x3e,0x95,0x36,0x00,0x75,0x1d,0xf7,0x06,0xe6,0x34,0x20,0x00,0x74,0x12,0xa9,0x20 -,0x00,0x74,0x0d,0x83,0x26,0xc2,0x34,0xdf,0x83,0x26,0xe9,0x34,0xdf,0xe9,0x03,0x00 -,0xe8,0xdd,0x09,0xba,0x06,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e -,0x03,0x16,0x74,0x34,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06,0x74 -,0x34,0xba,0x02,0x01,0xed,0x8b,0xd0,0x81,0xe2,0x00,0xc0,0xc1,0xea,0x0e,0x03,0x16 -,0x70,0x34,0xc1,0xe0,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0xc7 -,0x06,0xa6,0x33,0x04,0x00,0xc7,0x06,0xaa,0x33,0x00,0x00,0x8d,0x06,0xa0,0x33,0xc1 -,0xe8,0x04,0xcd,0x39,0xc3,0x95,0x09,0x95,0x09,0x65,0x09,0x78,0x09,0x95,0x09,0x95 -,0x09,0x91,0x07,0x95,0x09,0x96,0x09,0x8b,0x09,0x95,0x09,0x95,0x09,0x95,0x09,0x95 -,0x09,0x95,0x09,0x95,0x09,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x8b,0xc0,0x90 -,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9,0xcc,0x00,0x8c,0xc0,0x40,0x8e,0xc0,0x26 -,0x8b,0x0e,0x06,0x00,0x86,0xe9,0x26,0x89,0x0e,0x06,0x00,0x8c,0xc2,0xc1,0xe2,0x04 -,0xbe,0x0e,0x00,0x26,0xa1,0x04,0x00,0xd0,0xe0,0x24,0xc0,0x8a,0xe0,0xc0,0xec,0x04 -,0x0a,0xc4,0x26,0xa2,0x05,0x00,0x26,0xa1,0x08,0x00,0xa9,0x00,0xc0,0x74,0x03,0xe9 -,0x9e,0x00,0x26,0xf6,0x06,0x10,0x00,0x80,0x75,0x03,0xe9,0x0a,0x00,0x26,0xa0,0x16 -,0x00,0x24,0x1f,0x32,0xe4,0x03,0xf0,0x80,0x3e,0xec,0x34,0x06,0x72,0x5c,0x80,0x3e -,0x95,0x36,0x00,0x75,0x66,0x8b,0xfa,0x33,0xdb,0x8e,0xc3,0x26,0x89,0x1d,0x26,0x88 -,0x5d,0x04,0x51,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x21,0x09 -,0x58,0x59,0x0b,0xdb,0x74,0x34,0xfe,0x0e,0xe6,0x3a,0x26,0xc6,0x07,0x81,0x26,0xc6 -,0x47,0x01,0x00,0x26,0xc6,0x47,0x02,0xff,0x26,0xc7,0x47,0x04,0x00,0x00,0x26,0x89 -,0x4f,0x0a,0x86,0xf2,0x26,0x89,0x57,0x06,0x26,0x89,0x77,0x08,0x26,0xc6,0x47,0x09 -,0x00,0x26,0xc6,0x47,0x0c,0x02,0xe8,0x8c,0x09,0xc3,0xff,0x06,0xec,0x33,0x8c,0xc0 -,0x48,0x8e,0xc0,0xfa,0xe8,0x97,0x10,0xfb,0xe9,0xeb,0xff,0x8c,0xc0,0x48,0x8e,0xc0 -,0xfa,0xe8,0x8a,0x10,0xfb,0xc3,0x8c,0xc0,0x8e,0xc0,0xfa,0xe8,0x80,0x10,0xfb,0xc3 -,0x80,0x3e,0x95,0x36,0x00,0x75,0x03,0xe9,0xc2,0x00,0xbf,0x08,0x00,0x26,0xf6,0x06 -,0x10,0x00,0x80,0x75,0x05,0x03,0xfe,0xe9,0x0c,0x00,0x26,0xa0,0x16,0x00,0x24,0x1f -,0x32,0xe4,0x03,0xf0,0x03,0xfe,0xa0,0x95,0x36,0x3c,0x00,0x75,0x03,0xe9,0x9c,0x00 -,0x3c,0x01,0x74,0x0b,0x3c,0x02,0x74,0x14,0x3c,0x03,0x74,0x1d,0xe9,0x8d,0x00,0xc6 -,0x06,0x96,0x36,0x01,0xe8,0x3c,0x01,0x72,0x27,0xe9,0x80,0x00,0xc6,0x06,0x96,0x36 -,0x02,0xe8,0x83,0x00,0x72,0x1a,0xe9,0x73,0x00,0xc6,0x06,0x96,0x36,0x01,0xe8,0x22 -,0x01,0x72,0x0d,0xc6,0x06,0x96,0x36,0x02,0xe8,0x6c,0x00,0x72,0x03,0xe9,0x5c,0x00 -,0x53,0x06,0x50,0xc4,0x1e,0x8c,0x36,0xb9,0x0b,0x00,0x33,0xc0,0xe8,0x42,0x08,0x58 -,0x26,0xc6,0x07,0x82,0x26,0xc6,0x47,0x02,0xff,0x8d,0x06,0xe0,0xfe,0x86,0xc4,0x26 -,0x89,0x47,0x06,0xa0,0x96,0x36,0x26,0x88,0x47,0x08,0xe8,0xc8,0x08,0x07,0x5b,0x83 -,0x26,0xad,0x36,0xfe,0xa1,0xad,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef -,0xed,0xba,0x10,0x01,0xb8,0x02,0x02,0xef,0xed,0x52,0xba,0xe0,0x00,0xb8,0x41,0x10 -,0xef,0x5a,0xb8,0x9c,0x03,0xcd,0x39,0xc6,0x06,0x95,0x36,0x00,0x8c,0xc0,0x48,0x8e -,0xc0,0xfa,0xe8,0xa9,0x0f,0xfb,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x8b -,0xf0,0x8d,0x3e,0x20,0xf3,0x51,0xb1,0x0a,0x26,0x83,0x7d,0x0c,0x01,0x75,0x2a,0x57 -,0x26,0x83,0x7d,0x0e,0x00,0x74,0x06,0xe8,0x2f,0x00,0xe9,0x03,0x00,0xe8,0x66,0x07 -,0x5f,0x73,0x16,0x33,0xc0,0x8e,0xd8,0x26,0x8b,0x4d,0x12,0x8d,0x75,0x20,0x8d,0x3e -,0xe0,0xfe,0xf3,0xa4,0x59,0x07,0x1f,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20 -,0x01,0xe9,0xc4,0xff,0x59,0x07,0x1f,0xf8,0xc3,0x51,0x50,0x53,0x56,0x52,0x57,0x33 -,0xdb,0x26,0x8a,0x5d,0x0e,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0x5a,0x87,0xd7,0x26 -,0x8a,0x45,0x14,0x87,0xd7,0x42,0x32,0xff,0x80,0xff,0x08,0x75,0x08,0xfe,0xcb,0x22 -,0xdb,0x75,0xea,0x33,0xdb,0x23,0xdb,0x74,0x06,0xfe,0xc7,0xd0,0xc8,0x73,0x0c,0x50 -,0x26,0x8a,0x05,0x38,0x04,0x58,0x74,0x03,0xe9,0x0a,0x00,0x49,0x46,0x47,0x23,0xc9 -,0x74,0x0a,0xe9,0xd3,0xff,0x5a,0x5e,0x5b,0x58,0x59,0xf8,0xc3,0x5a,0x5e,0x5b,0x58 -,0x59,0xf9,0xc3,0x1e,0x06,0x1f,0x06,0x33,0xc0,0x8e,0xc0,0x86,0xcd,0x2b,0xce,0x8b -,0xf7,0x8b,0xc1,0x33,0xc9,0x80,0x3c,0xff,0x74,0x16,0x80,0xf9,0x06,0x73,0x09,0x32 -,0xc9,0x46,0x48,0x74,0x2e,0xe9,0xed,0xff,0x3d,0x60,0x00,0x73,0x0c,0xe9,0x23,0x00 -,0xfe,0xc1,0x46,0x48,0x74,0x1d,0xe9,0xdc,0xff,0xb8,0x10,0x00,0x8d,0x3e,0x18,0x34 -,0x32,0xed,0xb1,0x06,0xf3,0xa6,0x74,0x03,0xe9,0x08,0x00,0x48,0x23,0xc0,0x74,0x07 -,0xe9,0xe9,0xff,0x07,0x1f,0xf8,0xc3,0x8d,0x36,0x18,0x34,0x33,0xc0,0x8e,0xd8,0x8d -,0x3e,0xe0,0xfe,0xb8,0x10,0x00,0xb9,0x06,0x00,0x56,0xf3,0xa4,0x5e,0x48,0x3d,0x00 -,0x00,0x75,0xf3,0x07,0x1f,0xf9,0xc3,0xff,0x06,0xe4,0x33,0xc6,0x06,0xeb,0x34,0x00 -,0x26,0x8b,0x45,0x06,0x86,0xe0,0xc1,0xe8,0x04,0x48,0x06,0x8e,0xc0,0xfe,0x06,0xe6 -,0x3a,0xfa,0xe8,0x69,0x0e,0xfb,0x07,0xb0,0xff,0xc3,0x00,0x00,0x00,0x00,0x00,0x00 -,0xb0,0x01,0xc3,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3 -,0x8b,0x0e,0x97,0x36,0x81,0xe1,0x80,0x30,0x26,0x8b,0x47,0x04,0x25,0x7f,0xcf,0x0b -,0xc1,0xa3,0x97,0x36,0xa3,0xe6,0x34,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x74 -,0x03,0xb0,0x03,0xc3,0x26,0x8b,0x47,0x08,0xa3,0x97,0x36,0xa3,0xe6,0x34,0x26,0x8a -,0x47,0x20,0xa2,0xfd,0x34,0x3c,0x01,0x75,0x06,0xc7,0x06,0xa1,0x36,0x00,0x00,0x26 -,0x8a,0x47,0x21,0xa2,0xfe,0x34,0x26,0x8b,0x47,0x0a,0xa3,0x18,0x34,0xa3,0x58,0x34 -,0x26,0x8b,0x47,0x0c,0xa3,0x1a,0x34,0xa3,0x5a,0x34,0x26,0x8b,0x47,0x0e,0xa3,0x1c -,0x34,0xa3,0x5c,0x34,0xc6,0x06,0x2a,0x34,0xc0,0x26,0x8b,0x47,0x14,0x25,0x7f,0xff -,0x09,0x06,0x2c,0x34,0x26,0x8b,0x47,0x16,0x25,0xff,0xfe,0x25,0xff,0xfc,0x09,0x06 -,0x2e,0x34,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47,0x10,0xa3,0x02,0x34,0x26,0x8b -,0x47,0x12,0xa3,0x04,0x34,0x06,0x53,0xe8,0x84,0x0a,0x5b,0x07,0x3d,0x00,0x00,0x75 -,0x07,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3,0xb9,0x00,0x01,0xa1,0xac,0x33,0x33 -,0xd2,0xf7,0xf9,0xa3,0xae,0x33,0x91,0x49,0x33,0xd2,0xf7,0xe9,0x05,0x00,0x3b,0xa3 -,0x46,0x34,0xbf,0x00,0x3b,0x89,0x3e,0x44,0x34,0xba,0x68,0x00,0xb8,0xe0,0xe0,0xef -,0xa1,0xae,0x33,0xe7,0x62,0xa1,0xae,0x33,0xba,0x08,0x01,0xef,0xa1,0x44,0x34,0xe7 -,0x64,0xa1,0x44,0x34,0xba,0x0a,0x01,0xef,0xb8,0x00,0x01,0x2d,0x04,0x00,0x0d,0x00 -,0x10,0xe7,0x92,0xc3,0x3d,0x00,0x00,0x74,0x0a,0x26,0x89,0x47,0x07,0xe8,0x83,0x3a -,0xb0,0x07,0xc3,0xa1,0xae,0x33,0x26,0x89,0x47,0x2b,0xa1,0x44,0x34,0x26,0x89,0x47 -,0x2d,0xa1,0x46,0x34,0x26,0x89,0x47,0x2f,0x80,0x0e,0x93,0x36,0x20,0xa1,0x88,0x36 -,0x86,0xe0,0x26,0x89,0x47,0x08,0xa1,0x84,0x36,0x86,0xe0,0x26,0x89,0x47,0x0a,0xa1 -,0x80,0x36,0x86,0xe0,0x26,0x89,0x47,0x0c,0xb8,0x60,0xfe,0x86,0xe0,0x26,0x89,0x47 -,0x0e,0xa0,0xa1,0x36,0x26,0x88,0x47,0x10,0x8b,0x36,0x88,0x36,0x26,0xc6,0x44,0x02 -,0xff,0xe5,0x9e,0xa9,0x00,0x08,0x74,0x0c,0xba,0x84,0x00,0xed,0x0d,0x08,0x00,0xef -,0xba,0x8e,0x00,0xef,0xe5,0x02,0x25,0xf9,0xff,0xe7,0x02,0xba,0x10,0x01,0xb8,0x02 -,0x02,0xef,0xed,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3 -,0x80,0x26,0x93,0x36,0x9f,0xe8,0x8d,0x0a,0x80,0x0e,0x92,0x36,0x08,0xb0,0xfe,0xc3 -,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x2a -,0x34,0xc0,0x26,0x8b,0x47,0x06,0x25,0x7f,0xff,0xa3,0x2c,0x34,0x26,0x8b,0x47,0x08 -,0x25,0xff,0xfe,0x25,0xff,0xfc,0xa3,0x2e,0x34,0xcd,0x52,0xb0,0x00,0xc3,0xf6,0x06 -,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xc6,0x06,0x00,0x34,0xc0,0x26,0x8b,0x47 -,0x06,0xa3,0x02,0x34,0x26,0x8b,0x47,0x08,0xa3,0x04,0x34,0xcd,0x52,0xb0,0x00,0xc3 -,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x57,0x8d,0x7f,0x06,0x51,0xb9 -,0x07,0x00,0x33,0xc0,0xf3,0xab,0x59,0x8d,0x7f,0x06,0xa1,0x7a,0x34,0x03,0x06,0x39 -,0x37,0x26,0x88,0x05,0xa1,0x95,0x37,0x26,0x88,0x45,0x02,0xa1,0x80,0x34,0x03,0x06 -,0x76,0x34,0x26,0x88,0x45,0x07,0xa1,0xc6,0x34,0x26,0x88,0x45,0x09,0xa1,0xd8,0x33 -,0x26,0x88,0x45,0x0a,0x33,0xc0,0xa3,0x7a,0x34,0xa3,0x39,0x37,0xa3,0x95,0x37,0xa3 -,0x80,0x34,0xa3,0x76,0x34,0xa3,0xc6,0x34,0xa3,0xd8,0x33,0x5f,0xb0,0x00,0xc3,0xf6 -,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x83,0xf9,0x06 -,0x74,0x12,0x83,0xf9,0x04,0x74,0x0d,0x83,0xf9,0x00,0x74,0x08,0x83,0xf9,0x02,0x74 -,0x03,0xb0,0x01,0xc3,0x89,0x0e,0xe8,0x3a,0x83,0x26,0xab,0x36,0xf9,0x09,0x0e,0xab -,0x36,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc1,0xe7,0x02,0xb0,0x00,0xc3,0xf6,0x06,0x93 -,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0x26,0x8b,0x4f,0x04,0x80,0xf9,0xff,0x74,0x08 -,0x80,0xf9,0x00,0x74,0x10,0xb0,0x01,0xc3,0x83,0x0e,0xad,0x36,0x02,0xa1,0xad,0x36 -,0xe7,0x04,0xe9,0x0a,0x00,0x83,0x26,0xad,0x36,0xfd,0xa1,0xad,0x36,0xe7,0x04,0xb0 -,0x00,0xc3,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x04,0xc3,0xe8,0xd5,0x04,0xb0 -,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x06 -,0x05,0x75,0x03,0xe9,0x9d,0x00,0x26,0x8b,0x57,0x04,0x26,0x8b,0x47,0x08,0x26,0x81 -,0x7f,0x06,0x00,0x80,0x75,0x08,0xed,0x26,0x89,0x47,0x0a,0xe9,0x9d,0x00,0x26,0x83 -,0x7f,0x06,0x01,0x75,0x04,0xef,0xe9,0x92,0x00,0x26,0x81,0x7f,0x06,0x01,0x80,0x75 -,0x09,0xef,0xed,0x26,0x89,0x47,0x0a,0xe9,0x81,0x00,0x26,0x83,0x7f,0x06,0x02,0x75 -,0x07,0x26,0x21,0x47,0x04,0xe9,0x73,0x00,0x26,0x81,0x7f,0x06,0x02,0x80,0x75,0x0c -,0x26,0x21,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x5f,0x00,0x26,0x83,0x7f,0x06 -,0x03,0x75,0x07,0x26,0x09,0x47,0x04,0xe9,0x51,0x00,0x26,0x81,0x7f,0x06,0x03,0x80 -,0x75,0x0c,0x26,0x09,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x3d,0x00,0x26,0x83 -,0x7f,0x06,0x04,0x75,0x07,0x26,0x31,0x47,0x04,0xe9,0x2f,0x00,0x26,0x81,0x7f,0x06 -,0x04,0x80,0x75,0x0c,0x26,0x31,0x47,0x04,0xed,0x26,0x89,0x47,0x0a,0xe9,0x1b,0x00 -,0xb0,0x01,0xc3,0xfa,0x53,0x26,0x8b,0x4f,0x08,0x0b,0xc9,0x74,0x0c,0x8d,0x1e,0xe0 -,0xfe,0xe8,0x52,0xff,0x83,0xc3,0x08,0xe2,0xf8,0x5b,0xfb,0xb0,0x00,0xc3,0xf6,0x06 -,0x93,0x36,0x80,0x75,0x0a,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xb0,0x01,0xc3,0x8d -,0x3e,0xe0,0xfe,0xe5,0x00,0x26,0x89,0x05,0xe5,0x02,0x26,0x89,0x45,0x02,0xa1,0xad -,0x36,0x26,0x89,0x45,0x04,0xe5,0x06,0x26,0x89,0x45,0x06,0xe5,0x08,0x26,0x89,0x45 -,0x08,0xe5,0x0a,0x26,0x89,0x45,0x0a,0xe5,0x0e,0x26,0x89,0x45,0x0c,0xe5,0x48,0x26 -,0x89,0x45,0x0e,0xe5,0x4a,0x26,0x89,0x45,0x10,0xe5,0x4c,0x26,0x89,0x45,0x12,0xa1 -,0xb7,0x36,0x26,0x89,0x45,0x14,0xe5,0x50,0x26,0x89,0x45,0x16,0xe5,0x52,0x26,0x89 -,0x45,0x18,0xe5,0x54,0x26,0x89,0x45,0x1a,0xe5,0x56,0x26,0x89,0x45,0x1c,0xe5,0x58 -,0x26,0x89,0x45,0x1e,0xe5,0x62,0x26,0x89,0x45,0x20,0xe5,0x64,0x26,0x89,0x45,0x22 -,0xe5,0x66,0x26,0x89,0x45,0x24,0xe5,0x68,0x26,0x89,0x45,0x26,0xe5,0x6a,0x26,0x89 -,0x45,0x28,0xe5,0x6c,0x26,0x89,0x45,0x2a,0xe5,0x70,0x26,0x89,0x45,0x2c,0xe5,0x72 -,0x26,0x89,0x45,0x2e,0xe5,0x74,0x26,0x89,0x45,0x30,0xe5,0x76,0x26,0x89,0x45,0x32 -,0xe5,0x7c,0x26,0x89,0x45,0x34,0xe5,0x7e,0x26,0x89,0x45,0x36,0xe5,0x80,0x26,0x89 -,0x45,0x38,0xe5,0x82,0x26,0x89,0x45,0x3a,0xe5,0x86,0x26,0x89,0x45,0x3c,0xe5,0x88 -,0x26,0x89,0x45,0x3e,0xe5,0x9a,0x26,0x89,0x45,0x40,0xe5,0x9e,0x26,0x89,0x45,0x42 -,0xe5,0xcc,0x26,0x89,0x45,0x44,0xe5,0xce,0x26,0x89,0x45,0x46,0xe5,0xd0,0x26,0x89 -,0x45,0x48,0xe5,0xd2,0x26,0x89,0x45,0x4a,0xba,0x00,0x01,0xed,0x11,0x06,0x66,0x34 -,0x73,0x04,0xff,0x06,0x68,0x34,0x26,0x89,0x45,0x4c,0xba,0x02,0x01,0xed,0xc1,0xe0 -,0x02,0x11,0x06,0x6e,0x34,0x73,0x04,0xff,0x06,0x70,0x34,0x26,0x89,0x45,0x4e,0xba -,0x04,0x01,0xed,0x11,0x06,0x6a,0x34,0x73,0x04,0xff,0x06,0x6c,0x34,0x26,0x89,0x45 -,0x50,0xba,0x06,0x01,0xed,0xc1,0xe0,0x02,0x11,0x06,0x72,0x34,0x73,0x04,0xff,0x06 -,0x74,0x34,0x26,0x89,0x45,0x52,0xba,0x08,0x01,0xed,0x26,0x89,0x45,0x54,0xba,0x0a -,0x01,0xed,0x26,0x89,0x45,0x56,0xba,0x0c,0x01,0xed,0x26,0x89,0x45,0x58,0xba,0x0e -,0x01,0xed,0x01,0x06,0x7a,0x34,0x26,0x89,0x45,0x5e,0xba,0x10,0x01,0xed,0x26,0x89 -,0x45,0x5c,0xb0,0x00,0xc3,0xf6,0x06,0x93,0x36,0x80,0x74,0x07,0xf6,0x06,0x93,0x36 -,0x20,0x75,0x03,0xb0,0x01,0xc3,0x26,0x80,0x7f,0x06,0x00,0x75,0x30,0x80,0x3e,0x95 -,0x36,0x00,0x74,0x52,0xc6,0x06,0x95,0x36,0x00,0x83,0x26,0xad,0x36,0xfe,0xa1,0xad -,0x36,0xe7,0x04,0xba,0x10,0x01,0xb8,0x80,0x80,0xef,0xed,0xba,0x10,0x01,0xb8,0x02 -,0x02,0xef,0xed,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0xb0,0x00,0xc3,0x26,0x8b,0x47 -,0x04,0x3d,0x00,0x00,0x74,0x20,0x3d,0x03,0x00,0x77,0x1b,0xba,0x10,0x01,0xb8,0x02 -,0x00,0xef,0xba,0xe0,0x00,0xb8,0x01,0x10,0xef,0x83,0x0e,0xad,0x36,0x01,0xa1,0xad -,0x36,0xe7,0x04,0xb0,0x00,0xc3,0xb0,0x06,0xc3,0xf6,0x06,0x93,0x36,0x80,0x75,0x03 -,0xb0,0x01,0xc3,0x26,0x83,0x7f,0x04,0x01,0x74,0x0a,0x26,0x83,0x7f,0x04,0x02,0x74 -,0x19,0xb0,0x06,0xc3,0x26,0x83,0x7f,0x06,0x0c,0x77,0xf6,0x26,0x83,0x7f,0x0a,0x60 -,0x77,0xef,0xe8,0x10,0x00,0x72,0x0b,0xb0,0x46,0xc3,0xe8,0x4e,0x00,0x72,0x03,0xb0 -,0x46,0xc3,0xb0,0x00,0xc3,0x51,0xb1,0x0a,0x8b,0x3e,0x20,0xf3,0x26,0x83,0x7d,0x0c -,0x02,0x75,0x03,0xe9,0x0e,0x00,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01,0xe9,0xeb -,0xff,0x59,0xf8,0xc3,0x57,0x8d,0x7d,0x0e,0x8d,0x77,0x06,0xb9,0x12,0x00,0xf3,0xa4 -,0x8d,0x7d,0x20,0x8d,0x36,0xe0,0xfe,0x26,0x8b,0x4d,0x12,0xf3,0xa4,0xff,0x06,0x01 -,0x35,0x5f,0x26,0xc7,0x45,0x0c,0x01,0x00,0x59,0xf9,0xc3,0x51,0xb1,0x0a,0x8d,0x3e -,0x20,0xf3,0x8d,0x36,0xe0,0xfe,0x26,0x83,0x7d,0x0c,0x01,0x75,0x1b,0x57,0xe8,0x25 -,0x00,0x5f,0x73,0x14,0x33,0xc0,0xb9,0x20,0x01,0xf3,0xaa,0x26,0xc7,0x45,0x0c,0x02 -,0x00,0xff,0x0e,0x01,0x35,0x59,0xf9,0xc3,0xfe,0xc9,0x74,0x07,0x81,0xc7,0x20,0x01 -,0xe9,0xd3,0xff,0x59,0xf8,0xc3,0x51,0x26,0x8b,0x4d,0x12,0x8d,0x7d,0x20,0xf3,0xa6 -,0x74,0x03,0x59,0xf8,0xc3,0x59,0xf9,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x80,0x3e,0xec,0x34,0x06,0x72,0x33,0xff,0x06,0xf0,0x33,0x50,0xc4,0x1e,0x8c,0x36 -,0xb9,0x0f,0x00,0x33,0xc0,0xe8,0x29,0x00,0x58,0x81,0x26,0xc2,0x34,0xdf,0x7f,0x81 -,0x26,0xe9,0x34,0xdf,0x7f,0x0b,0xdb,0x74,0x11,0x26,0xc6,0x07,0x84,0x26,0xc6,0x47 -,0x02,0xff,0x26,0x89,0x47,0x06,0xe8,0xac,0x00,0xc3,0xff,0x06,0xea,0x33,0xe9,0xf5 -,0xff,0x57,0x26,0x8b,0x3f,0x03,0xf9,0x26,0x3b,0x7f,0x02,0x74,0x16,0x26,0x3b,0x7f -,0x04,0x7c,0x2a,0x3d,0x00,0x00,0x75,0x13,0x8d,0x7f,0x08,0x03,0xf9,0x26,0x3b,0x7f -,0x02,0x7c,0x14,0xff,0x06,0xde,0x33,0x33,0xdb,0x5f,0xc3,0x26,0x8b,0x7f,0x02,0x26 -,0x89,0x3f,0x03,0xf9,0xe9,0x06,0x00,0x26,0x89,0x3f,0x26,0x29,0x0f,0x26,0xc7,0x05 -,0xff,0xff,0x26,0x87,0x3f,0x26,0x89,0x0d,0x8d,0x5d,0x02,0x50,0x8b,0xfb,0x83,0xe9 -,0x02,0x33,0xc0,0xf3,0xaa,0x58,0xfe,0x0e,0xec,0x34,0x5f,0xc3,0x8b,0x7c,0x02,0x3b -,0x3c,0x74,0x2f,0x83,0x3d,0xff,0x75,0x0b,0x8d,0x7c,0x08,0x89,0x7c,0x02,0x83,0x3d -,0xff,0x74,0x1e,0x8a,0x45,0x02,0x3c,0x81,0x75,0x0c,0x80,0x3e,0xeb,0x34,0x00,0x74 -,0x05,0x33,0xc0,0xe9,0x0b,0x00,0x8b,0x0d,0x01,0x4c,0x02,0x8d,0x75,0x02,0x83,0xe9 -,0x02,0xc3,0x80,0x3e,0xec,0x34,0x06,0x72,0x05,0x33,0xc0,0xe9,0xf3,0xff,0xff,0x06 -,0xee,0x33,0xe9,0xbe,0xff,0xf6,0x06,0x92,0x36,0x40,0x74,0x01,0xc3,0x57,0x56,0x51 -,0x52,0x8b,0x36,0x8c,0x36,0xe8,0xa4,0xff,0x75,0x03,0xe9,0x1a,0x00,0xe9,0x1c,0x00 -,0xfe,0x06,0xec,0x34,0xc4,0x3e,0x80,0x36,0xf3,0xa4,0x80,0x0e,0x92,0x36,0x40,0xba -,0x0c,0x01,0xb8,0x80,0x80,0xef,0xed,0x5a,0x59,0x5e,0x5f,0xc3,0xff,0x06,0xe0,0x33 -,0x80,0x3c,0x81,0x75,0x0c,0xff,0x06,0xe2,0x33,0xc6,0x06,0xeb,0x34,0x01,0xe9,0xcf -,0xff,0x80,0x3c,0x84,0x75,0x07,0xff,0x06,0xe6,0x33,0xe9,0xc3,0xff,0xff,0x06,0xe8 -,0x33,0xe9,0xbc,0xff,0x8d,0x3e,0xe0,0xfe,0xa1,0x72,0x34,0xc7,0x06,0x72,0x34,0x00 -,0x00,0x89,0x05,0xa1,0x74,0x34,0xc7,0x06,0x74,0x34,0x00,0x00,0x89,0x45,0x02,0xba -,0x04,0x01,0xed,0x89,0x45,0x04,0xc7,0x45,0x06,0x00,0x00,0xa1,0x6e,0x34,0xc7,0x06 -,0x6e,0x34,0x00,0x00,0x89,0x45,0x08,0xa1,0x70,0x34,0xc7,0x06,0x70,0x34,0x00,0x00 -,0x89,0x45,0x0a,0xba,0x00,0x01,0xed,0x89,0x45,0x0c,0xc7,0x45,0x0e,0x00,0x00,0x32 -,0xe4,0xba,0x0e,0x01,0xec,0x89,0x45,0x10,0xa1,0x7e,0x34,0xc7,0x06,0x7e,0x34,0x00 -,0x00,0x89,0x45,0x12,0xa1,0x8c,0x34,0xc7,0x06,0x8c,0x34,0x00,0x00,0x89,0x45,0x14 -,0xa1,0x8a,0x34,0xc7,0x06,0x8a,0x34,0x00,0x00,0x89,0x45,0x16,0xa1,0x7c,0x34,0xc7 -,0x06,0x7c,0x34,0x00,0x00,0x89,0x45,0x18,0xa1,0x88,0x34,0xc7,0x06,0x88,0x34,0x00 -,0x00,0x89,0x45,0x1a,0xa1,0xca,0x33,0xc7,0x06,0xca,0x33,0x00,0x00,0x89,0x45,0x1c -,0xa1,0x78,0x34,0xc7,0x06,0x78,0x34,0x00,0x00,0x89,0x45,0x1e,0xa1,0xc6,0x34,0xc7 -,0x06,0xc6,0x34,0x00,0x00,0x89,0x45,0x20,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0xfa,0x33,0xc0,0x8e,0xd8,0x8e,0xc0,0xb8,0xa0,0x01,0xc1,0xe8,0x04,0x8e,0xd0,0x8d -,0x26,0x80,0x00,0xe8,0x00,0x01,0xe8,0x10,0xeb,0x8b,0x1e,0xf7,0x34,0x8b,0x16,0xf9 -,0x34,0x8b,0x36,0xff,0x34,0x33,0xc0,0xb9,0xef,0xff,0x8d,0x3e,0x14,0x00,0x2b,0xcf -,0x2b,0xce,0xd1,0xe9,0xf3,0xab,0x89,0x1e,0xf7,0x34,0x89,0x16,0xf9,0x34,0x83,0xfe -,0x00,0x74,0x0c,0xb9,0xef,0xff,0xbf,0x80,0xfe,0x2b,0xcf,0xd1,0xe9,0xf3,0xab,0xb9 -,0xff,0xff,0x81,0xe9,0x00,0x3b,0x83,0xfe,0x00,0x74,0x03,0xe9,0x1b,0x00,0x51,0x1e -,0xb8,0x00,0xe0,0x8e,0xd8,0x33,0xf6,0x8d,0x3e,0x00,0xd8,0xb9,0x00,0x0c,0xf3,0xa5 -,0x1f,0x59,0xbe,0xff,0xff,0x81,0xee,0x00,0xd8,0x2b,0xce,0x81,0xe1,0x00,0xff,0x89 -,0x0e,0xac,0x33,0x8d,0x06,0x20,0x02,0xc1,0xe8,0x04,0xa3,0x32,0x34,0x8e,0xd0,0x36 -,0xc7,0x06,0x1e,0x00,0x80,0x18,0x36,0xc7,0x06,0x22,0x00,0xff,0x7f,0x36,0xc7,0x06 -,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0x8d,0x06,0xa0,0x02,0xc1 -,0xe8,0x04,0xa3,0x30,0x34,0x8e,0xd0,0x36,0xc7,0x06,0x1e,0x00,0x50,0x28,0x36,0xc7 -,0x06,0x0a,0x00,0xff,0xff,0x36,0xc7,0x06,0x1c,0x00,0x80,0x00,0xb8,0xa0,0x01,0xc1 -,0xe8,0x04,0xa3,0x34,0x34,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00,0xb8,0x00 -,0x90,0xe7,0x02,0x8d,0x3e,0x70,0x01,0x8b,0xc7,0xc1,0xe8,0x04,0xb9,0x03,0x00,0x89 -,0x45,0x0e,0x89,0x45,0x02,0xc7,0x05,0xff,0xff,0x83,0xc7,0x10,0x05,0x01,0x00,0xe2 -,0xee,0xe8,0x5b,0x01,0xe5,0xce,0xa3,0xb5,0x36,0xe8,0x21,0x00,0xe8,0x45,0x01,0xa1 -,0x32,0x34,0x8c,0xcb,0xcd,0x37,0x0e,0x58,0xa9,0x00,0xf0,0x74,0x07,0x33,0xf6,0x89 -,0x36,0xff,0x34,0xc3,0x8d,0x36,0x30,0x61,0x89,0x36,0xff,0x34,0xc3,0x33,0xc0,0x8b -,0xd0,0x8b,0xf2,0xb9,0x68,0x00,0x2e,0x80,0xbc,0xac,0x17,0x80,0x75,0x01,0xef,0x83 -,0xc2,0x02,0x46,0xe2,0xf1,0xb8,0x02,0x00,0xe7,0x50,0xb9,0x5a,0x00,0x33,0xff,0xc7 -,0x05,0x65,0x18,0x8c,0x4d,0x02,0x83,0xc7,0x04,0xe2,0xf4,0x33,0xc0,0x8e,0xc0,0x8c -,0xc8,0x8e,0xd8,0x8d,0x3e,0x80,0x00,0x8d,0x36,0x9c,0x17,0xb9,0x08,0x00,0xe8,0x37 -,0x00,0x8d,0x36,0x20,0x21,0x8d,0x3e,0xc0,0x00,0xb9,0x0d,0x00,0xe8,0x29,0x00,0x8d -,0x3e,0x40,0x01,0xb9,0x0a,0x00,0xe8,0x1f,0x00,0xe8,0x4b,0x0e,0x33,0xc0,0x8e,0xd8 -,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xe7,0x48,0xe7,0x4c,0xb8,0x40,0x9c,0xe7,0x4a,0xe5 -,0x48,0x90,0xb8,0x00,0x70,0xe7,0x48,0xc3,0xa5,0x83,0xc7,0x02,0xe2,0xfa,0xc3,0xe5 -,0x4c,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe5,0x58,0xd1 -,0xe0,0x73,0x11,0x8b,0xf0,0xd1,0xe6,0x33,0xc0,0x8e,0xd8,0x8b,0xb4,0x80,0x00,0x83 -,0xc6,0x0b,0xff,0xe6,0x1f,0x07,0x5a,0x5f,0x5e,0x59,0x58,0xcf,0x58,0x1c,0xe4,0x1c -,0x6c,0x1c,0x8e,0x1a,0xc0,0x1f,0x40,0x1a,0x44,0x1c,0x65,0x18,0x80,0x80,0x80,0xff -,0x80,0x03,0x02,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff -,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff -,0x80,0x03,0x03,0x43,0x80,0x80,0x02,0x80,0x42,0x03,0x02,0xff,0x03,0x01,0x03,0x01 -,0x01,0x03,0x02,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x03,0x01,0x03 -,0x03,0xff,0x01,0x01,0xff,0x01,0xff,0x01,0x01,0x03,0x03,0x03,0xff,0xff,0xff,0xff -,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff -,0xff,0xff,0xff,0x02,0xb8,0x0f,0x00,0xe7,0x84,0xb8,0x0f,0xf8,0xe7,0x82,0xc3,0xb9 -,0x08,0x00,0x89,0x0e,0xe6,0x3a,0x8d,0x06,0x20,0x03,0x8b,0xd0,0xc1,0xe8,0x04,0xa3 -,0x90,0x01,0x8b,0xc2,0x8b,0xd8,0xc1,0xe8,0x04,0x8e,0xc0,0x05,0x61,0x00,0x26,0xa3 -,0x00,0x00,0xa1,0x30,0x34,0x26,0xa3,0x02,0x00,0x83,0xc3,0x14,0xd1,0xeb,0x26,0x89 -,0x1e,0x08,0x00,0x81,0xc2,0x10,0x06,0xe2,0xd9,0x26,0xc7,0x06,0x00,0x00,0xff,0xff -,0x8c,0x06,0x92,0x01,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8 -,0xe7,0x5a,0xff,0x06,0xbe,0x33,0xba,0xd2,0x00,0xed,0xcf,0x00,0x00,0x00,0x00,0x00 -,0x8c,0xcb,0xa1,0x30,0x34,0xcd,0x37,0xe9,0x06,0xed,0xb8,0x32,0x00,0xc3,0xe8,0x8c -,0x01,0xfe,0x06,0xe2,0x34,0xe8,0x21,0x01,0x75,0xf0,0xe8,0x53,0x0e,0x81,0x0e,0xaf -,0x36,0x00,0xc0,0xc7,0x06,0xad,0x36,0x60,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75 -,0x1a,0xf7,0x06,0xe6,0x34,0x00,0x08,0x74,0x09,0xc7,0x06,0xab,0x36,0x0b,0x00,0xe9 -,0x0f,0x00,0xc7,0x06,0xab,0x36,0x03,0x00,0xe9,0x06,0x00,0xc7,0x06,0xab,0x36,0x11 -,0x9c,0xc7,0x06,0xa9,0x36,0x18,0x00,0xf7,0x06,0xe6,0x34,0x80,0x00,0x75,0x0d,0xf7 -,0x06,0xb5,0x36,0x02,0x00,0x74,0x05,0x83,0x0e,0xa9,0x36,0x20,0xa1,0xa9,0x36,0xe7 -,0x00,0xa1,0xab,0x36,0xe7,0x02,0xf7,0x06,0xe6,0x34,0x80,0x00,0x74,0x2e,0xe8,0xf2 -,0x2f,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08 -,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xb8,0x40,0x00,0xe7,0x4e,0x33 -,0xc0,0xe7,0x0e,0xc7,0x06,0x26,0x02,0x00,0x00,0xe9,0x23,0x00,0xc7,0x06,0x4e,0x37 -,0x3f,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x80,0x74,0x07,0x26 -,0x81,0x0e,0x08,0x00,0x00,0x80,0xc6,0x06,0xe0,0x34,0x01,0xb8,0x00,0x00,0xc3,0xfe -,0x06,0xe1,0x34,0xc6,0x06,0xe0,0x34,0x00,0xa1,0x26,0x02,0x0b,0xc0,0x74,0x01,0xc3 -,0xe8,0x04,0x00,0xb8,0x00,0x00,0xc3,0xa1,0xa9,0x36,0xe7,0x00,0x8b,0x1e,0xab,0x36 -,0x83,0xe3,0x06,0xe5,0x02,0x25,0xf9,0xff,0x0b,0xc3,0x0d,0x10,0x00,0xe7,0x02,0xa1 -,0xad,0x36,0xe7,0x04,0xc3,0xb8,0x0a,0x00,0xe7,0x84,0xfe,0x06,0xe5,0x34,0xc6,0x06 -,0xe3,0x34,0x01,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x40,0x74,0x07 -,0x26,0x81,0x0e,0x08,0x00,0x00,0x40,0xc3,0xc7,0x06,0x4e,0x37,0x6f,0x17,0xfe,0x06 -,0xe4,0x34,0xc6,0x06,0xe3,0x34,0x00,0xc3,0xc3,0xf6,0x06,0x18,0x34,0x80,0x75,0x0d -,0xa1,0x18,0x34,0x0b,0x06,0x1a,0x34,0x0b,0x06,0x1c,0x34,0x75,0x01,0xc3,0xa1,0x2e -,0x34,0x25,0xff,0xfe,0x8b,0x16,0xe7,0x36,0x81,0xe2,0x00,0x01,0x0b,0xc2,0xa3,0x2e -,0x34,0x8d,0x16,0x10,0x00,0xbf,0x00,0x00,0xb9,0x08,0x00,0x8b,0x85,0x00,0x34,0xef -,0x83,0xc2,0x10,0x8b,0x85,0x02,0x34,0xef,0x83,0xc2,0x10,0x8b,0x85,0x04,0x34,0xef -,0x83,0xc2,0xe2,0x83,0xc7,0x06,0x49,0x75,0xe2,0xb8,0x00,0x00,0x8e,0xc0,0xbe,0x00 -,0x34,0xbf,0xb9,0x36,0xb9,0x18,0x00,0xf3,0xa5,0xb8,0x00,0x00,0xc3,0x33,0xc0,0x8e -,0xc0,0x8d,0x3e,0xb0,0x33,0xb9,0x08,0x00,0xf3,0xab,0x8d,0x3e,0x3e,0x34,0xb9,0x03 -,0x00,0xf3,0xab,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xba -,0x33,0xe5,0x56,0x0d,0x20,0x00,0xe7,0x56,0xba,0x7a,0x00,0xed,0x08,0x26,0x94,0x36 -,0x33,0xc0,0xb1,0x08,0x32,0xed,0x06,0x8e,0xc0,0x8d,0x3e,0xe0,0xff,0xf3,0xaa,0x8e -,0x06,0x32,0x34,0x26,0x81,0x0e,0x08,0x00,0x00,0x02,0x07,0xe5,0x56,0x25,0xdf,0xff -,0xe7,0x56,0xe9,0xf8,0xfc,0x00,0xbd,0x1b,0x10,0x1b,0xd9,0x1a,0xf3,0x1a,0x50,0x51 -,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb6,0x33,0x53 -,0x06,0x51,0xe5,0x80,0xa3,0xb4,0x33,0x8b,0xd8,0x8b,0xc8,0x25,0x10,0x00,0xa3,0xed -,0x34,0x0b,0xc0,0x74,0x14,0xff,0x06,0x80,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x03 -,0xe9,0x06,0x00,0xb8,0x80,0x00,0xe8,0x9d,0x04,0x83,0xe3,0x03,0xd1,0xe3,0x2e,0xff -,0x97,0x86,0x1a,0x59,0x07,0x5b,0xe9,0xa4,0xfc,0xba,0x20,0x00,0x8e,0x06,0x3c,0x34 -,0x83,0x3e,0x3c,0x34,0x00,0x75,0x03,0xe9,0xf0,0x00,0xc7,0x06,0x3c,0x34,0x00,0x00 -,0xe9,0x2a,0x00,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0x83,0x3e,0x3a,0x34,0x00,0x75 -,0x03,0xe9,0xd5,0xff,0xc7,0x06,0x3a,0x34,0x00,0x00,0xe8,0x10,0x00,0xe9,0xc9,0xff -,0xba,0x10,0x00,0x8e,0x06,0x3a,0x34,0xc7,0x06,0x3a,0x34,0x00,0x00,0x26,0xa1,0x14 -,0x00,0x26,0xa3,0x0c,0x00,0x26,0xa1,0x16,0x00,0x26,0xa3,0x0e,0x00,0x26,0xc6,0x06 -,0x0a,0x00,0x00,0xc1,0xea,0x02,0x23,0xd1,0x74,0x1c,0xba,0x20,0x00,0x26,0xc7,0x06 -,0x0e,0x00,0xea,0x05,0x26,0x0b,0x16,0x0c,0x00,0x26,0x89,0x16,0x0c,0x00,0xff,0x06 -,0x86,0x34,0xff,0x06,0xdc,0x33,0x26,0xa1,0x0c,0x00,0xa9,0x00,0x37,0x74,0x16,0x26 -,0xc6,0x06,0x0a,0x00,0x02,0xa9,0x00,0x30,0x74,0x04,0xff,0x06,0x7a,0x34,0xff,0x06 -,0xda,0x33,0xe9,0x49,0x00,0xc0,0xec,0x07,0x83,0x16,0x8a,0x34,0x00,0x24,0x07,0x3c -,0x07,0x75,0x04,0xff,0x06,0x8c,0x34,0xff,0x06,0x7e,0x34,0xa1,0x30,0x34,0x8c,0xc3 -,0x8e,0xc0,0x8e,0xdb,0x26,0x83,0x0e,0x08,0x00,0x40,0x8c,0xd8,0x26,0x87,0x06,0x16 -,0x00,0x26,0x83,0x3e,0x14,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x8c,0x1e,0x00,0x00 -,0xe9,0x05,0x00,0x26,0x8c,0x1e,0x14,0x00,0x33,0xc0,0x8e,0xd8,0xc3,0xc3,0x8c,0xc0 -,0x87,0x06,0x92,0x01,0x3d,0xff,0xff,0x74,0x0d,0x8e,0xd8,0x8c,0x06,0x00,0x00,0x33 -,0xc0,0x8e,0xd8,0xe9,0x04,0x00,0x8c,0x06,0x90,0x01,0xe8,0x01,0x00,0xc3,0x06,0x83 -,0x3e,0x90,0x01,0xff,0x74,0x29,0x83,0x3e,0x3a,0x34,0x00,0x75,0x11,0xba,0x86,0x00 -,0xe8,0x1e,0x00,0x8c,0x06,0x3a,0x34,0x83,0x3e,0x90,0x01,0xff,0x74,0x11,0x83,0x3e -,0x3c,0x34,0x00,0x75,0x0a,0xba,0x88,0x00,0xe8,0x06,0x00,0x8c,0x06,0x3c,0x34,0x07 -,0xc3,0xa1,0x90,0x01,0x8e,0xc0,0x26,0xa1,0x08,0x00,0xef,0x26,0xa1,0x00,0x00,0x26 -,0xc7,0x06,0x00,0x00,0xff,0xff,0xa3,0x90,0x01,0x3d,0xff,0xff,0x75,0x03,0xa3,0x92 -,0x01,0x83,0x3e,0xed,0x34,0x00,0x74,0x0b,0xb8,0x10,0x00,0xe7,0x84,0xc7,0x06,0xed -,0x34,0x00,0x00,0xc3,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7 -,0x5a,0xff,0x06,0xbc,0x33,0xe9,0x25,0xfb,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33 -,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb0,0x33,0xe9,0x11,0xfb,0x50,0x51,0x56,0x57 -,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb4,0x33,0x06,0xff,0x06 -,0x76,0x34,0x80,0x3e,0xfe,0x34,0x00,0x74,0x04,0x07,0xe9,0xf0,0xfa,0xb8,0x80,0x00 -,0xe8,0xd3,0x02,0x07,0xe9,0xe6,0xfa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0xc6,0x1d,0x08,0x1d,0x91,0x1e,0x5d,0x1e,0x73,0x1e,0x89,0x1e,0x91,0x1e,0xa8,0x1d -,0x91,0x1e,0x91,0x1e,0xaf,0x1e,0xaf,0x1e,0x15,0x1d,0x15,0x1d,0x91,0x1e,0x99,0x1f -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x02,0x00,0x00 -,0x00,0x01,0x00,0x10,0x00,0x01,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00 -,0x07,0xe9,0x99,0xfa,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7 -,0x5a,0xff,0x06,0xb2,0x33,0x06,0x68,0xf6,0x1c,0xe5,0x06,0xa3,0xb2,0x33,0x8b,0xf0 -,0x83,0xe6,0x1e,0x2e,0xff,0xa4,0xa0,0x1c,0xe5,0x0c,0xa9,0x80,0x00,0x74,0x06,0xe8 -,0xa4,0x01,0xe5,0x06,0xc3,0x53,0xe5,0x0c,0x8b,0xd8,0xa9,0x01,0x00,0x74,0x14,0x83 -,0x3e,0xe0,0x3a,0x00,0x74,0x0d,0x8e,0x06,0x38,0x34,0xe8,0xbf,0x06,0xc7,0x06,0xe0 -,0x3a,0x00,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7 -,0x02,0x8b,0xc3,0x5b,0xa9,0x01,0x00,0x74,0x01,0xc3,0x8b,0xd0,0xb8,0x00,0x08,0xe7 -,0x84,0x8b,0xc2,0x8e,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0x8b,0xd0,0xc1,0xe0,0x03 -,0x83,0x16,0x88,0x34,0x00,0xff,0x06,0x7c,0x34,0x26,0x83,0x3e,0x06,0x00,0x0a,0x75 -,0x21,0x8b,0xc2,0x25,0x40,0x18,0x3d,0x40,0x00,0x74,0x0c,0x3d,0x00,0x10,0x75,0x12 -,0x26,0xfe,0x0e,0x0a,0x00,0x74,0x0b,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x03,0xe9 -,0x5a,0x06,0x8c,0xc0,0x26,0x8e,0x06,0x02,0x00,0x26,0x83,0x0e,0x08,0x00,0x20,0x26 -,0xa3,0x12,0x00,0x26,0xa3,0x10,0x00,0xc3,0xff,0x06,0xc4,0x33,0xe5,0x0c,0xa9,0x01 -,0x00,0x75,0x01,0xc3,0xa9,0xf0,0x07,0x74,0x01,0xc3,0xff,0x06,0xd4,0x33,0xe5,0x00 -,0x0d,0x18,0x00,0xe7,0x00,0xc3,0xff,0x06,0xca,0x33,0x80,0x3e,0xa0,0x36,0x08,0x75 -,0x14,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26,0x81 -,0x0e,0x08,0x00,0x00,0x08,0xe5,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe5,0x0c,0x50,0xe5 -,0x80,0x25,0x00,0x07,0xa3,0xe4,0x3a,0xe5,0x8c,0x25,0x00,0x80,0xa3,0xe2,0x3a,0x58 -,0xa9,0x02,0x00,0x75,0x25,0x83,0x3e,0xe2,0x3a,0x00,0x75,0x1e,0x83,0x3e,0xe4,0x3a -,0x00,0x75,0x17,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe8,0x6a,0x01 -,0xe5,0x82,0x0d,0x02,0x00,0xe7,0x82,0xe9,0x21,0x00,0xe8,0x1a,0x06,0x80,0x3e,0xe8 -,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x0d,0x00,0xc6,0x06 -,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0x80,0x3e,0x9f,0x36,0x06 -,0x75,0x05,0x83,0x0e,0x99,0x36,0x40,0xb8,0x00,0x01,0xe9,0x09,0x01,0xff,0x06,0xcc -,0x33,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xff,0x06,0xc6,0x34 -,0xe9,0x1e,0x00,0xff,0x06,0xce,0x33,0xff,0x06,0x95,0x37,0x81,0x26,0xaf,0x36,0xff -,0xef,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x08,0x00,0xff,0x06,0xd0,0x33,0xff,0x06,0x7a -,0x34,0xff,0x06,0xd2,0x33,0xd1,0xe6,0x8e,0x06,0x30,0x34,0x2e,0x8b,0x84,0xc0,0x1c -,0x26,0x09,0x06,0x08,0x00,0x2e,0x8b,0x84,0xc2,0x1c,0x09,0x06,0x66,0x37,0xc3,0xe5 -,0x0c,0xa9,0x80,0x00,0x74,0x56,0x50,0xe8,0xf0,0x00,0x58,0xa9,0x00,0x01,0x75,0x07 -,0xff,0x06,0xc6,0x33,0xe9,0x08,0x00,0xff,0x06,0x78,0x34,0xff,0x06,0xc8,0x33,0xe5 -,0x82,0x25,0xfd,0xff,0xe7,0x82,0xe8,0x6e,0x05,0xba,0x10,0x01,0xed,0x80,0x3e,0xe8 -,0xff,0x00,0x74,0x0a,0x80,0x3e,0xe8,0xff,0x04,0x74,0x03,0xe9,0x1d,0x00,0xc6,0x06 -,0xe8,0xff,0x01,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xe9,0x0d,0x00,0xc6,0x06 -,0xe8,0xff,0x03,0xba,0x0c,0x01,0xb8,0x08,0x08,0xef,0xed,0xc3,0xa9,0x01,0x00,0x74 -,0x1c,0xe8,0x2c,0x00,0x83,0x3e,0xe0,0x3a,0x00,0x74,0x0f,0x06,0x8e,0x06,0x38,0x34 -,0xe8,0xc9,0x04,0xc7,0x06,0xe0,0x3a,0x00,0x00,0x07,0xe9,0x5d,0x00,0x8b,0xd0,0x8e -,0x06,0x38,0x34,0x26,0xa3,0x0c,0x00,0xe8,0x06,0x00,0x68,0x69,0x1d,0xe9,0x4a,0x00 -,0xa9,0x00,0x04,0x74,0x0a,0xb8,0x00,0x04,0xff,0x06,0xd8,0x33,0xe9,0x17,0x00,0xa9 -,0x00,0x01,0x74,0x0a,0xff,0x06,0x39,0x37,0xb8,0x00,0x01,0xe9,0x08,0x00,0xa9,0x10 -,0x00,0xb8,0x10,0x00,0x74,0x1d,0x09,0x06,0x66,0x37,0x8c,0xc0,0x8e,0x06,0x30,0x34 -,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01 -,0x8e,0xc0,0xc3,0xff,0x06,0xc2,0x33,0xe9,0xf8,0xff,0xe5,0x00,0x0d,0x18,0x00,0xe7 -,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0xc3,0x58,0xe9,0x43,0xfd,0xe5,0x08,0x0d -,0x00,0x04,0x25,0xff,0x04,0xe7,0x08,0xe9,0xe0,0xff,0xe5,0x0e,0xa9,0x00,0x08,0x75 -,0x01,0xc3,0xe9,0xf5,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x50,0x51,0x56,0x57,0x52,0x06,0x1e,0x33,0xc0,0x8e,0xd8,0xe7,0x5a,0xff,0x06,0xb8 -,0x33,0xe5,0x48,0x06,0x53,0x57,0xff,0x16,0x4e,0x37,0x5f,0x5b,0x83,0x3e,0x80,0x01 -,0xff,0x74,0x58,0x8e,0x06,0x80,0x01,0x26,0xff,0x0e,0x08,0x00,0x75,0x4d,0x26,0xa1 -,0x00,0x00,0xa3,0x80,0x01,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8c,0xc0,0x26,0x8e -,0x06,0x02,0x00,0x26,0x81,0x0e,0x08,0x00,0x80,0x00,0x8b,0xd0,0x26,0x87,0x06,0x1a -,0x00,0x26,0x83,0x3e,0x18,0x00,0xff,0x74,0x0a,0x8e,0xc0,0x26,0x89,0x16,0x00,0x00 -,0xe9,0x05,0x00,0x26,0x89,0x16,0x18,0x00,0x83,0x3e,0x80,0x01,0xff,0x74,0x0c,0x8e -,0x06,0x80,0x01,0x26,0x83,0x3e,0x08,0x00,0x00,0x74,0xb3,0x07,0xe9,0x3e,0xf7,0xe5 -,0x4c,0x90,0xe5,0x02,0xa9,0x00,0x20,0x74,0x0d,0x25,0xff,0xdf,0x0d,0x01,0x00,0xe7 -,0x02,0x0d,0x00,0x20,0xe7,0x02,0xe5,0x0a,0x8b,0xd8,0xa3,0xf4,0x33,0x25,0xc3,0x57 -,0x0d,0x00,0x10,0xe7,0x0a,0xf7,0x06,0x9b,0x36,0x00,0x80,0x74,0x37,0xf7,0xc3,0x00 -,0x80,0x74,0x06,0xf7,0xc3,0x00,0x08,0x74,0x5d,0x81,0x26,0xc2,0x34,0x7f,0xff,0xc7 -,0x06,0x35,0x37,0x05,0x00,0xb8,0x80,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0xff,0x7f -,0xc7,0x06,0x0f,0x37,0x04,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06 -,0x0f,0x37,0x03,0x00,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x2a,0xf7,0xc3,0x00,0x08 -,0x74,0x24,0x80,0x3e,0x9d,0x36,0x06,0x7c,0x1d,0xff,0x06,0x94,0x34,0x83,0x0e,0x66 -,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26 -,0x81,0x0e,0x08,0x00,0x00,0x01,0xf7,0xc3,0x00,0x20,0x75,0x3b,0xf7,0x06,0x9a,0x37 -,0x80,0x00,0x74,0x0b,0xff,0x06,0x89,0x37,0x33,0xc0,0xe7,0x0e,0xe9,0x04,0x00,0xff -,0x06,0x3b,0x37,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x1c,0x80,0x26,0x9e,0x36,0xff -,0x75,0x15,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x08,0x74,0x07,0x26 -,0x81,0x0e,0x08,0x00,0x00,0x08,0xc3,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x02,0x23,0x02,0x23,0x02,0x23,0x02,0x23,0x03,0x23,0xdd,0x22,0x02,0x23,0xfd,0x21 -,0x02,0x23,0xa4,0x24,0xf3,0x24,0x02,0x23,0x8d,0x22,0x7a,0x23,0x02,0x23,0x97,0x24 -,0x1b,0x24,0x75,0x24,0x02,0x23,0x02,0x23,0x8e,0x25,0xfb,0x8e,0x06,0x7e,0x01,0xfb -,0x26,0x83,0x3e,0x00,0x00,0xff,0x74,0xf2,0x26,0x8e,0x06,0x00,0x00,0xfa,0x26,0x8b -,0x1e,0x08,0x00,0x26,0x23,0x1e,0x0a,0x00,0x74,0xe5,0x8c,0xc0,0x8e,0xd0,0x26,0x8b -,0x26,0x02,0x00,0x8c,0x16,0xf2,0x33,0x22,0xff,0x75,0x6a,0x26,0xa1,0x1c,0x00,0x8a -,0xe3,0x8a,0xdc,0x22,0xd8,0x75,0x0d,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0xf2,0xb0 -,0x80,0xe9,0xed,0xff,0xd0,0xe8,0x24,0xf8,0x0a,0xc0,0x75,0x02,0xb0,0x80,0x32,0xe4 -,0x26,0xa3,0x1c,0x00,0xf7,0xc3,0x08,0x00,0x75,0x47,0x2e,0x8a,0x9f,0xc5,0x25,0x2e -,0x8b,0xbf,0xc5,0x26,0x80,0xc3,0x10,0x26,0x8e,0x1d,0x26,0x8c,0x1e,0x06,0x00,0x8b -,0x16,0x00,0x00,0xc7,0x06,0x00,0x00,0xff,0xff,0x26,0x89,0x15,0x83,0xfa,0xff,0x75 -,0x0a,0x2e,0x8b,0x97,0xcd,0x26,0x26,0x21,0x16,0x08,0x00,0x33,0xc0,0x8e,0xd8,0x26 -,0x89,0x1e,0x04,0x00,0xc3,0x8a,0xdf,0xb7,0x00,0x2e,0x8a,0x9f,0xc5,0x25,0xe9,0xe0 -,0xff,0x26,0x83,0x26,0x08,0x00,0xf7,0x83,0xc3,0x10,0xe9,0xde,0xff,0x60,0x06,0x1e -,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x8b,0x0e,0x34,0x34,0x39,0x0e -,0xf2,0x33,0x74,0x0e,0x26,0x81,0x0e,0x0a,0x00,0x00,0x02,0x26,0x81,0x0e,0x08,0x00 -,0x00,0x02,0x26,0x89,0x26,0x02,0x00,0xa3,0xf2,0x33,0x8e,0xd0,0x8d,0x26,0x80,0x00 -,0x36,0x89,0x26,0x02,0x00,0x36,0x89,0x1e,0x20,0x00,0x36,0xc7,0x06,0x08,0x00,0x00 -,0x00,0xb9,0x04,0x00,0xbe,0x00,0x00,0x2e,0x8b,0xbc,0xc5,0x26,0x36,0xc7,0x05,0xff -,0xff,0x36,0xc7,0x45,0x02,0xff,0xff,0x83,0xc6,0x02,0xe2,0xeb,0x8e,0x06,0x7e,0x01 -,0x36,0x8b,0x0e,0x22,0x00,0x8c,0xc0,0x26,0x83,0x3e,0x00,0x00,0xff,0x26,0x8e,0x06 -,0x00,0x00,0x74,0x07,0x26,0x3b,0x0e,0x22,0x00,0x7d,0xea,0x36,0x8c,0x06,0x00,0x00 -,0x8e,0xc0,0x26,0x8c,0x16,0x00,0x00,0xfb,0x36,0xff,0x2e,0x1e,0x00,0x06,0x1e,0x68 -,0x8b,0x25,0x6a,0x00,0x1f,0x26,0x09,0x36,0x08,0x00,0xf7,0xc6,0x00,0xff,0x74,0x01 -,0xc3,0x56,0x52,0x2e,0x8b,0xb4,0xc5,0x25,0x81,0xe6,0xff,0x00,0x2e,0x8b,0xb4,0xc5 -,0x26,0x8c,0xc2,0x8e,0xc0,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x8e,0xc2,0x26,0x83 -,0x3c,0xff,0x74,0x0f,0x8b,0xd0,0x26,0x87,0x54,0x02,0x8e,0xc2,0x26,0xa3,0x00,0x00 -,0xe9,0x07,0x00,0x26,0x89,0x44,0x02,0x26,0x89,0x04,0x5a,0x5e,0xc3,0x06,0x1e,0x68 -,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0x06,0xf2,0x33,0x26,0xa3,0x0a,0x00,0x26,0x89,0x26 -,0x02,0x00,0xa1,0x34,0x34,0x8e,0xd0,0x8d,0x26,0x80,0x00,0x8c,0x16,0xf2,0x33,0xe9 -,0x4d,0xfe,0xcf,0x50,0x1e,0x52,0x53,0x33,0xc0,0x8e,0xd8,0x26,0x83,0x3e,0x04,0x00 -,0xff,0x26,0xc7,0x06,0x04,0x00,0x00,0x00,0x74,0x03,0xe9,0x1a,0x00,0x83,0x3e,0xe6 -,0x3a,0x02,0x76,0x13,0xff,0x06,0xd6,0x33,0x8c,0xc0,0x8e,0x06,0x32,0x34,0xbe,0x40 -,0x00,0x68,0x3a,0x23,0xe9,0x5e,0xff,0xe8,0x84,0xf8,0x5b,0x5a,0x1f,0x58,0xcf,0xe8 -,0xe1,0x00,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0x8a,0x1e,0x29,0x00,0x88,0x1e,0x1b -,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c,0x26,0xa1 -,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x80,0xfb,0x08,0x74,0x09,0x0d,0x18,0xac,0xe7,0x00 -,0x07,0x1f,0x58,0xcf,0x0d,0x18,0x00,0xe9,0xf4,0xff,0x50,0x1e,0x06,0x33,0xc0,0x8e -,0xd8,0x83,0x3e,0xa1,0x36,0x00,0x75,0xb7,0x26,0x8b,0x36,0x06,0x00,0x2e,0xff,0x94 -,0xdc,0x23,0x07,0x1f,0x58,0xcf,0xe8,0x8a,0x00,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00 -,0xe8,0x49,0x00,0xc3,0x53,0xf7,0x06,0xef,0x34,0x20,0x00,0x75,0x2d,0xe5,0x8c,0x25 -,0x00,0x70,0x8b,0xd8,0xe5,0x8c,0x25,0x00,0x70,0x3b,0xc3,0x74,0x05,0x8b,0xd8,0xe9 -,0xf2,0xff,0x3d,0x00,0x30,0x75,0x10,0xe5,0x02,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06 -,0xe0,0x3a,0xff,0xff,0xe9,0x03,0x00,0xe8,0x12,0x00,0x5b,0xc3,0xa3,0x23,0x96,0x23 -,0xa4,0x23,0xa4,0x23,0x96,0x23,0xa4,0x23,0x96,0x23,0x96,0x23,0x26,0xa0,0x29,0x00 -,0xa2,0x1b,0x37,0x26,0xc7,0x06,0x0c,0x00,0xff,0x7f,0x26,0xa1,0x0e,0x00,0xe7,0x9c -,0x26,0xa1,0x08,0x00,0xe7,0x9a,0xe5,0x00,0x25,0xff,0x53,0x26,0x8b,0x36,0x06,0x00 -,0x83,0xe6,0x0e,0x2e,0x0b,0x84,0xad,0x25,0xe7,0x00,0xc3,0x06,0x1e,0x68,0x8b,0x25 -,0x6a,0x00,0x1f,0x83,0x0e,0xef,0x34,0x20,0x83,0x0e,0x9b,0x36,0x08,0xe5,0x00,0x25 -,0xef,0xff,0x0d,0x08,0x00,0xe7,0x00,0xe5,0x00,0xa9,0x10,0x00,0x75,0x01,0xc3,0xe5 -,0x00,0xa9,0x10,0x00,0x75,0xf9,0xc3,0x50,0x53,0x51,0x56,0x06,0x1e,0x33,0xc0,0x8e -,0xd8,0xb8,0x05,0x00,0xe7,0x84,0xe5,0x08,0x0d,0x00,0x04,0x25,0xff,0x04,0xe7,0x08 -,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d,0x11,0x00,0xe7,0x02,0x1f,0x07 -,0x5e,0x59,0x5b,0x58,0xc3,0x50,0x1e,0x33,0xc0,0x8e,0xd8,0xc7,0x06,0xef,0x34,0x00 -,0x00,0x83,0x26,0x9b,0x36,0xf7,0xe5,0x00,0x0d,0x18,0x00,0xe7,0x00,0xe5,0x02,0x0d -,0x11,0x00,0xe7,0x02,0x1f,0x58,0xcf,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f -,0xe8,0x16,0xf5,0xc3,0x06,0x1e,0x68,0x8b,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x26,0x83 -,0x3e,0x0a,0x00,0x00,0x74,0x03,0xe8,0x43,0x00,0x26,0xc7,0x06,0x0a,0x00,0xff,0xff -,0x26,0x8b,0x16,0x06,0x00,0x8e,0x1e,0x8e,0x01,0x8c,0xd8,0x8b,0xca,0x83,0x3e,0x00 -,0x00,0xff,0x8e,0x1e,0x00,0x00,0x74,0x0a,0x2b,0x16,0x08,0x00,0x73,0xeb,0x29,0x0e -,0x08,0x00,0x26,0x89,0x0e,0x08,0x00,0x26,0x8c,0x1e,0x00,0x00,0x8e,0xd8,0x8c,0x06 -,0x00,0x00,0xc3,0x60,0x06,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0x8e,0xc0,0x8b,0xc8 -,0x8e,0x1e,0x8e,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x8c,0xd8,0x83,0x3e,0x00 -,0x00,0xff,0x74,0x25,0x3b,0x0e,0x00,0x00,0x8e,0x1e,0x00,0x00,0x75,0xed,0x8e,0xd8 -,0x26,0xa1,0x00,0x00,0xa3,0x00,0x00,0x3d,0xff,0xff,0x74,0x56,0x8e,0xd8,0x26,0xa1 -,0x08,0x00,0x01,0x06,0x08,0x00,0xe9,0x49,0x00,0x26,0x8e,0x1e,0x02,0x00,0xbe,0x18 -,0x00,0x83,0x3c,0xff,0x74,0x3c,0x39,0x0c,0x74,0x19,0x8e,0x1c,0xbe,0x00,0x00,0x83 -,0x3e,0x00,0x00,0xff,0x74,0x2c,0x39,0x0e,0x00,0x00,0x74,0x07,0x8e,0x1e,0x00,0x00 -,0xe9,0xec,0xff,0x26,0xa1,0x00,0x00,0x89,0x04,0x33,0xc9,0x8e,0xd9,0x3d,0xff,0xff -,0x75,0x10,0x83,0xfe,0x18,0x75,0x0b,0x26,0x8e,0x1e,0x02,0x00,0x81,0x26,0x08,0x00 -,0x7f,0xff,0x33,0xc0,0x8e,0xd8,0xc3,0x1f,0x07,0x61,0xcf,0x1f,0x07,0xcf,0x60,0x06 -,0x1e,0x68,0x87,0x25,0x6a,0x00,0x1f,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75 -,0xf6,0xb9,0x08,0x00,0xe5,0x58,0xe7,0x5a,0x23,0xc0,0xe0,0xf8,0xc3,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0x00,0x00,0x00,0xa8,0x00,0x8c,0x02,0x04,0x00 -,0x00,0x08,0x10,0x20,0x00,0xff,0x0e,0x0c,0x0c,0x0a,0x0a,0x0a,0x0a,0x08,0x08,0x08 -,0x08,0x08,0x08,0x08,0x08,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06 -,0x06,0x06,0x06,0x06,0x06,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 -,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04 -,0x04,0x04,0x04,0x04,0x04,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 -,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 -,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 -,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02 -,0x02,0x02,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x14,0x00,0x10,0x00,0x0c,0x00,0xff,0x7f,0xff -,0xbf,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0x7f,0xff,0xbf -,0xff,0xdf,0xff,0xef,0xff,0xf7,0xff,0xfb,0xff,0xfd,0xff,0xfe,0xff,0x00,0x00,0x00 -,0x80,0x3e,0xe2,0x34,0x01,0x76,0x03,0xe9,0xa5,0x00,0xb8,0x00,0x00,0xe7,0x4e,0xb9 -,0x28,0x00,0xe2,0xfe,0xc6,0x06,0x45,0x37,0x02,0xbf,0x3f,0x28,0x2e,0x8b,0x45,0x08 -,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x1d,0xc7,0x06,0xb3,0x36,0x40,0x11 -,0xc7,0x06,0xb1,0x36,0x27,0x00,0xc7,0x06,0x46,0x37,0x02,0x00,0xc7,0x06,0x48,0x37 -,0x64,0x00,0xf7,0x06,0xb5,0x36,0x02,0x00,0x75,0x1c,0x2e,0x0b,0x5d,0x02,0x81,0x26 -,0xb3,0x36,0xff,0xfe,0xc7,0x06,0xb1,0x36,0x9c,0x00,0xc7,0x06,0x46,0x37,0x08,0x00 -,0xc7,0x06,0x48,0x37,0x90,0x01,0x89,0x1e,0xb7,0x36,0x89,0x1e,0xfe,0x33,0xbe,0x20 -,0x00,0x8b,0xc3,0xe7,0x4e,0xb9,0x28,0x00,0xe2,0xfe,0x2e,0x8b,0x45,0x04,0xe7,0x4e -,0xb9,0x28,0x00,0xe2,0xfe,0xe5,0x4e,0x8b,0xcb,0x2e,0x23,0x45,0x06,0x2e,0x23,0x4d -,0x06,0x3a,0xc1,0x74,0x36,0x4e,0x75,0xd9,0x80,0x3e,0x45,0x37,0x00,0x74,0x0b,0xc6 -,0x06,0x45,0x37,0x00,0xbf,0x2f,0x28,0xe9,0x72,0xff,0xc6,0x06,0x45,0x37,0x01,0xf7 -,0x06,0xb5,0x36,0x02,0x00,0x74,0x14,0xe5,0xce,0x25,0xfd,0xff,0xe7,0xce,0xe8,0x43 -,0x00,0xe5,0xce,0x0d,0x02,0x00,0xe7,0xce,0xe8,0x39,0x00,0x80,0x3e,0xe2,0x34,0x01 -,0x76,0x01,0xc3,0xb8,0xea,0x05,0xe7,0x8c,0xfa,0xe8,0x12,0xf4,0xfb,0x8d,0x06,0xd0 -,0x39,0x8b,0xd8,0xc1,0xe8,0x04,0xa3,0x38,0x34,0x8e,0xc0,0xa1,0x30,0x34,0x26,0xa3 -,0x02,0x00,0x26,0xc7,0x06,0x00,0x00,0xff,0xff,0x83,0xc3,0x18,0xd1,0xeb,0x26,0x89 -,0x1e,0x08,0x00,0xc3,0xe5,0x02,0x0d,0x00,0x40,0xe7,0x02,0xe5,0x00,0x0d,0x04,0x00 -,0xe7,0x00,0xb8,0x00,0x00,0xe7,0x0a,0xe5,0x0a,0xa9,0x00,0x80,0x75,0x14,0xe5,0x08 -,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x0a,0x0d,0x00,0x08,0xb9,0x05,0x00,0xe7,0x0a,0xe2 -,0xfc,0xc3,0xe5,0x08,0x0d,0x00,0x10,0xb9,0x05,0x00,0xe7,0x08,0xe2,0xfc,0xc3,0x04 -,0x0c,0x20,0x00,0x01,0x0c,0x7e,0xff,0x00,0x0c,0x02,0x00,0x10,0x00,0x40,0x00,0x0c -,0xc6,0x01,0x00,0x00,0xc0,0xf7,0xff,0x00,0xc0,0x02,0x00,0x10,0x00,0x40,0x00,0x00 -,0x33,0xc0,0x8e,0xd8,0x8d,0x3e,0x72,0x49,0x8d,0x36,0xb0,0x37,0xb9,0x14,0x00,0x8b -,0x1e,0x30,0x34,0x89,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05 -,0x89,0x44,0x04,0x83,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xc6,0x06,0x9e,0x36,0x0e -,0xe8,0xfd,0x26,0x68,0x83,0x28,0xa1,0xaa,0x02,0xcd,0x35,0x83,0x3e,0xa1,0x36,0x00 -,0x74,0x03,0xe9,0x3b,0x27,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e -,0xff,0xa4,0x2e,0x30,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x01,0x00,0xc6 -,0x06,0xca,0x34,0x01,0xe9,0x7d,0x19,0x80,0x3e,0xa0,0x36,0x08,0x74,0xe6,0x80,0x26 -,0x9e,0x36,0xff,0x75,0x1a,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x12,0xf7,0x06,0x9b -,0x36,0x03,0x00,0x75,0x0a,0x83,0x0e,0x66,0x37,0x10,0xc6,0x06,0xa0,0x36,0x08,0xe9 -,0xfb,0x01,0x80,0x3e,0x9e,0x36,0x02,0x75,0xce,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xec -,0x01,0xc3,0xe9,0xe8,0x01,0x26,0xc7,0x06,0x0a,0x00,0x00,0x00,0x26,0xff,0x26,0x04 -,0x00,0xa1,0xd1,0x36,0x26,0x39,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39 -,0x06,0x1c,0x00,0x75,0x18,0xa1,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26 -,0xf7,0x06,0x0c,0x00,0x40,0x00,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf -,0x36,0x00,0x10,0xa1,0xaf,0x36,0xe7,0x06,0x80,0x3e,0x9d,0x36,0x02,0x75,0x06,0xcd -,0x34,0xe9,0xa2,0x1a,0xc3,0xf7,0x06,0x9b,0x36,0x10,0x00,0x75,0x54,0x26,0xf6,0x06 -,0x0a,0x00,0xff,0x75,0x4c,0x26,0xa0,0x19,0x00,0x24,0xc0,0x3c,0x40,0x75,0x11,0x80 -,0x3e,0x95,0x36,0x00,0x74,0x3b,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0xe9,0x31,0x00 -,0xe8,0xf1,0x04,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0x2f,0x8b,0xd8,0xb8,0x7d,0x03 -,0xcd,0x3a,0x8b,0xc3,0xc6,0x06,0xa0,0x36,0x06,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75 -,0x05,0xc6,0x06,0xa0,0x36,0x04,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83,0x26,0x9b,0x36 -,0xfc,0xe9,0x23,0x01,0xe8,0x87,0x1d,0xe9,0x33,0x01,0x50,0x26,0xa1,0x0c,0x00,0x25 -,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x84,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9 -,0x7c,0x00,0x83,0x3e,0xe8,0x3a,0x04,0x74,0x75,0x83,0x3e,0xe8,0x3a,0x02,0x74,0x6e -,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00 -,0x80,0x74,0x35,0x26,0x80,0x3e,0x29,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36 -,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x74,0x45 -,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1 -,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b -,0x26,0x80,0x3e,0x19,0x00,0x00,0x74,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10 -,0x00,0x74,0x12,0x26,0xa0,0x28,0x00,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7 -,0x06,0x04,0x00,0xff,0xff,0x58,0x23,0xc0,0x74,0x03,0xe9,0x57,0xff,0x81,0x26,0x9b -,0x36,0xff,0xfe,0x83,0xfe,0x06,0x7f,0x24,0x26,0xa1,0x20,0x00,0x3b,0x06,0xd1,0x36 -,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10,0x26,0xa1,0x24,0x00 -,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01,0x26,0xa1,0x20,0x00 -,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba,0x34,0x26,0xa1,0x24 -,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1,0xe6,0x80,0xfc,0x09 -,0x74,0x03,0xe8,0xaa,0x1c,0x8b,0xc6,0x2e,0xff,0xa4,0x30,0x49,0x26,0xa1,0x0c,0x00 -,0x3d,0xff,0x7f,0x74,0x0f,0x26,0xff,0x26,0x04,0x00,0x8e,0x06,0x38,0x34,0xe8,0x36 -,0x06,0xcd,0x50,0xc3,0xe9,0x16,0x00,0xcd,0x34,0xe9,0x11,0x00,0xcd,0x34,0x89,0x36 -,0x3d,0x37,0xa1,0x9d,0x36,0xa3,0x3f,0x37,0xc6,0x06,0xa0,0x36,0x0c,0xe8,0x8e,0x00 -,0xa1,0x9f,0x36,0x22,0xe4,0x75,0x32,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x2a,0xf6 -,0x06,0x9d,0x36,0x80,0x74,0x07,0x88,0x26,0x9e,0x36,0xe9,0x31,0x00,0x3a,0x06,0x9d -,0x36,0xa3,0x9d,0x36,0x74,0x28,0x8b,0xf0,0x2e,0xff,0xa4,0x0d,0x2b,0x44,0x29,0xee -,0x42,0x19,0x44,0xcd,0x44,0x2f,0x45,0x5a,0x45,0x3a,0x26,0x9e,0x36,0x75,0x01,0xc3 -,0x32,0xc0,0x86,0xc4,0x8b,0xf0,0xa2,0x9e,0x36,0x2e,0xff,0xa4,0x20,0x49,0x8b,0x2e -,0x99,0x36,0x23,0xed,0x75,0x01,0xc3,0xbf,0x01,0x00,0xbe,0x00,0x00,0x85,0xfd,0x75 -,0x1a,0x46,0xd1,0xe7,0xe9,0xf6,0xff,0x2a,0x00,0x29,0x00,0x28,0x00,0x27,0x00,0x25 -,0x00,0x05,0x00,0x07,0x00,0x26,0x00,0x06,0x00,0x20,0x00,0xf7,0xd7,0x21,0x3e,0x99 -,0x36,0xd1,0xe6,0x2e,0x8b,0xb4,0x47,0x2b,0xe9,0x4f,0xff,0xe9,0x56,0xff,0x80,0x26 -,0x9e,0x36,0xff,0x75,0x17,0xf7,0x06,0x4c,0x37,0x01,0x00,0x75,0x0f,0xf6,0x06,0x9d -,0x36,0x80,0x74,0x08,0xf7,0x06,0x66,0x37,0xff,0xff,0x75,0x07,0xc7,0x06,0x66,0x37 -,0x00,0x00,0xc3,0xf7,0x06,0x41,0x37,0x01,0x00,0x75,0x0b,0xb8,0x7f,0x03,0xcd,0x39 -,0xc7,0x06,0x41,0x37,0x01,0x00,0x33,0xf6,0xb8,0x00,0x40,0x85,0x06,0x66,0x37,0x74 -,0x21,0x80,0xbc,0x54,0x37,0xff,0x74,0x04,0xfe,0x84,0x54,0x37,0x80,0xbc,0x96,0x34 -,0xff,0x74,0x04,0xfe,0x84,0x96,0x34,0x31,0x06,0x66,0x37,0x83,0x3e,0x66,0x37,0x00 -,0x74,0x05,0x46,0xd1,0xe8,0x73,0xd4,0xc3,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b -,0xa9,0x00,0x10,0x75,0x09,0x8b,0x1e,0x43,0x37,0xff,0xe3,0xe9,0xd7,0x00,0xc7,0x06 -,0x35,0x37,0x05,0x00,0xc7,0x06,0x43,0x37,0x1e,0x2c,0xf7,0x06,0xf4,0x33,0x00,0x08 -,0x74,0x06,0xc7,0x06,0x43,0x37,0x10,0x2c,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xcd,0xfe -,0xa9,0x00,0x08,0x74,0xd9,0xff,0x0e,0x35,0x37,0x75,0xed,0xe9,0x66,0x00,0xa9,0x00 -,0x08,0x75,0xcb,0xff,0x0e,0x35,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6 -,0x06,0x9d,0x36,0x80,0x74,0x48,0x81,0x0e,0x9b,0x36,0x00,0x80,0xf7,0x06,0x9b,0x36 -,0x01,0x00,0x74,0x1e,0xb8,0x7d,0x03,0xcd,0x3a,0x81,0x0e,0x9b,0x36,0x80,0x00,0x83 -,0x26,0x9b,0x36,0xfe,0xc7,0x06,0x0f,0x37,0x02,0x00,0xc6,0x06,0xa0,0x36,0x04,0xe9 -,0x7b,0xfe,0x80,0x3e,0xa0,0x36,0x04,0x75,0x07,0x83,0x3e,0x0f,0x37,0x01,0x75,0x05 -,0xc6,0x06,0xa0,0x36,0x06,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x5f,0xfe,0xbe,0x02 -,0x00,0xe9,0x4a,0xfe,0x80,0x26,0x9e,0x36,0xff,0x75,0x3a,0xf6,0x06,0x9d,0x36,0x80 -,0x74,0x2d,0xf7,0x06,0x9b,0x36,0x00,0x20,0x75,0x2b,0xc6,0x06,0xa0,0x36,0x06,0xff -,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a -,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x01,0xe9,0x06,0x00,0xbe -,0x04,0x00,0xe9,0x09,0xfe,0x81,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06 -,0xe5,0x0a,0xa9,0x00,0x80,0x74,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36 -,0xe7,0x06,0xe9,0x09,0xff,0xe9,0xf5,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0x83,0x0e -,0x99,0x36,0x02,0xe9,0xe7,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0x1d,0xf7,0x06,0x9b -,0x36,0x00,0x40,0x75,0x05,0x83,0x0e,0x99,0x36,0x08,0x83,0x0e,0x99,0x36,0x20,0x81 -,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x85,0x03,0xcd,0x39,0xe9,0xc0,0xfd,0x80,0x3e,0x9e -,0x36,0x06,0x74,0x07,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x34,0xf6,0x06,0x9d,0x36,0x80 -,0x75,0x06,0xbe,0x07,0x00,0xe9,0x96,0xfd,0xc6,0x06,0xa0,0x36,0x04,0x83,0x3e,0x0f -,0x37,0x02,0x74,0x1b,0xc7,0x06,0x0f,0x37,0x04,0x00,0x80,0x3e,0x9e,0x36,0x06,0x75 -,0x0e,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xe9 -,0x7b,0xfd,0x80,0x3e,0x9d,0x36,0x04,0x75,0x12,0x81,0x0e,0xc2,0x34,0x00,0x40,0xff -,0x06,0x92,0x34,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x62,0xfd,0xbe,0x05,0x00,0xe9,0x4d -,0xfd,0xf6,0x06,0x9d,0x36,0x80,0x75,0x19,0x83,0x0e,0xc2,0x34,0x04,0xbe,0x06,0x00 -,0xe9,0x3b,0xfd,0x80,0x26,0x9e,0x36,0xff,0x75,0xc5,0xff,0x06,0x31,0x37,0xe9,0x00 -,0x00,0x83,0x26,0xc2,0x34,0xbf,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x2f,0xfd,0xe5,0x0a -,0x50,0x25,0xc3,0xbf,0xe7,0x0a,0x58,0x80,0x26,0x9e,0x36,0xff,0x75,0x0d,0xa9,0x00 -,0x40,0x75,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0x12,0xfd,0xb8,0x83,0x03,0xcd,0x39 -,0xc3,0xb8,0x7c,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09,0xc7,0x06 -,0x33,0x37,0x02,0x00,0xe9,0xf6,0xfc,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9,0xed,0xfc -,0xff,0x06,0x8e,0x34,0xe8,0xf7,0x19,0x83,0x0e,0xc2,0x34,0x08,0xbe,0x03,0x00,0xe9 -,0xcc,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x04,0x04,0x05 -,0x04,0x04,0x04,0x00,0x03,0x00,0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x04,0x00,0x08,0x08,0x05,0x08,0x08,0x08,0x00,0x03,0x00,0x03,0x03,0x00,0x00 -,0x02,0x04,0x04,0x04,0x04,0x00,0x00,0x08,0x00,0x00,0x0a,0x14,0x00,0x00,0x1a,0x00 -,0x1c,0x00,0x1e,0x20,0x00,0x00,0x04,0x41,0x06,0x0b,0x08,0xc2,0xff,0xe7,0x04,0x03 -,0x06,0x04,0x04,0x05,0x04,0x06,0x04,0x87,0x04,0x03,0x06,0x04,0x04,0x85,0x4e,0xa2 -,0x04,0xcf,0x04,0xcd,0xc7,0x06,0xa2,0x37,0x00,0x00,0xc7,0x06,0xa6,0x37,0x00,0x00 -,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xf5,0x36,0x26,0xa1,0x22,0x00,0xa3,0xf7 -,0x36,0x26,0xa1,0x24,0x00,0xa3,0xf9,0x36,0xe8,0x3b,0x19,0x8b,0xf0,0x26,0x8b,0x0e -,0x0e,0x00,0x2b,0xc8,0x83,0xe9,0x0e,0xb8,0x01,0x80,0x83,0xf9,0x04,0x7c,0x51,0x26 -,0x8a,0x54,0x28,0x88,0x16,0x1c,0x37,0x40,0x26,0x8b,0x6c,0x26,0x86,0xcd,0x3b,0xcd -,0x86,0xcd,0x89,0x0e,0xa4,0x37,0x75,0x38,0x40,0x32,0xff,0x26,0x8a,0x5c,0x29,0x80 -,0xfb,0x15,0x77,0x25,0x80,0xfb,0x0a,0x74,0x20,0x80,0xfb,0x01,0x74,0x1b,0xb8,0x04 -,0x80,0x2e,0x3a,0x97,0x02,0x2e,0x74,0x07,0x2e,0x3a,0x97,0x18,0x2e,0x75,0x11,0x33 -,0xc0,0x80,0xfb,0x09,0x75,0x4f,0x8b,0xf3,0xc3,0x26,0xc7,0x06,0x04,0x00,0xff,0xff -,0x50,0x52,0xa1,0xa4,0x37,0x86,0xc4,0x26,0x3b,0x06,0x26,0x00,0x7c,0x32,0x26,0x81 -,0x3e,0x26,0x00,0x00,0x04,0x7e,0x29,0x8d,0x74,0x2a,0x26,0x8b,0x14,0x22,0xd2,0x74 -,0x1f,0x80,0xe6,0xbf,0x80,0xfe,0x09,0x75,0x17,0xc7,0x06,0xa2,0x37,0x01,0x00,0x80 -,0xfa,0x04,0x75,0x0c,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34 -,0x5a,0x58,0xe9,0xb1,0xff,0xbd,0x72,0x37,0x2e,0x8a,0x87,0x2e,0x2e,0x22,0xc0,0x74 -,0x16,0x05,0x44,0x2e,0x8b,0xf8,0x2e,0x8b,0x05,0x3e,0x89,0x46,0x00,0x83,0xc5,0x02 -,0x83,0xc7,0x02,0x22,0xe4,0x7d,0xef,0x8d,0x74,0x2a,0x83,0xe9,0x04,0x75,0x03,0xe9 -,0xa1,0x00,0x26,0x8b,0x14,0x22,0xd2,0x75,0x03,0xe9,0x7c,0x00,0xc7,0x06,0xa6,0x37 -,0x01,0x00,0xbf,0x72,0x37,0x8b,0x05,0x83,0xc7,0x02,0x80,0xe6,0xbf,0x80,0xe4,0x3f -,0x80,0xfe,0x09,0x75,0x22,0x80,0xfa,0x04,0x75,0x5e,0xc7,0x06,0xa2,0x37,0x01,0x00 -,0x26,0x8b,0x44,0x02,0xa3,0x03,0x37,0x86,0xc4,0xa3,0xd0,0x34,0x86,0xc4,0xc7,0x06 -,0xa6,0x37,0x00,0x00,0xe9,0x47,0x00,0x3b,0xfd,0x7e,0x15,0x26,0x8b,0x04,0xa8,0x40 -,0x74,0x06,0xb8,0x07,0x80,0xe9,0x38,0xff,0x32,0xc0,0x26,0x8b,0x04,0xe9,0x2e,0x00 -,0x3a,0xf4,0x75,0xb1,0xc7,0x45,0xfe,0x00,0x00,0x80,0xfe,0x22,0x75,0x0d,0x3a,0xd0 -,0x77,0x16,0xc7,0x06,0xa6,0x37,0x00,0x00,0xe9,0x13,0x00,0x3a,0xd0,0x75,0x09,0xc7 -,0x06,0xa6,0x37,0x00,0x00,0xe9,0x06,0x00,0xb8,0x05,0x80,0xe9,0x02,0xff,0x32,0xf6 -,0x03,0xf2,0x2b,0xca,0xb8,0x05,0x80,0x23,0xc9,0x76,0x03,0xe9,0x64,0xff,0x74,0x03 -,0xe9,0xed,0xfe,0x33,0xc0,0xbf,0x72,0x37,0x8b,0x15,0x47,0x47,0x3b,0xfd,0x7f,0x1b -,0xf6,0xc6,0x80,0x74,0x16,0xf7,0x06,0xa6,0x37,0x01,0x00,0x74,0x06,0xb8,0x08,0x80 -,0xe9,0xc3,0xfe,0xf6,0xc6,0x40,0x74,0xe0,0xb8,0x07,0x80,0xe9,0xb8,0xfe,0x7d,0x42 -,0xa3,0x45,0x44,0x29,0x44,0x29,0xb7,0x28,0xe2,0x28,0xee,0x2b,0xf2,0x28,0xf5,0x28 -,0x01,0x29,0xac,0x2a,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x44,0x29,0x00,0x00 -,0x73,0x36,0x00,0x00,0x03,0x36,0xc5,0x35,0x83,0x35,0x45,0x35,0x07,0x35,0xd2,0x34 -,0x45,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0xa6,0x38,0x00,0x00,0xe0,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0xf2,0x33,0x00,0x00,0xa6,0x33,0x60,0x33,0xfd,0x32,0xbc,0x32,0x77,0x32,0x3c,0x32 -,0xfb,0x31,0x6a,0x31,0x0a,0x31,0xe0,0xe0,0x10,0x10,0x10,0xe0,0xe0,0xe0,0xe0,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0 -,0xe0,0x33,0xff,0x26,0xf6,0x06,0x1a,0x00,0x80,0x74,0x1b,0x26,0x80,0x26,0x1a,0x00 -,0x7f,0x26,0x8b,0x3e,0x26,0x00,0x83,0xe7,0x1f,0x74,0x0b,0x26,0x80,0x0e,0x20,0x00 -,0x80,0x26,0x01,0x3e,0x0e,0x00,0xc3,0x60,0x2e,0x8b,0x84,0xa6,0x30,0x26,0xa3,0x18 -,0x00,0xd1,0xe6,0x2e,0xff,0x94,0x50,0x30,0x61,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4 -,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x16,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26 -,0xc6,0x06,0x19,0x00,0x00,0xe8,0xbf,0x05,0xe8,0x98,0x05,0x26,0xc7,0x06,0x26,0x00 -,0x00,0x08,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x2a,0xbf,0x2a -,0x00,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x2a,0xa1,0x93,0x37,0x33,0xdb,0xa9 -,0x40,0x00,0x75,0x02,0xb3,0x01,0xa9,0x00,0x10,0x74,0x02,0xb7,0x88,0xa9,0x00,0x08 -,0x74,0x03,0x80,0xcf,0x44,0x26,0x89,0x5d,0x02,0xc3,0x83,0x0e,0xc2,0x34,0x20,0x26 -,0xc7,0x06,0x04,0x00,0x6b,0x2b,0x26,0xc7,0x06,0x0e,0x00,0x30,0x00,0x26,0xc7,0x06 -,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00 -,0x00,0xe8,0x69,0x05,0xe8,0x2c,0x05,0x26,0xc7,0x06,0x26,0x00,0x00,0x22,0x26,0xc6 -,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x29,0xbf,0x2a,0x00,0x26,0xc6,0x05 -,0x08,0x26,0xc6,0x45,0x01,0x2d,0x8d,0x7d,0x02,0xbe,0x54,0x37,0xb9,0x03,0x00,0xf3 -,0xa5,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x2e,0x8d,0x7d,0x02,0xbe,0x5a,0x37 -,0xb9,0x03,0x00,0xf3,0xa5,0xe8,0xd4,0x05,0xe8,0x64,0x05,0xb9,0x06,0x00,0xbe,0x54 -,0x37,0x8d,0x2e,0x2c,0x00,0x26,0x8b,0x46,0x00,0x29,0x04,0x83,0xc6,0x02,0x83,0xc5 -,0x02,0x83,0xf9,0x04,0x75,0x02,0x45,0x45,0xe2,0xeb,0xc3,0x26,0xc7,0x06,0x04,0x00 -,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00 -,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xe4,0x04,0xe8,0xa7,0x04,0x26,0xc7,0x06,0x26 -,0x00,0x00,0x16,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x28,0xbf -,0x2a,0x00,0xe8,0x5b,0x06,0xe8,0x74,0x05,0xe8,0x04,0x05,0xc3,0x26,0xc7,0x06,0x04 -,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1a,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 -,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0xa3,0x04,0xe8,0x66,0x04,0x26,0xc7,0x06 -,0x26,0x00,0x00,0x0c,0x26,0xc6,0x06,0x28,0x00,0x60,0x26,0xc6,0x06,0x29,0x00,0x27 -,0xbf,0x2a,0x00,0xe8,0x21,0x05,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7 -,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0a,0x00,0x26,0xc7,0x06,0x0a -,0x00,0x04,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x4b,0x04,0xe8,0x24,0x04,0x26 -,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29 -,0x00,0x26,0xbf,0x2a,0x00,0xe8,0xf4,0x04,0xe8,0x84,0x04,0xc3,0x26,0xc7,0x06,0x04 -,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 -,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x0d,0x04,0xe8,0xe6,0x03,0x26,0xc7,0x06 -,0x26,0x00,0x00,0x26,0x26,0xc6,0x06,0x28,0x00,0x40,0x26,0xc6,0x06,0x29,0x00,0x25 -,0xbf,0x2a,0x00,0xe8,0xb6,0x04,0xe8,0x46,0x04,0xe8,0xfa,0x04,0xc3,0x26,0xc7,0x06 -,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x38,0x00,0xa1,0xa2,0x37,0x50,0x0b -,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06 -,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x99,0x03,0xe8,0xa4,0xfd,0x26,0xc7,0x45 -,0x26,0x00,0x2a,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c -,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x24,0x83,0xc7,0x2a -,0xe8,0x29,0x04,0xe8,0xa0,0x04,0xe8,0x22,0x05,0xe8,0xf8,0x03,0xe8,0x09,0x04,0xc3 -,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x32,0x00,0x26,0xc7 -,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x45,0x03,0xe8,0x50 -,0xfd,0x26,0xc7,0x45,0x26,0x00,0x24,0xa1,0x1c,0x37,0xc1,0xe0,0x04,0x26,0x88,0x45 -,0x28,0x26,0xc6,0x45,0x29,0x23,0x83,0xc7,0x2a,0xe8,0xe0,0x03,0xe8,0x6c,0x04,0xe8 -,0x8a,0x04,0xe8,0x9c,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06 -,0x0e,0x00,0x34,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00 -,0x00,0xe8,0xff,0x02,0xe8,0x0a,0xfd,0x26,0xc7,0x45,0x26,0x00,0x26,0xa1,0x1c,0x37 -,0xc1,0xe0,0x04,0x26,0x88,0x45,0x28,0x26,0xc6,0x45,0x29,0x22,0x83,0xc7,0x2a,0xe8 -,0x9a,0x03,0xe8,0xc7,0x03,0xe8,0x57,0x03,0xe8,0xf8,0x03,0xe8,0x78,0x04,0xe8,0x8a -,0x04,0xc3,0x26,0xc7,0x06,0x04,0x00,0x74,0x45,0x26,0xc7,0x06,0x0e,0x00,0x3e,0x00 -,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc7,0x06,0x0a,0x00,0x04,0x00,0x26,0xc6 -,0x06,0x19,0x00,0x00,0xe8,0xfc,0x02,0xe8,0xa9,0x02,0x83,0x3e,0x8d,0x37,0x03,0x75 -,0x01,0x90,0x26,0xc7,0x06,0x26,0x00,0x00,0x30,0x26,0xc6,0x06,0x28,0x00,0x50,0x26 -,0xc6,0x06,0x29,0x00,0x20,0xbf,0x2a,0x00,0xe8,0xd0,0x03,0xe8,0x01,0x03,0xe8,0xb5 -,0x03,0xe8,0x9f,0x03,0xc3,0x26,0xc7,0x06,0x04,0x00,0x61,0x43,0xb9,0xf0,0x00,0x83 -,0xe9,0x02,0x26,0x89,0x0e,0x0e,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6 -,0x06,0x19,0x00,0x00,0x26,0xc7,0x06,0x1a,0x00,0x00,0x00,0x26,0xc7,0x06,0x1c,0x00 -,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x00,0xe8,0x47,0x02,0x83,0xe9,0x0e,0x86 -,0xcd,0x26,0x89,0x0e,0x26,0x00,0x86,0xcd,0x26,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6 -,0x06,0x29,0x00,0x08,0xbf,0x2a,0x00,0x83,0xe9,0x04,0x26,0x89,0x0d,0x26,0xc6,0x45 -,0x01,0x26,0x8d,0x7d,0x02,0x83,0xe9,0x02,0xbb,0x01,0x00,0xb8,0x30,0x30,0x4b,0x75 -,0x17,0xbb,0x0a,0x00,0x8a,0xc4,0x26,0x88,0x05,0xb0,0x31,0x80,0xc4,0x01,0x80,0xfc -,0x3a,0x75,0x0a,0xb4,0x61,0xe9,0x05,0x00,0x26,0x88,0x05,0x04,0x01,0x47,0x49,0x75 -,0xdd,0xc3,0x26,0xc7,0x06,0x04,0x00,0x04,0x45,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00 -,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x01,0xe8,0xe5,0x01 -,0xe8,0xd0,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x04,0x26,0xc6,0x06,0x28,0x00,0x00 -,0x26,0xc6,0x06,0x29,0x00,0x07,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7 -,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19 -,0x00,0x06,0xe8,0x04,0x02,0xe8,0x9b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26 -,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x06,0xbf,0x2a,0x00,0xe8,0x6b -,0x02,0xe8,0xfb,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e -,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x05 -,0xe8,0xc6,0x01,0xe8,0x5d,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06 -,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x05,0xbf,0x2a,0x00,0xe8,0x2d,0x02,0xe8 -,0xbd,0x01,0xc3,0xff,0x06,0x82,0x34,0x26,0xc7,0x06,0x04,0x00,0x3d,0x41,0x26,0xc7 -,0x06,0x0e,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x0e,0x00,0x26,0xc6,0x06,0x19 -,0x00,0x04,0xe8,0x84,0x01,0xe8,0x1b,0x01,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26 -,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x04,0xbf,0x2a,0x00,0xe8,0xeb -,0x01,0xe8,0x7b,0x01,0xc3,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7,0x06,0x0e -,0x00,0x20,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19,0x00,0x03 -,0xe8,0x46,0x01,0xe8,0xdd,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x12,0x26,0xc6,0x06 -,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x03,0xbf,0x2a,0x00,0xe8,0xad,0x01,0xe8 -,0x3d,0x01,0xc3,0xff,0x06,0x84,0x34,0x26,0xc7,0x06,0x04,0x00,0x67,0x42,0x26,0xc7 -,0x06,0x0e,0x00,0x24,0x00,0x26,0xc7,0x06,0x06,0x00,0x08,0x00,0x26,0xc6,0x06,0x19 -,0x00,0x02,0xe8,0x04,0x01,0xe8,0x9b,0x00,0x26,0xc7,0x06,0x26,0x00,0x00,0x16,0x26 -,0xc6,0x06,0x28,0x00,0x00,0x26,0xc6,0x06,0x29,0x00,0x02,0xbf,0x2a,0x00,0x26,0xc6 -,0x05,0x04,0x26,0xc6,0x45,0x01,0x01,0xa1,0x0f,0x37,0x86,0xe0,0xf6,0x06,0x6f,0x37 -,0x01,0x75,0x0f,0x39,0x06,0xcc,0x34,0x74,0x09,0x8b,0xd8,0xb8,0x89,0x03,0xcd,0x39 -,0x8b,0xc3,0xa3,0xcc,0x34,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xe8,0x3d,0x01,0xe8 -,0xcd,0x00,0xc3,0x26,0xc7,0x06,0x04,0x00,0xc4,0x2a,0x26,0xc7,0x06,0x0e,0x00,0x1c -,0x00,0xa1,0xa2,0x37,0x50,0x0b,0xc0,0x75,0x07,0x26,0xc7,0x06,0x0e,0x00,0x18,0x00 -,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x23,0x00 -,0xe8,0x2e,0xfa,0x26,0xc7,0x45,0x26,0x00,0x0e,0x58,0x0b,0xc0,0x75,0x06,0x26,0xc7 -,0x45,0x26,0x00,0x0a,0x26,0xc6,0x45,0x29,0x00,0x83,0xc7,0x2a,0xe8,0xbd,0x00,0xe8 -,0xff,0x00,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x20,0x00,0xf3 -,0xa5,0x59,0x5f,0x5e,0xc3,0x56,0x57,0x51,0xb9,0x03,0x00,0xbe,0xd1,0x36,0xbf,0x1a -,0x00,0xf3,0xa5,0x59,0x5f,0x5e,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7 -,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x10,0xc3,0x26,0xc7,0x06 -,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00,0x00,0x26,0xc7,0x06,0x1e,0x00 -,0x00,0x08,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00,0x26,0xc7,0x06,0x1c,0x00,0x00 -,0x00,0x26,0xc7,0x06,0x1e,0x00,0x00,0x02,0xc3,0x26,0xc7,0x06,0x1a,0x00,0xc0,0x00 -,0x26,0xc7,0x06,0x1c,0x00,0xff,0xff,0x26,0xc7,0x06,0x1e,0x00,0xff,0xff,0xc3,0x26 -,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03 -,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x06,0xa1,0x0d,0x37 -,0x26,0x89,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01 -,0x07,0xa1,0x0b,0x37,0x26,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0xa1,0xa2,0x37,0x0b -,0xc0,0x74,0x13,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x09,0xa1,0x03,0x37,0x26 -,0x89,0x45,0x02,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x02 -,0x8d,0x7d,0x02,0xbe,0x05,0x37,0xb9,0x03,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06 -,0x26,0xc6,0x45,0x01,0x0b,0x8d,0x7d,0x02,0xbe,0xef,0x36,0xb9,0x02,0x00,0xf3,0xa5 -,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x20,0xa1,0x68,0x37,0x26,0x89,0x45 -,0x02,0xa1,0x6a,0x37,0x26,0x88,0x65,0x05,0xc1,0xe0,0x04,0x26,0x88,0x45,0x04,0x83 -,0xc7,0x06,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45,0x02 -,0x00,0x00,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x14,0x26,0xc6,0x45,0x01,0x22,0x8d -,0x7d,0x02,0xbe,0x1f,0x37,0xb9,0x09,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x0c,0x26 -,0xc6,0x45,0x01,0x23,0x8d,0x7d,0x02,0x1e,0x0e,0x1f,0x8d,0x36,0x40,0x54,0xb9,0x03 -,0x00,0xf3,0xa5,0x33,0xc0,0xb9,0x02,0x00,0xf3,0xab,0x1f,0xc3,0x26,0xc6,0x05,0x08 -,0x26,0xc6,0x45,0x01,0x28,0x8d,0x7d,0x02,0xbe,0xd1,0x36,0xb9,0x03,0x00,0xf3,0xa5 -,0xc3,0x26,0xc6,0x05,0x08,0x26,0xc6,0x45,0x01,0x29,0xa1,0xc2,0x34,0x86,0xe0,0x26 -,0x89,0x45,0x02,0xa1,0x9b,0x36,0x26,0x89,0x45,0x04,0x26,0x88,0x45,0x06,0x26,0x88 -,0x45,0x07,0x8d,0x7d,0x08,0xc3,0x26,0xc6,0x05,0x06,0x26,0xc6,0x45,0x01,0x2b,0x8d -,0x7d,0x02,0xbe,0xbb,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3,0x26,0xc6,0x05,0x06,0x26 -,0xc6,0x45,0x01,0x2c,0x8d,0x7d,0x02,0xbe,0xe5,0x36,0xb9,0x02,0x00,0xf3,0xa5,0xc3 -,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x30,0xa1,0x37,0x37,0x86,0xe0,0x26,0x89 -,0x45,0x02,0x8d,0x7d,0x04,0xc3,0x26,0xc7,0x06,0x0e,0x00,0x1e,0x00,0x26,0xc7,0x06 -,0x06,0x00,0x02,0x00,0x26,0xc6,0x06,0x19,0x00,0x00,0xe8,0x6c,0xfe,0xe8,0x03,0xfe -,0x26,0xc7,0x06,0x26,0x00,0x00,0x10,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06 -,0x29,0x00,0x11,0xbf,0x2a,0x00,0xe8,0x35,0x00,0xe8,0x45,0x00,0xe8,0x55,0x00,0xc3 -,0x26,0xc7,0x06,0x0e,0x00,0x12,0x00,0x26,0xc7,0x06,0x06,0x00,0x02,0x00,0x26,0xc6 -,0x06,0x19,0x00,0x00,0xe8,0x32,0xfe,0xe8,0xc9,0xfd,0x26,0xc7,0x06,0x26,0x00,0x00 -,0x04,0x26,0xc6,0x06,0x28,0x00,0x30,0x26,0xc6,0x06,0x29,0x00,0x13,0xc3,0x26,0xc6 -,0x05,0x04,0x26,0xc6,0x45,0x01,0x0c,0x26,0xc7,0x45,0x02,0x00,0x01,0x83,0xc7,0x04 -,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x0e,0x26,0xc7,0x45,0x02,0x00,0x02 -,0x83,0xc7,0x04,0xc3,0x26,0xc6,0x05,0x04,0x26,0xc6,0x45,0x01,0x21,0x26,0xc7,0x45 -,0x02,0x00,0x00,0x83,0xc7,0x04,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0xb3,0x39,0xc9,0x39,0x83,0x3a,0xb3,0x39,0xb3,0x39,0xb3,0x39,0x1c,0x3a,0x1c,0x3a -,0xa3,0xb6,0x34,0xa1,0xe9,0x36,0xa3,0x11,0x37,0xa3,0xd2,0x34,0xa1,0xeb,0x36,0xa3 -,0x13,0x37,0xa3,0xd4,0x34,0xa1,0xed,0x36,0xa3,0x15,0x37,0xa3,0xd6,0x34,0xa1,0x01 -,0x37,0xa3,0xce,0x34,0xa1,0xf7,0x36,0xa3,0x17,0x37,0xa3,0xdc,0x34,0xa1,0xf9,0x36 -,0xa3,0x19,0x37,0xa3,0xde,0x34,0xf7,0x06,0x9b,0x36,0x02,0x00,0x75,0x0c,0x33,0xc0 -,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x50,0x39,0xe9,0x0f,0x01,0xbe,0x07,0x00 -,0xe9,0x19,0xf1,0xf6,0x06,0x9d,0x36,0x80,0x74,0xf3,0xc6,0x06,0xa0,0x36,0x02,0xc6 -,0x06,0x6e,0x37,0x08,0xc6,0x06,0x70,0x37,0x02,0xb8,0x88,0x03,0xcd,0x39,0xf6,0x06 -,0x6f,0x37,0x01,0x75,0x4a,0xa1,0xd1,0x36,0x3a,0x06,0xe9,0x36,0x75,0x41,0x3a,0x26 -,0xea,0x36,0x75,0x3b,0xa1,0xd3,0x36,0x3a,0x06,0xeb,0x36,0x75,0x32,0x3a,0x26,0xec -,0x36,0x75,0x2c,0xa1,0xd5,0x36,0x3a,0x06,0xed,0x36,0x75,0x23,0x3a,0x26,0xee,0x36 -,0x75,0x1d,0xc6,0x06,0x70,0x37,0x02,0xfe,0x0e,0x6e,0x37,0x75,0x0f,0xb8,0x88,0x03 -,0xcd,0x3a,0x83,0x0e,0x9b,0x36,0x12,0xc6,0x06,0xa0,0x36,0x0c,0xe9,0xa8,0xf0,0xa1 -,0x05,0x37,0x26,0x3b,0x06,0x20,0x00,0x75,0x40,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22 -,0x00,0x75,0x36,0xa1,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x2c,0xa0,0x9e,0x36 -,0x3c,0x02,0x75,0x08,0x26,0xf6,0x06,0x18,0x00,0x08,0x75,0x47,0xc6,0x06,0x6e,0x37 -,0x08,0xfe,0x0e,0x70,0x37,0x75,0x1c,0xc6,0x06,0x70,0x37,0x02,0xe5,0x02,0x0d,0x01 -,0x04,0x25,0xef,0xff,0xe7,0x02,0xe9,0x5e,0xf0,0xc6,0x06,0x70,0x37,0x02,0xc6,0x06 -,0x6e,0x37,0x08,0xe5,0x02,0x25,0xff,0xfb,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02 -,0xe9,0x44,0xf0,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x25,0x26,0xf6,0x06,0x18,0x00 -,0x08,0x75,0xed,0x81,0x26,0x9b,0x36,0x7f,0xff,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x84 -,0x03,0xcd,0x3a,0xc6,0x06,0xa0,0x36,0x06,0x83,0x26,0xc2,0x34,0xaf,0xe9,0x17,0xf0 -,0xa1,0x01,0x37,0x3a,0x26,0x0f,0x37,0x7f,0xc7,0xe9,0xf7,0xfe,0x83,0x26,0x9b,0x36 -,0xec,0xe8,0x2a,0x0d,0x81,0x0e,0x9b,0x36,0x80,0x00,0xbb,0xff,0x7f,0xcd,0x53,0xc6 -,0x06,0xa0,0x36,0x02,0xe9,0xf0,0xef,0x83,0x0e,0x9b,0x36,0x11,0xc6,0x06,0xa0,0x36 -,0x0c,0xe9,0xf9,0xef,0x44,0x3b,0x2c,0x3b,0xc7,0x2a,0x6b,0x3b,0x44,0x3b,0xc7,0x2a -,0xc7,0x2a,0xc7,0x2a,0xa3,0xb6,0x34,0x81,0x0e,0xc2,0x34,0x00,0x20,0xf7,0x06,0x41 -,0x37,0x01,0x00,0x74,0x1b,0x8c,0xc3,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f,0x03 -,0xcd,0x3a,0x33,0xc0,0x8e,0xc0,0xbf,0x54,0x37,0xb9,0x06,0x00,0xf3,0xab,0x8e,0xc3 -,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0xe4,0x3a,0xf7,0x06,0x9b,0x36 -,0x00,0x01,0x75,0x21,0x83,0x26,0xc2,0x34,0xbf,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0x9b -,0x36,0xe9,0x09,0x00,0xa1,0x9b,0x36,0x81,0x26,0x9b,0x36,0xff,0xdf,0xa9,0x00,0x20 -,0x75,0x06,0xe9,0x6e,0x00,0xe9,0x6f,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37 -,0x37,0x01,0x00,0xc6,0x06,0xca,0x34,0x01,0xe9,0x58,0x00,0x83,0x0e,0x9b,0x36,0x40 -,0xe8,0x58,0x00,0xa1,0x05,0x37,0x3b,0x06,0xe9,0x36,0x75,0x37,0xa1,0x07,0x37,0x3b -,0x06,0xeb,0x36,0x75,0x2e,0xa1,0x09,0x37,0x3b,0x06,0xed,0x36,0x75,0x25,0xfe,0x0e -,0x71,0x37,0x75,0x1c,0xb8,0x87,0x03,0xcd,0x3a,0x83,0x0e,0x99,0x36,0x10,0xa1,0x50 -,0x37,0xc7,0x06,0x50,0x37,0x00,0x00,0x09,0x06,0x99,0x36,0xc6,0x06,0xa0,0x36,0x08 -,0xe9,0x14,0xef,0x83,0x0e,0x99,0x36,0x04,0xc7,0x06,0x37,0x37,0x03,0x00,0xc6,0x06 -,0xca,0x34,0x03,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0xfc,0xee,0xa1,0xd1,0x36,0x26,0x3b -,0x06,0x20,0x00,0x75,0x15,0xa1,0xd3,0x36,0x26,0x3b,0x06,0x22,0x00,0x75,0x12,0xa1 -,0xd5,0x36,0x26,0x3b,0x06,0x24,0x00,0x75,0x0f,0xc3,0x8d,0x36,0x20,0x00,0xe9,0x0b -,0x00,0x8d,0x36,0x22,0x00,0xe9,0x04,0x00,0x8d,0x36,0x24,0x00,0x83,0xc4,0x02,0xf7 -,0x06,0xe6,0x34,0x01,0x00,0x74,0x15,0x26,0x3a,0x04,0x77,0x08,0x72,0x0e,0x26,0x3a -,0x64,0x01,0x72,0x08,0xc6,0x06,0xa0,0x36,0x06,0xe9,0xab,0xee,0xe8,0x7c,0x0a,0x8c -,0xc0,0x3d,0xff,0xff,0x74,0x1b,0x26,0xc6,0x06,0x18,0x00,0x10,0x26,0xc7,0x06,0x04 -,0x00,0x49,0x3c,0x26,0xc7,0x06,0x06,0x00,0x0c,0x00,0xcd,0x50,0xb9,0x4e,0x00,0xe2 -,0xfe,0xc6,0x06,0xa0,0x36,0x0a,0xe9,0x94,0xee,0xe9,0x7b,0xee,0x8f,0x3c,0x06,0x3d -,0x06,0x3d,0x06,0x3d,0xd2,0x3c,0xea,0x3c,0x06,0x3d,0x06,0x3d,0xa3,0xb6,0x34,0x81 -,0x26,0xc2,0x34,0xaf,0xdf,0xc7,0x06,0x4c,0x37,0x00,0x00,0xb8,0x8a,0x03,0xcd,0x3a -,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74,0x05,0xc6,0x06 -,0x9f,0x36,0x06,0x33,0xc0,0xa0,0x9e,0x36,0x8b,0xf0,0x2e,0xff,0xa4,0x4c,0x3c,0xf7 -,0x06,0x9b,0x36,0x00,0x20,0x75,0x0e,0x81,0x26,0x9b,0x36,0xff,0xbf,0xb8,0x8b,0x03 -,0xcd,0x3a,0xe9,0x54,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x03,0xe9,0x17,0xee -,0xc7,0x06,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04 -,0x83,0x0e,0x50,0x37,0x04,0xf6,0x06,0x9d,0x36,0x80,0x75,0x2a,0xe8,0x1f,0x0b,0xe9 -,0x27,0x00,0xf7,0x06,0x9b,0x36,0x00,0x01,0x75,0xd3,0xc7,0x06,0x37,0x37,0x02,0x00 -,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0xc6,0x06,0xa0,0x36,0x00,0xf6 -,0x06,0x9d,0x36,0x80,0x74,0x03,0xe8,0xde,0x0a,0x81,0x26,0x9b,0x36,0x7c,0xff,0xbb -,0xff,0xff,0xcd,0x53,0xcd,0x54,0xe9,0xbe,0xed,0xa3,0xb6,0x34,0xe8,0xad,0x01,0xb8 -,0x86,0x03,0xcd,0x39,0xc7,0x06,0x4c,0x37,0x00,0x00,0x81,0x26,0xc2,0x34,0xaf,0xdf -,0xf6,0x06,0x9d,0x36,0x80,0x74,0x34,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x56,0xf7 -,0x06,0x9b,0x36,0x00,0x01,0x74,0x27,0xe8,0x35,0x01,0x72,0x1c,0xbe,0x00,0x40,0x85 -,0x36,0xc2,0x34,0x75,0x08,0x09,0x36,0xc2,0x34,0xff,0x06,0x92,0x34,0xe8,0x8b,0x01 -,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x6c,0xed,0xe9,0xb5,0x00,0xc7,0x06 -,0x37,0x37,0x02,0x00,0xc6,0x06,0xca,0x34,0x02,0x83,0x0e,0x99,0x36,0x04,0x83,0x0e -,0x50,0x37,0x04,0x80,0x3e,0x9e,0x36,0x08,0x74,0x03,0xe8,0x5a,0x0a,0xe8,0xef,0x00 -,0x72,0xd6,0xe9,0xc8,0xff,0x80,0x3e,0x9e,0x36,0x0a,0x75,0x12,0xc6,0x06,0xa0,0x36 -,0x00,0xf7,0x06,0x9b,0x36,0x08,0x00,0x74,0x02,0xcd,0x54,0xe8,0x39,0x0a,0x81,0x26 -,0x9b,0x36,0xff,0xbf,0xe8,0xc8,0x00,0x72,0xaf,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x9c -,0xff,0xf6,0x06,0x9e,0x36,0xff,0x75,0x58,0xa3,0xb6,0x34,0xe8,0xfe,0x00,0x81,0x26 -,0xc2,0x34,0xff,0xbf,0xf6,0x06,0x9d,0x36,0x80,0x74,0x48,0xf7,0x06,0x9b,0x36,0x00 -,0x20,0x74,0x22,0xf7,0x06,0x9b,0x36,0x00,0x40,0x75,0x08,0xe8,0x91,0x00,0x72,0x30 -,0xe9,0x22,0x00,0x26,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x75,0x24,0x81,0x0e,0x66,0x37 -,0x00,0x08,0xe9,0xd2,0xec,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe8,0x71,0x00,0x72,0x10 -,0xb8,0x8b,0x03,0xcd,0x39,0xe8,0xd3,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00 -,0xe9,0xb4,0xec,0x80,0x3e,0x9d,0x36,0x04,0x75,0x0c,0x80,0x3e,0x9e,0x36,0x06,0x74 -,0x46,0xc6,0x06,0x9f,0x36,0x06,0xf7,0x06,0x9b,0x36,0x00,0x01,0x74,0x0c,0x80,0x3e -,0x9d,0x36,0x08,0x75,0x05,0xc6,0x06,0x9f,0x36,0x0a,0xe8,0x32,0x00,0x72,0xd1,0xe8 -,0x99,0x00,0x80,0x3e,0x9d,0x36,0x08,0x75,0x13,0x81,0x0e,0x99,0x36,0x80,0x00,0xf7 -,0x06,0x9b,0x36,0x00,0x20,0x75,0x08,0xb8,0x8b,0x03,0xcd,0x39,0xe9,0x68,0xec,0xc6 -,0x06,0x9f,0x36,0x0a,0xe9,0x60,0xec,0xb8,0x86,0x03,0xcd,0x3a,0xe9,0x58,0xec,0x26 -,0xa1,0x0c,0x00,0xa9,0x60,0x00,0x74,0x08,0x81,0x26,0xc2,0x34,0xff,0xbf,0xf9,0xc3 -,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x13,0x81,0x0e,0x66,0x37,0x00,0x08,0xe8,0x4a -,0x00,0x73,0x06,0x81,0x0e,0x99,0x36,0x80,0x00,0xf9,0xc3,0x81,0x0e,0x9b,0x36,0x00 -,0x40,0x80,0x26,0x6f,0x37,0xfe,0x81,0x26,0x9b,0x36,0x7f,0xff,0xc6,0x06,0xa0,0x36 -,0x00,0xf8,0xc3,0x81,0x0e,0x99,0x36,0x00,0x01,0xe9,0x21,0xec,0x26,0xa1,0x20,0x00 -,0xa3,0xfb,0x36,0xa3,0xaa,0x34,0x26,0xa1,0x22,0x00,0xa3,0xfd,0x36,0xa3,0xac,0x34 -,0x26,0xa1,0x24,0x00,0xa3,0xff,0x36,0xa3,0xae,0x34,0xc3,0xa1,0x05,0x37,0x26,0x3b -,0x06,0x20,0x00,0x75,0x19,0xa1,0x07,0x37,0x26,0x3b,0x06,0x22,0x00,0x75,0x0f,0xa1 -,0x09,0x37,0x26,0x3b,0x06,0x24,0x00,0x75,0x05,0xe8,0x02,0x00,0xf8,0xc3,0x51,0x1e -,0x06,0x8b,0xc7,0x8d,0x36,0x20,0x00,0xbf,0x05,0x37,0xb9,0x03,0x00,0x1e,0x06,0x1f -,0x07,0xf3,0xa5,0x8b,0xf8,0x8d,0x36,0x20,0x00,0xbf,0xa0,0x34,0xb9,0x03,0x00,0xf3 -,0xa5,0x07,0x1f,0x59,0x8b,0xf8,0xa1,0x07,0x37,0xa3,0xa6,0x34,0xa1,0x09,0x37,0xa3 -,0xa8,0x34,0xf9,0xc3,0xc6,0x06,0xb6,0x34,0x01,0xe9,0x8b,0xeb,0xe8,0x87,0x08,0x8b -,0xf0,0x05,0x12,0x00,0x26,0x29,0x06,0x0e,0x00,0x26,0x8b,0x44,0x2a,0x26,0x3a,0x06 -,0x0e,0x00,0x75,0x5b,0x26,0x83,0x2e,0x0e,0x00,0x02,0x80,0xfc,0x27,0x75,0x50,0x26 -,0x8b,0x44,0x2c,0xa9,0xff,0xff,0x75,0x47,0x8b,0xfe,0x33,0xc0,0x26,0xf6,0x45,0x3c -,0x80,0x74,0x06,0x26,0x8a,0x45,0x3a,0x24,0x1f,0x03,0xf8,0x26,0x80,0x7d,0x45,0x09 -,0x75,0x2d,0x8c,0xc2,0x8e,0x06,0x38,0x34,0x8e,0xda,0x8b,0x0e,0x0e,0x00,0x26,0x89 -,0x0e,0x0e,0x00,0x8d,0x74,0x2c,0xbf,0x18,0x00,0xf3,0xa4,0x33,0xc0,0x8e,0xd8,0x26 -,0xc7,0x06,0x04,0x00,0xb5,0x3f,0x26,0xc7,0x06,0x06,0x00,0x06,0x00,0xcd,0x50,0xb8 -,0x06,0x80,0xe9,0xef,0xe9,0x26,0xa1,0x0c,0x00,0xa3,0x93,0x37,0x83,0x0e,0x99,0x36 -,0x01,0xe9,0x00,0xeb,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e -,0x00,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36 -,0x26,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3 -,0x1e,0x00,0xb8,0x0a,0x80,0xe8,0x36,0x07,0xe9,0xe2,0xea,0xff,0x06,0x90,0x34,0xbe -,0x0a,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e -,0xc2,0x34,0x01,0xe9,0xb6,0xea,0x80,0x3e,0x9d,0x36,0x0a,0x75,0x0f,0x26,0xa1,0x0c -,0x00,0x25,0x07,0x00,0x3d,0x04,0x00,0x75,0x03,0xe8,0x79,0x00,0xa1,0xf3,0x36,0x86 -,0xe0,0xe7,0x1e,0xa3,0xe3,0x36,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37 -,0x7b,0x7f,0x83,0x0e,0x0d,0x37,0x48,0xe8,0x1e,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07 -,0x00,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20,0x00,0x75,0x06,0xb8 -,0x01,0x00,0xe9,0x3f,0xe9,0xe9,0x5f,0xea,0xc7,0x06,0x41,0x37,0x00,0x00,0xb8,0x7f -,0x03,0xcd,0x3a,0xa1,0x1d,0x37,0xa3,0xc4,0x34,0x86,0xe0,0x68,0x7f,0x03,0x1f,0xa3 -,0x06,0x00,0x33,0xc0,0x8e,0xd8,0xa1,0x0b,0x37,0xa3,0xb2,0x34,0xa1,0x0d,0x37,0xa3 -,0xb4,0x34,0xa1,0xf3,0x36,0xa3,0xc8,0x34,0xa1,0xef,0x36,0xa3,0x9c,0x34,0xa1,0xf1 -,0x36,0xa3,0x9e,0x34,0xc3,0x80,0x0e,0x9d,0x36,0x80,0xbe,0x00,0x00,0xe8,0xb4,0x07 -,0xb8,0x7b,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00 -,0xa1,0xe5,0x36,0xe7,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xb8,0x82,0x03,0xcd,0x3a,0xf7 -,0x06,0x9b,0x36,0x00,0x20,0x75,0x03,0xe8,0xfd,0x06,0xa1,0xd3,0x36,0xa3,0xef,0x36 -,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3,0xf1,0x36,0xa3,0x9e,0x34,0xc3,0xf6,0x06,0x9d -,0x36,0x80,0x74,0x31,0xbe,0x22,0x00,0xe9,0x17,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74 -,0x24,0xbe,0x23,0x00,0xe9,0x0a,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x17,0xbe,0x24 -,0x00,0x56,0xe8,0xa8,0x05,0x8c,0xc0,0x3d,0xff,0xff,0x5e,0x74,0x05,0xe8,0xd7,0xef -,0xcd,0x50,0xe9,0x1f,0xe8,0xe9,0x9f,0xe9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x8a,0x03,0xcd,0x39,0xe9,0xf7,0x00,0x80,0x3e,0xa0 -,0x36,0x08,0x75,0x2e,0xa9,0xd0,0x07,0x75,0x2c,0xa1,0xb1,0x36,0x0d,0x00,0x04,0xe7 -,0x08,0xe5,0x00,0x25,0xff,0x73,0xe7,0x00,0xb8,0x8a,0x03,0xcd,0x3a,0xe8,0xc3,0x06 -,0x33,0xc0,0xe7,0x0e,0xe5,0x0a,0x25,0xc3,0x17,0xe7,0x0a,0xcd,0x54,0xc6,0x06,0xa0 -,0x36,0x00,0xe9,0x68,0xe9,0xbe,0x04,0x00,0xe9,0x3f,0xe9,0x83,0x26,0x9b,0x36,0xbf -,0xc6,0x06,0x71,0x37,0x03,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8 -,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x39,0x81,0x0e,0xc2,0x34,0x00,0x20,0xe9 -,0x92,0x00,0xe8,0x49,0x06,0xb8,0x87,0x03,0xcd,0x39,0xbb,0xff,0x7f,0xcd,0x53,0xb8 -,0x84,0x03,0xcd,0x3a,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x83 -,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xc3,0xe5,0x00 -,0x25,0xff,0x53,0xe7,0x00,0x83,0x0e,0xc2,0x34,0x40,0x83,0x26,0xc2,0x34,0xef,0xe8 -,0x0c,0x06,0xbb,0xff,0x7f,0xcd,0x53,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd -,0x3a,0xb8,0x86,0x03,0xcd,0x3a,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a -,0xb8,0x8b,0x03,0xcd,0x3a,0xb8,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xc3 -,0x83,0x0e,0xc2,0x34,0x50,0xe8,0x18,0x04,0xe8,0xd3,0x05,0xf6,0x06,0x6f,0x37,0x01 -,0x75,0x12,0xb8,0x89,0x03,0xcd,0x39,0x83,0x3e,0x0f,0x37,0x00,0x75,0x06,0xc7,0x06 -,0x0f,0x37,0x04,0x00,0xa1,0x9d,0x36,0x80,0xfc,0x08,0x74,0x05,0xb8,0x84,0x03,0xcd -,0x39,0xe5,0x02,0x0d,0x01,0x08,0x25,0xef,0xff,0xe7,0x02,0xa1,0x9d,0x36,0x86,0xe0 -,0x32,0xe4,0x8b,0xf0,0xd1,0xee,0x33,0xc0,0x0d,0x20,0x00,0x09,0x06,0xad,0x36,0xa1 -,0xad,0x36,0xe7,0x04,0xe9,0x53,0xe8,0xe9,0x5a,0xe8,0x33,0xc0,0xa0,0x1b,0x37,0xd1 -,0xe0,0x3a,0x06,0xa0,0x36,0x75,0x03,0xe9,0xba,0xff,0xe9,0x60,0xe8,0xc7,0x06,0x41 -,0x37,0x00,0x00,0xe8,0xc1,0xe1,0xe8,0x6a,0x06,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56 -,0xa1,0xb1,0x36,0x0d,0x00,0x10,0xe7,0x08,0xe5,0x02,0x25,0xf9,0xff,0x0d,0x03,0x00 -,0xe7,0x02,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1,0xad,0x36,0xe7 -,0x04,0xe8,0x7c,0x03,0xe8,0x9f,0x03,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b -,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x99,0x36,0xa3,0x9b -,0x36,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xa3,0x4c,0x37,0xa3,0xf3,0x36,0xa3,0xef,0x36 -,0xa3,0xf1,0x36,0xe8,0x82,0xfd,0xc6,0x06,0x9f,0x36,0x02,0xe9,0xef,0xe7,0xe5,0x02 -,0x0d,0x01,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xe8,0xf2 -,0x05,0xe5,0x0a,0x0d,0x40,0x00,0xe7,0x0a,0x33,0xc0,0xa3,0x81,0x37,0xa3,0x85,0x37 -,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xe5,0x00,0x0d,0x00,0x84,0xe7,0x00 -,0xb8,0x8c,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff -,0xe5,0x00,0x25,0xff,0x7b,0xe7,0x00,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x7e,0x03 -,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0xa7,0xed -,0x83,0x26,0xef,0x34,0xdf,0xff,0x06,0x81,0x37,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20 -,0xc3,0xf7,0x06,0x9a,0x37,0x80,0x00,0x74,0x3d,0xa9,0xd0,0x07,0x74,0x10,0xa9,0x00 -,0x04,0x74,0x12,0x33,0xc0,0xe7,0x0e,0xff,0x06,0x87,0x37,0xe9,0xd2,0xff,0xff,0x06 -,0x85,0x37,0xe9,0xcb,0xff,0xff,0x06,0x83,0x37,0xe9,0xc4,0xff,0x83,0x26,0x9a,0x37 -,0x7f,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f,0x01,0xc3,0xbb,0xff -,0x7f,0xcd,0x53,0xe9,0x00,0x00,0xe5,0x02,0x25,0xff,0xfb,0x25,0xef,0xff,0x0d,0x01 -,0x00,0xe7,0x02,0xa1,0x83,0x37,0x3b,0x06,0x46,0x37,0x7f,0x2a,0xa1,0x85,0x37,0x3b -,0x06,0x48,0x37,0x7c,0x21,0xa1,0x89,0x37,0x03,0x06,0x87,0x37,0x3d,0x05,0x00,0x7f -,0x15,0xc6,0x06,0x9f,0x36,0x04,0xe5,0x02,0x25,0xff,0xf7,0x0d,0x01,0x00,0x25,0xef -,0xff,0xe7,0x02,0xe9,0xf7,0xe6,0xbe,0x01,0x00,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74 -,0x0a,0x83,0x26,0x9b,0x36,0xfc,0x83,0x0e,0xc2,0x34,0x04,0xe9,0xd0,0xe6,0xb8,0x7b -,0x03,0xcd,0x39,0xe5,0x02,0x0d,0x01,0x60,0x25,0xef,0xff,0xe7,0x02,0xc7,0x06,0xf1 -,0x34,0x20,0x03,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0x81,0x26,0xc2,0x34,0x7f,0xff,0x80 -,0x0e,0x6f,0x37,0x01,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74,0xd2,0xb8,0x7b,0x03,0xcd -,0x3a,0xb8,0x7d,0x03,0xcd,0x39,0x83,0x26,0x9b,0x36,0xef,0x33,0xc0,0xb0,0x8a,0xa2 -,0x9f,0x36,0xa2,0x9d,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc7,0x06,0x0f,0x37,0x04 -,0x00,0xf7,0x06,0x9b,0x36,0x40,0x00,0x75,0x06,0xc7,0x06,0x0f,0x37,0x03,0x00,0xb8 -,0x8d,0x03,0xcd,0x39,0xe8,0x00,0xd5,0xe5,0x02,0x0d,0x01,0x40,0x25,0xef,0xff,0x8b -,0xd8,0xb8,0x7c,0x03,0xcd,0x39,0xc7,0x06,0x33,0x37,0x02,0x00,0x8b,0xc3,0x0d,0x00 -,0x20,0x25,0xf9,0xff,0x0b,0x06,0xe8,0x3a,0xe7,0x02,0xc3,0xff,0x0e,0xf1,0x34,0x75 -,0x01,0xc3,0xe5,0x4e,0xa9,0x01,0x00,0x75,0x12,0xe5,0x00,0xa9,0x00,0x04,0x75,0x05 -,0x0d,0x00,0x04,0xe7,0x00,0xb8,0x8e,0x03,0xcd,0x39,0xc3,0xe5,0x00,0xa9,0x00,0x04 -,0x74,0xf3,0x25,0xff,0xfb,0xe7,0x00,0xe9,0xeb,0xff,0xc6,0x06,0xa0,0x36,0x04,0x83 -,0x26,0x9b,0x36,0xfc,0x81,0x0e,0x9b,0x36,0x80,0x00,0xe9,0x10,0xe6,0xb8,0x8e,0x03 -,0xcd,0x3a,0xcd,0x54,0x81,0x0e,0xaf,0x36,0x00,0x18,0xa1,0xaf,0x36,0xe7,0x06,0xb8 -,0x7b,0x03,0xcd,0x39,0xa1,0xd3,0x36,0xa3,0x8f,0x37,0xa1,0xd5,0x36,0xa3,0x91,0x37 -,0xc7,0x06,0x8b,0x37,0x02,0x00,0xc7,0x06,0x8d,0x37,0x02,0x00,0x83,0x0e,0x99,0x36 -,0x40,0xe9,0xd9,0xe5,0x80,0x3e,0x9f,0x36,0x06,0x75,0x15,0xa9,0xd0,0x07,0x75,0xec -,0x25,0x00,0x18,0x75,0x0e,0xff,0x0e,0x8b,0x37,0x75,0xe1,0xc6,0x06,0x9f,0x36,0x08 -,0xe9,0xba,0xe5,0xff,0x0e,0x8d,0x37,0x75,0xd3,0xbe,0x08,0x00,0xe9,0x9f,0xe5,0xb8 -,0x7b,0x03,0xcd,0x39,0xf7,0x06,0x9b,0x36,0x00,0x20,0x74,0x08,0xc6,0x06,0x9f,0x36 -,0x0a,0xe9,0x0d,0x00,0xf7,0x06,0x9b,0x36,0x00,0x40,0x74,0x0b,0xb8,0x8b,0x03,0xcd -,0x39,0x81,0x0e,0x99,0x36,0x80,0x00,0xe9,0x83,0xe5,0xb8,0x7b,0x03,0xcd,0x39,0xc7 -,0x06,0x8b,0x37,0x04,0x00,0xc7,0x06,0x8d,0x37,0x04,0x00,0x81,0x0e,0x99,0x36,0x00 -,0x02,0xe9,0x69,0xe5,0xf6,0x06,0x9d,0x36,0x80,0x75,0x1b,0xa9,0xd0,0x07,0x75,0xeb -,0xa9,0x00,0x18,0x75,0x0c,0xff,0x0e,0x8d,0x37,0x75,0xe0,0xe8,0x17,0xfb,0xe9,0x4c -,0xe5,0xb8,0x82,0x03,0xcd,0x39,0xc3,0xff,0x0e,0x8b,0x37,0x75,0xce,0xbe,0x09,0x00 -,0xe9,0x2b,0xe5,0xc7,0x06,0x3d,0x37,0x00,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8 -,0x3c,0x02,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b -,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02 -,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x50,0x00 -,0xe8,0x73,0x00,0xb8,0x81,0x03,0xcd,0x39,0xc3,0xf7,0x06,0x9b,0x36,0x03,0x00,0x74 -,0x0d,0xc6,0x06,0x9f,0x36,0x02,0xc6,0x06,0xa0,0x36,0x00,0xe9,0xdf,0xe4,0x83,0x0e -,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xe7,0x02,0xe5,0x56,0x0d,0x02 -,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0x8b,0x36,0x3d,0x37,0xe8,0x44,0x02 -,0xc6,0x06,0xa0,0x36,0x0e,0xe9,0xb5,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x06,0xb8,0x8a,0x03,0xcd,0x3a,0xb8,0x85,0x03,0xcd,0x3a,0xb8,0x86,0x03,0xcd,0x3a -,0xb8,0x83,0x03,0xcd,0x3a,0xb8,0x87,0x03,0xcd,0x3a,0xb8,0x8b,0x03,0xcd,0x3a,0xb8 -,0x88,0x03,0xcd,0x3a,0x07,0xc3,0x06,0xb8,0x88,0x03,0xcd,0x3a,0xb8,0x7b,0x03,0xcd -,0x3a,0xb8,0x82,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x7c,0x03,0xcd,0x3a -,0xb8,0x7e,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0xb8,0x81,0x03,0xcd,0x3a,0xb8 -,0x84,0x03,0xcd,0x3a,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x7d,0x03,0xcd,0x3a,0xb8,0x8d -,0x03,0xcd,0x3a,0xc7,0x06,0x41,0x37,0x00,0x00,0x07,0xc3,0x06,0x8e,0x06,0x38,0x34 -,0x1f,0x8b,0x0e,0x0e,0x00,0x26,0x89,0x0e,0x0e,0x00,0xbe,0x18,0x00,0xbf,0x18,0x00 -,0xf3,0xa4,0x06,0x1e,0x07,0xcd,0x34,0x07,0x33,0xc0,0x8e,0xd8,0xc3,0x26,0xf6,0x06 -,0x20,0x00,0x80,0x74,0x44,0x33,0xc0,0x26,0xa0,0x26,0x00,0x24,0x1f,0x8b,0xf0,0x26 -,0x8b,0x5c,0x28,0x89,0x1e,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04 -,0x26,0x88,0x5c,0x28,0x8b,0xc6,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3 -,0xa4,0x8b,0xc8,0x83,0xc7,0x06,0xf3,0xa4,0x26,0x81,0x26,0x26,0x00,0x1f,0x80,0x26 -,0x81,0x36,0x26,0x00,0x00,0x80,0xe9,0xa9,0xff,0x26,0x8b,0x1e,0x28,0x00,0x89,0x1e -,0x6a,0x37,0x06,0x8e,0x06,0x38,0x34,0x1f,0xc0,0xe3,0x04,0x26,0x88,0x1e,0x28,0x00 -,0xb9,0x06,0x00,0xbe,0x20,0x00,0xbf,0x1a,0x00,0xf3,0xa4,0xe9,0x84,0xff,0x86,0xc4 -,0xa3,0x68,0x37,0xe8,0x87,0xff,0xf7,0x06,0x6a,0x37,0x0f,0x00,0x74,0x10,0x80,0x3e -,0x9e,0x36,0x00,0x75,0x09,0xbe,0x00,0x00,0xe8,0xac,0xe9,0xcd,0x50,0xc3,0xc3,0x50 -,0x56,0x06,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06,0x26,0xa0,0x26,0x00 -,0x24,0x1f,0x8b,0xf0,0x26,0x8b,0x5c,0x26,0x86,0xfb,0x83,0xeb,0x04,0x74,0x4f,0x83 -,0xc6,0x2a,0x8c,0xc0,0x8e,0xd8,0xb9,0x07,0x00,0x33,0xc0,0x8e,0xc0,0xbf,0x72,0x37 -,0xf3,0xab,0x33,0xc9,0x8a,0x0c,0x80,0xf9,0x00,0x75,0x03,0xe9,0x30,0x00,0x3b,0xd9 -,0x73,0x03,0xe9,0x29,0x00,0x2b,0xd9,0x8a,0x44,0x01,0x25,0x3f,0x00,0x74,0x19,0x3d -,0x0b,0x00,0x7d,0x14,0xd1,0xe0,0x8b,0xf8,0x2e,0x8b,0xbd,0x5c,0x49,0x8d,0x74,0x02 -,0x83,0xe9,0x02,0xf3,0xa4,0xe9,0x02,0x00,0x03,0xf1,0x23,0xdb,0x75,0xc4,0x33,0xc0 -,0x8e,0xd8,0x07,0x5e,0x58,0xc3,0x33,0xc0,0x26,0xf6,0x06,0x20,0x00,0x80,0x74,0x06 -,0x26,0xa0,0x26,0x00,0x24,0x1f,0xc3,0xe5,0x0a,0x25,0xc3,0xbf,0xe7,0x0a,0xb8,0x86 -,0x03,0xcd,0x39,0xb8,0x83,0x03,0xcd,0x39,0x81,0x26,0x9b,0x36,0x7c,0xdf,0xb8,0x85 -,0x03,0xcd,0x3a,0xe5,0x02,0x25,0xff,0xf3,0x0d,0x01,0x00,0x25,0xef,0xff,0xe7,0x02 -,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00,0xa1,0xe7,0x36,0x25,0xff,0xfe,0xa3,0xe7,0x36 -,0xe7,0x3e,0x83,0x26,0x99,0x36,0xcf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36 -,0xe7,0x06,0xc3,0xe5,0x02,0x0d,0x01,0x0c,0x25,0xef,0xff,0xe7,0x02,0xa1,0xe7,0x36 -,0x0d,0x00,0x01,0xe7,0x3e,0xa3,0xe7,0x36,0x81,0x0e,0x9b,0x36,0x00,0x20,0x83,0x0e -,0x99,0x36,0x20,0x81,0x26,0x9b,0x36,0x7c,0xbf,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1 -,0xaf,0x36,0xe7,0x06,0xb8,0x86,0x03,0xcd,0x39,0xb8,0x85,0x03,0xcd,0x39,0xb8,0x83 -,0x03,0xcd,0x3a,0xc3,0x0b,0xf6,0x75,0x49,0x06,0x8e,0x06,0x32,0x34,0x80,0x3e,0xe0 -,0x34,0x01,0x75,0x1b,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26,0xf7,0x06 -,0x0a,0x00,0x00,0x20,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x20,0x07,0xc3,0x80 -,0x3e,0xe3,0x34,0x01,0x75,0x19,0x26,0x89,0x36,0x06,0x00,0x8e,0x06,0x32,0x34,0x26 -,0xf7,0x06,0x0a,0x00,0x00,0x10,0x74,0x07,0x26,0x81,0x0e,0x08,0x00,0x00,0x10,0x07 -,0xc3,0xe9,0xb4,0xff,0x50,0x51,0x57,0x33,0xc0,0xb9,0x06,0x00,0x8e,0xc0,0xbf,0xd1 -,0x36,0xf3,0xae,0x5f,0x74,0x0c,0x26,0xf6,0x06,0x00,0x00,0xc0,0x75,0x04,0xf8,0x59 -,0x58,0xc3,0xf9,0xe9,0xf9,0xff,0x8b,0x05,0x0b,0x45,0x02,0x0b,0x45,0x04,0xc3,0x52 -,0x50,0xe5,0x06,0x25,0x1e,0x00,0x3d,0x1e,0x00,0x75,0xf6,0xb8,0x01,0x80,0xe7,0x5a -,0x58,0x5a,0xc3,0xe8,0xe9,0xff,0x50,0xe5,0x02,0x25,0xff,0x7f,0x0d,0x01,0x00,0x25 -,0xef,0xff,0xe7,0x02,0x0d,0x00,0x80,0xe7,0x02,0xa1,0xad,0x36,0xe7,0x04,0xa1,0xaf -,0x36,0xe7,0x06,0x58,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x2e,0x2b,0xce,0x41,0x10,0x42,0x7b,0x41,0x30,0x41,0xa2,0x41,0xaf,0x45,0x44,0x29 -,0xc7,0x2a,0xc7,0x2a,0x60,0x39,0xf4,0x3a,0x5c,0x3c,0x09,0x3d,0xb1,0x3d,0x34,0x3f -,0xc7,0x2a,0x3c,0x3f,0xc7,0x2a,0xc4,0x3f,0x16,0x40,0x16,0x40,0xed,0x40,0xfa,0x40 -,0x07,0x41,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xc7,0x2a,0xd6,0x52,0x00,0x00,0x01,0x37 -,0xe9,0x36,0xf3,0x36,0xef,0x36,0x1d,0x37,0x0d,0x37,0x0b,0x37,0x9c,0x37,0x03,0x37 -,0xfb,0x36,0x62,0x2d,0x40,0x06,0xd1,0x2d,0xf4,0x01,0xba,0x44,0x40,0x06,0x8c,0x43 -,0x64,0x00,0xe8,0x2c,0xc8,0x00,0xd8,0x2b,0x05,0x00,0xe9,0x45,0x50,0x00,0x97,0x45 -,0xfa,0x00,0xae,0x2d,0x04,0x01,0x6a,0x42,0x02,0x00,0xf6,0x2c,0xbc,0x02,0x93,0x2d -,0xdc,0x05,0x1d,0x2d,0x64,0x00,0xa1,0x2d,0x14,0x00,0xd7,0x3a,0x08,0x07,0x81,0x2d -,0x64,0x00,0xb3,0x3e,0x02,0x00,0x30,0x43,0x64,0x00,0xc5,0x2c,0xf4,0x01,0x8b,0x44 -,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x80,0x3e,0xfd,0x34,0x02,0x74,0x0c,0xe8,0x20,0x05,0xc7,0x06,0xa1,0x36,0x00,0x00 -,0xe9,0x9a,0xf8,0xff,0x06,0xc0,0x33,0xe8,0x10,0x05,0x8b,0x36,0x3d,0x37,0xe8,0x73 -,0xfe,0xc3,0xcd,0x34,0xe9,0xe8,0x05,0xc7,0x06,0xa3,0x36,0x00,0x00,0xc7,0x06,0x41 -,0x37,0x00,0x00,0xe8,0xed,0xfe,0x33,0xc0,0x0d,0x41,0x00,0xe7,0x56,0xa1,0xb1,0x36 -,0x0d,0x00,0x10,0xe7,0x08,0xa1,0xb3,0x36,0xe7,0x0a,0xa1,0xaf,0x36,0xe7,0x06,0xa1 -,0xad,0x36,0xe7,0x04,0xe8,0x2b,0x09,0xc7,0x06,0x1d,0x37,0x00,0xc8,0xc7,0x06,0x0b -,0x37,0x00,0x03,0xc7,0x06,0x0d,0x37,0x7b,0x7f,0x33,0xc0,0xa3,0x9b,0x36,0xa3,0x9d -,0x36,0xc7,0x06,0x4c,0x37,0x01,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x05,0x37 -,0x00,0x00,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xa3,0xf3 -,0x36,0xa3,0xef,0x36,0xa3,0xf1,0x36,0xe8,0xfe,0xf5,0xe5,0x02,0x25,0xf9,0xff,0x0d -,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02 -,0xb8,0x8f,0x03,0xcd,0x39,0xb8,0x80,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff -,0xa1,0xa9,0x36,0xa3,0xa7,0x36,0x0d,0x00,0xa4,0x0d,0x00,0x08,0xe7,0x00,0xa3,0xa9 -,0x36,0xc7,0x06,0xa3,0x36,0x01,0x00,0xc7,0x06,0xa5,0x36,0x0c,0x00,0x83,0x3e,0xa5 -,0x36,0x00,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9,0x13,0xff,0xff,0x0e,0xa5 -,0x36,0xbe,0x11,0x00,0xe8,0x22,0x05,0xb8,0x90,0x03,0xcd,0x39,0xc3,0x83,0x3e,0xa3 -,0x36,0x01,0x74,0xd9,0xc3,0xb8,0x90,0x03,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b -,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x01,0x74,0x03,0xe9,0xf0,0x04,0x3c -,0x0f,0x75,0x1e,0x81,0xfb,0x00,0x02,0x75,0x18,0x26,0xa1,0x20,0x00,0xa3,0x05,0x37 -,0x26,0xa1,0x22,0x00,0xa3,0x07,0x37,0x26,0xa1,0x24,0x00,0xa3,0x09,0x37,0xe9,0x09 -,0x00,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xb6,0xfe,0xc7,0x06,0xa3,0x36,0x02,0x00 -,0xc6,0x06,0x9e,0x36,0xff,0xe8,0xcb,0xfd,0xe8,0x1c,0xd9,0x33,0xc0,0xa3,0x85,0x37 -,0xa3,0x83,0x37,0xa3,0x87,0x37,0xa3,0x89,0x37,0xb8,0x91,0x03,0xcd,0x39,0xb8,0x80 -,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xe5,0x00,0x25,0xff,0x53,0xe7,0x00 -,0x81,0x0e,0x9a,0x37,0x80,0x00,0xb8,0x92,0x03,0xcd,0x39,0x33,0xc0,0xe7,0x0e,0xbe -,0x08,0x00,0x8e,0x06,0x38,0x34,0xe8,0x8e,0xe5,0x26,0xc7,0x06,0x04,0x00,0x7d,0x4b -,0x83,0x26,0xef,0x34,0xdf,0xcd,0x50,0x83,0x0e,0xef,0x34,0x20,0xc3,0xf7,0x06,0x9a -,0x37,0x80,0x00,0x74,0x32,0xa9,0xd0,0x07,0x74,0x0c,0xa9,0x00,0x04,0x74,0x0e,0x33 -,0xc0,0xe7,0x0e,0xe9,0xda,0xff,0xff,0x06,0x85,0x37,0xe9,0xd3,0xff,0xff,0x06,0x83 -,0x37,0xe9,0xcc,0xff,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0x36,0xfe,0x83,0x26,0x9a -,0x37,0x7f,0xbb,0xff,0x7f,0xcd,0x53,0xe5,0x00,0x0d,0x00,0xac,0xe7,0x00,0xe5,0x02 -,0x25,0xff,0xfb,0x25,0xef,0xff,0x25,0xff,0xf7,0x0d,0x01,0x00,0xe7,0x02,0xa1,0x83 -,0x37,0x3b,0x06,0x46,0x37,0x7f,0xcd,0xa1,0x85,0x37,0x3b,0x06,0x48,0x37,0x7c,0xc4 -,0xc7,0x06,0xa3,0x36,0x03,0x00,0xbe,0x13,0x00,0xe8,0xfd,0x03,0xb8,0x93,0x03,0xcd -,0x39,0xb8,0x94,0x03,0xcd,0x39,0xb8,0x96,0x03,0xcd,0x39,0xb8,0x95,0x03,0xcd,0x39 -,0xbe,0x06,0x00,0xe8,0xe3,0x03,0xe9,0xd6,0x03,0x83,0x3e,0xa3,0x36,0x03,0x74,0x01 -,0xc3,0xbe,0x13,0x00,0xe8,0xd2,0x03,0xb8,0x94,0x03,0xcd,0x39,0xc3,0xb8,0x94,0x03 -,0xcd,0x3a,0x26,0xa0,0x2b,0x00,0x26,0x8b,0x1e,0x2c,0x00,0xcd,0x34,0x83,0x3e,0xa3 -,0x36,0x03,0x74,0x03,0xe9,0xa8,0x03,0x3c,0x0d,0x75,0x3e,0x83,0xfb,0x00,0x75,0x39 -,0xe5,0x02,0x0d,0x00,0x20,0xe7,0x02,0xb8,0x93,0x03,0xcd,0x3a,0xc7,0x06,0xa3,0x36 -,0x04,0x00,0xbe,0x00,0x00,0xe8,0x0c,0xfc,0xc6,0x06,0x9d,0x36,0x80,0xc6,0x06,0x9e -,0x36,0x00,0xc7,0x06,0x33,0x37,0x02,0x00,0xb8,0x9a,0x03,0xcd,0x39,0xe8,0xfc,0x00 -,0xc7,0x06,0x4c,0x37,0x00,0x00,0xe9,0x66,0x03,0xc7,0x06,0x3d,0x37,0x08,0x00,0xe9 -,0x61,0xfd,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06,0x3d,0x37,0x05,0x00,0xe9 -,0x51,0xfd,0xe9,0x4a,0x03,0x83,0x3e,0xa3,0x36,0x04,0x74,0x12,0x83,0x3e,0xa3,0x36 -,0x05,0x74,0x0b,0xcd,0x34,0xc7,0x06,0x3d,0x37,0x07,0x00,0xe9,0x35,0xfd,0xc7,0x06 -,0xa3,0x36,0x06,0x00,0xc6,0x06,0x9e,0x36,0xff,0xb8,0x9a,0x03,0xcd,0x3a,0xb8,0x99 -,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03 -,0xcd,0x39,0xb8,0x9b,0x03,0xcd,0x39,0xe9,0x18,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36 -,0x04,0x77,0x18,0x83,0x3e,0xa3,0x36,0x03,0x75,0x08,0xf7,0x06,0x9b,0x36,0x00,0x01 -,0x75,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xe8,0xfc,0xe9,0xe1,0x02,0xcd,0x34 -,0x83,0x3e,0xa3,0x36,0x02,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00,0xe9,0xd3,0xfc -,0x83,0x3e,0xa3,0x36,0x04,0x77,0x05,0xb8,0x96,0x03,0xcd,0x39,0xe9,0xc0,0x02,0x83 -,0x3e,0xa3,0x36,0x03,0x75,0x10,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x50,0x3d,0x04 -,0x00,0x75,0x03,0xe8,0x36,0x00,0xa1,0xf3,0x36,0x86,0xe0,0xe7,0x1e,0xa3,0xe3,0x36 -,0x81,0x26,0x0b,0x37,0x00,0x03,0x81,0x26,0x0d,0x37,0x7b,0x7f,0x83,0x0e,0x0d,0x37 -,0x48,0xe8,0x14,0xf3,0x58,0x3d,0x04,0x00,0x74,0x09,0x26,0xf7,0x06,0x0c,0x00,0x20 -,0x00,0x75,0x06,0xb8,0x01,0x00,0xe9,0x7a,0x02,0xe9,0x86,0xfc,0xa1,0xe5,0x36,0xe7 -,0x2e,0xa1,0xe7,0x36,0xe7,0x3e,0xa1,0xd3,0x36,0xa3,0x9c,0x34,0xa1,0xd5,0x36,0xa3 -,0x9e,0x34,0xc3,0x26,0x80,0x3e,0x1c,0x00,0xff,0x75,0x2f,0x26,0x80,0x3e,0x1e,0x00 -,0xff,0x75,0x27,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00,0x75,0x1b,0xa1,0xd1,0x36,0x26 -,0xa3,0x1a,0x00,0xa1,0xd3,0x36,0x26,0xa3,0x1c,0x00,0xa1,0xd5,0x36,0x26,0xa3,0x1e -,0x00,0xb8,0x0a,0x80,0xe9,0x2c,0x02,0xe9,0x38,0xfc,0xff,0x06,0x90,0x34,0xbe,0x0a -,0x00,0xc6,0x06,0xb6,0x34,0x01,0xf6,0x06,0x9d,0x36,0x80,0x75,0x05,0x83,0x0e,0xc2 -,0x34,0x01,0xcd,0x34,0xe9,0x0c,0xfc,0x83,0x3e,0xa3,0x36,0x03,0x75,0x09,0xc7,0x06 -,0x3d,0x37,0x05,0x00,0xe9,0xfc,0xfb,0xe5,0x02,0x0d,0x03,0x00,0x0d,0x00,0x88,0x0d -,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x05,0x00,0xc6,0x06,0x9e -,0x36,0xff,0xbe,0x02,0x00,0xe8,0xe1,0x01,0xb8,0x89,0x03,0xcd,0x3a,0xb8,0x9a,0x03 -,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x39,0xb8,0x97,0x03,0xcd,0x39,0xb8,0x98,0x03,0xcd -,0x39,0xe9,0xbb,0x01,0x83,0x3e,0xa3,0x36,0x03,0x74,0x0a,0x83,0x3e,0xa3,0x36,0x04 -,0x74,0x03,0xe9,0xaa,0x01,0xbe,0x06,0x00,0xe8,0xae,0x01,0xb8,0x95,0x03,0xcd,0x39 -,0xe9,0x9c,0x01,0x83,0x3e,0xa3,0x36,0x05,0x74,0x03,0xe9,0x92,0x01,0xbe,0x02,0x00 -,0xe8,0x96,0x01,0xb8,0x99,0x03,0xcd,0x39,0xe9,0x84,0x01,0xc7,0x06,0x0f,0x37,0x05 -,0x00,0xe9,0x7b,0x01,0xe5,0x02,0x25,0xff,0xdf,0xe7,0x02,0xc7,0x06,0xa3,0x36,0x07 -,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xe9,0x65,0x01,0xe8,0xd5,0x04,0xc6,0x06,0x9d -,0x36,0x00,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc7,0x06 -,0xa8,0x02,0x00,0x00,0xc7,0x06,0x4c,0x37,0x01,0x00,0xe5,0x02,0x25,0xf9,0xff,0x0d -,0x03,0x00,0x0d,0x00,0x88,0x25,0xef,0xff,0x0d,0x00,0x40,0x0d,0x00,0x04,0xe7,0x02 -,0xe9,0x67,0xfc,0xb8,0x9a,0x03,0xcd,0x39,0xf7,0x06,0xf4,0x33,0x00,0x10,0x75,0x09 -,0xc7,0x06,0x33,0x37,0x02,0x00,0xe9,0x16,0x01,0xff,0x0e,0x33,0x37,0x74,0x03,0xe9 -,0x0d,0x01,0xff,0x06,0x8e,0x34,0x83,0x0e,0xc2,0x34,0x08,0xc7,0x06,0x3d,0x37,0x03 -,0x00,0xe9,0xff,0xfa,0xc3,0x52,0x50,0xba,0xe0,0x00,0xb8,0x00,0x10,0xef,0x58,0x5a -,0xc3,0xc7,0x06,0x3d,0x37,0x00,0x00,0xe9,0xe9,0xfa,0xfa,0xe8,0x54,0x04,0xb8,0x80 -,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xd8,0x2b,0xb8,0x7f,0x03,0x8e,0xc0,0x26 -,0xc7,0x06,0x04,0x00,0xe8,0x2c,0x33,0xc0,0x8e,0xc0,0xa1,0xa7,0x36,0xa3,0xa9,0x36 -,0xa1,0xa9,0x36,0xe7,0x00,0xa1,0xab,0x36,0xe7,0x02,0xc7,0x06,0x05,0x37,0x00,0x00 -,0xc7,0x06,0x07,0x37,0x00,0x00,0xc7,0x06,0x09,0x37,0x00,0x00,0xc6,0x06,0x9d,0x36 -,0x00,0xc6,0x06,0x9e,0x36,0xff,0xc7,0x06,0x9b,0x36,0x00,0x00,0xc7,0x06,0xa3,0x36 -,0x00,0x00,0xc7,0x06,0x0f,0x37,0x00,0x00,0xc7,0x06,0xa8,0x02,0x00,0x00,0xc7,0x06 -,0x4c,0x37,0x01,0x00,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0xbb -,0xff,0x7f,0xcd,0x53,0xe8,0x7c,0xf9,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xfb,0xc3 -,0x8d,0x3e,0xc0,0x53,0x8d,0x36,0xf0,0x38,0xb9,0x0e,0x00,0x8b,0x1e,0x30,0x34,0x89 -,0x5c,0x02,0x2e,0x8b,0x45,0x02,0x89,0x44,0x06,0x2e,0x8b,0x05,0x89,0x44,0x04,0x83 -,0xc7,0x04,0x83,0xc6,0x10,0xe2,0xe8,0xb8,0x80,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04 -,0x00,0xe2,0x51,0xb8,0x7f,0x03,0x8e,0xc0,0x26,0xc7,0x06,0x04,0x00,0xb2,0x52,0x33 -,0xc0,0x8e,0xc0,0xc7,0x06,0xa1,0x36,0x01,0x00,0xc7,0x06,0x0f,0x37,0x05,0x00,0xc3 -,0x33,0xff,0x8e,0x06,0xa6,0x02,0x8b,0x36,0xa4,0x02,0x2e,0xff,0xa4,0xa0,0x53,0xe8 -,0x8c,0xdb,0xc3,0xe8,0x48,0xf7,0xe9,0xf6,0xff,0x8e,0x06,0x38,0x34,0xe8,0x07,0xe1 -,0x26,0xc7,0x06,0x04,0x00,0xdf,0x4f,0xcd,0x50,0xc3,0x26,0xc7,0x06,0x0a,0x00,0x00 -,0x00,0x26,0xff,0x26,0x04,0x00,0xcd,0x34,0xe9,0xd4,0xff,0xa1,0xd1,0x36,0x26,0x39 -,0x06,0x1a,0x00,0x75,0x22,0xa1,0xd3,0x36,0x26,0x39,0x06,0x1c,0x00,0x75,0x18,0xa1 -,0xd5,0x36,0x26,0x39,0x06,0x1e,0x00,0x75,0x0e,0x26,0xf7,0x06,0x0c,0x00,0x40,0x00 -,0x74,0x05,0x83,0x0e,0x66,0x37,0x40,0x81,0x0e,0xaf,0x36,0x00,0x10,0xa1,0xaf,0x36 -,0xe7,0x06,0x83,0x3e,0xa3,0x36,0x02,0x75,0x05,0xcd,0x34,0xe9,0x56,0xfb,0x83,0x3e -,0xa3,0x36,0x00,0x74,0xb1,0x83,0x3e,0xa3,0x36,0x05,0x77,0xaa,0x26,0xf6,0x06,0x0a -,0x00,0xff,0x75,0xa2,0xe8,0xfd,0xdd,0x50,0xf6,0x06,0x93,0x36,0x20,0x75,0x03,0xe9 -,0x8c,0x00,0x26,0xa1,0x0c,0x00,0x25,0x07,0x00,0x3d,0x07,0x00,0x75,0x03,0xe9,0x76 -,0x00,0x3d,0x05,0x00,0x75,0x03,0xe9,0x6e,0x00,0xf7,0x06,0xe6,0x34,0x18,0x80,0x75 -,0x03,0xe9,0x6a,0x00,0xf7,0x06,0xe6,0x34,0x00,0x80,0x74,0x35,0x26,0x80,0x3e,0x29 -,0x00,0x02,0x75,0x2d,0x51,0x56,0x57,0x8d,0x36,0x3e,0x34,0x8d,0x3e,0x20,0x00,0xb9 -,0x06,0x00,0xf3,0xa6,0x5f,0x5e,0x59,0x75,0x45,0x26,0xa1,0x20,0x00,0xa3,0x3e,0x34 -,0x26,0xa1,0x22,0x00,0xa3,0x40,0x34,0x26,0xa1,0x24,0x00,0xa3,0x42,0x34,0xe9,0x26 -,0x00,0xf7,0x06,0xe6,0x34,0x08,0x00,0x74,0x0b,0x26,0x80,0x3e,0x19,0x00,0x00,0x74 -,0x03,0xe9,0x13,0x00,0xf7,0x06,0xe6,0x34,0x10,0x00,0x74,0x12,0x26,0xa0,0x28,0x00 -,0xc0,0xe8,0x04,0x22,0xc0,0x74,0x07,0x26,0xc7,0x06,0x04,0x00,0xff,0xff,0x58,0x23 -,0xc0,0x74,0x03,0xe9,0xdd,0xfe,0x81,0x26,0x9b,0x36,0xff,0xfe,0x26,0xa1,0x20,0x00 -,0x3b,0x06,0xd1,0x36,0x75,0x1a,0x26,0xa1,0x22,0x00,0x3b,0x06,0xd3,0x36,0x75,0x10 -,0x26,0xa1,0x24,0x00,0x3b,0x06,0xd5,0x36,0x75,0x06,0x81,0x0e,0x9b,0x36,0x00,0x01 -,0x26,0xa1,0x20,0x00,0x25,0x7f,0xff,0xa3,0xb8,0x34,0x26,0xa1,0x22,0x00,0xa3,0xba -,0x34,0x26,0xa1,0x24,0x00,0xa3,0xbc,0x34,0x8b,0xc6,0x86,0xc4,0xa3,0xc0,0x34,0xd1 -,0xe6,0x80,0xfc,0x09,0x74,0x03,0xe8,0xf6,0xf5,0xa1,0x05,0x37,0x0b,0x06,0x07,0x37 -,0x0b,0x06,0x09,0x37,0x74,0x3e,0x26,0xa1,0x20,0x00,0x3b,0x06,0x05,0x37,0x75,0x17 -,0x26,0xa1,0x22,0x00,0x3b,0x06,0x07,0x37,0x75,0x0d,0x26,0xa1,0x24,0x00,0x3b,0x06 -,0x09,0x37,0x75,0x03,0xe9,0x1d,0x00,0x26,0xa0,0x28,0x00,0x24,0x0f,0x3c,0x03,0x74 -,0x1b,0x3c,0x00,0x75,0x0f,0x83,0x3e,0xa3,0x36,0x04,0x74,0x10,0xf7,0x06,0x9b,0x36 -,0x00,0x01,0x74,0x08,0x2e,0xff,0x94,0xf8,0x53,0xe9,0x33,0xfe,0xcd,0x34,0xc7,0x06 -,0x3d,0x37,0x01,0x00,0xe9,0x2c,0xf8,0x83,0x3e,0xa3,0x36,0x05,0x74,0x10,0x83,0x3e -,0xa3,0x36,0x01,0x7e,0x09,0x83,0xee,0x16,0x2e,0xff,0x94,0x24,0x54,0xc3,0xcd,0x34 -,0xc3,0x26,0xa1,0x0c,0x00,0x3d,0xff,0x7f,0x74,0x05,0x26,0xff,0x26,0x04,0x00,0xe9 -,0xfd,0xfd,0xa1,0xf4,0x33,0xa9,0x00,0x88,0x74,0x0b,0xa9,0x00,0x10,0x75,0x09,0x8b -,0x1e,0x43,0x37,0xff,0xe3,0xe9,0x97,0x00,0xc7,0x06,0x35,0x37,0x05,0x00,0xc7,0x06 -,0x43,0x37,0x28,0x52,0xf7,0x06,0xf4,0x33,0x00,0x08,0x74,0x06,0xc7,0x06,0x43,0x37 -,0x1a,0x52,0xb8,0x80,0x03,0xcd,0x39,0xe9,0xc5,0xfd,0xa9,0x00,0x08,0x74,0xd9,0xff -,0x0e,0x35,0x37,0x75,0xed,0xe9,0x30,0x00,0xa9,0x00,0x08,0x75,0xcb,0xff,0x0e,0x35 -,0x37,0x75,0xdf,0x81,0x0e,0xc2,0x34,0xc0,0x00,0xf6,0x06,0x9d,0x36,0x80,0x74,0x0f -,0x81,0x0e,0x9b,0x36,0x00,0x80,0xc7,0x06,0x0f,0x37,0x02,0x00,0xe9,0x90,0xfd,0xc7 -,0x06,0x3d,0x37,0x02,0x00,0xe9,0x8b,0xf7,0x80,0x26,0x9e,0x36,0xff,0x75,0x30,0xf6 -,0x06,0x9d,0x36,0x80,0x74,0x20,0xff,0x06,0x94,0x34,0x83,0x0e,0x66,0x37,0x20,0x8e -,0x06,0x30,0x34,0x26,0xf7,0x06,0x0a,0x00,0x00,0x01,0x74,0x07,0x26,0x81,0x0e,0x08 -,0x00,0x00,0x01,0xe9,0x09,0x00,0xc7,0x06,0x3d,0x37,0x04,0x00,0xe9,0x54,0xf7,0x81 -,0x0e,0xaf,0x36,0x00,0x08,0xa1,0xaf,0x36,0xe7,0x06,0xe5,0x0a,0xa9,0x00,0x80,0x74 -,0x0e,0x81,0x26,0xaf,0x36,0xff,0xf7,0xa1,0xaf,0x36,0xe7,0x06,0xe9,0x49,0xff,0xe9 -,0x2d,0xfd,0xc7,0x06,0x41,0x37,0x00,0x00,0xbe,0x29,0x00,0xe8,0x2b,0xfd,0xe9,0x1e -,0xfd,0xcd,0x34,0x83,0x3e,0xa3,0x36,0x04,0x77,0x09,0xc7,0x06,0x3d,0x37,0x01,0x00 -,0xe9,0x10,0xf7,0xe9,0x09,0xfd,0xcd,0x34,0xc3,0xc7,0x06,0x9b,0x36,0x00,0x00,0xe8 -,0x0c,0xf5,0x81,0x26,0xaf,0x36,0xff,0xe7,0xa1,0xaf,0x36,0xe7,0x06,0x81,0x26,0x9b -,0x36,0xff,0x7f,0xe5,0x02,0x0d,0x01,0x00,0x25,0xef,0xff,0x25,0xff,0xdf,0xe7,0x02 -,0xbb,0xff,0x7f,0xcd,0x53,0x33,0xc0,0xa3,0x9d,0x36,0xa3,0x9f,0x36,0xe8,0x20,0xf3 -,0xe8,0x43,0xf3,0x83,0x0e,0x9b,0x36,0x10,0xc7,0x06,0x99,0x36,0x00,0x00,0xe8,0xd2 -,0xf5,0xe5,0x56,0x0d,0x02,0x00,0xe7,0x56,0xc7,0x06,0xa8,0x02,0x00,0x00,0xbe,0x00 -,0x00,0xe8,0x30,0xf5,0xc6,0x06,0xa0,0x36,0x0e,0xb8,0x9c,0x03,0xcd,0x39,0xb8,0x80 -,0x00,0xcd,0x35,0xc7,0x06,0xaa,0x02,0xff,0xff,0xc7,0x06,0xa1,0x36,0x01,0x00,0xe9 -,0xa5,0xf6,0x06,0xb8,0x8f,0x03,0xcd,0x3a,0xb8,0x90,0x03,0xcd,0x3a,0xb8,0x91,0x03 -,0xcd,0x3a,0xb8,0x92,0x03,0xcd,0x3a,0xb8,0x93,0x03,0xcd,0x3a,0xb8,0x94,0x03,0xcd -,0x3a,0xb8,0x95,0x03,0xcd,0x3a,0xb8,0x96,0x03,0xcd,0x3a,0xb8,0x97,0x03,0xcd,0x3a -,0xb8,0x98,0x03,0xcd,0x3a,0xb8,0x99,0x03,0xcd,0x3a,0xb8,0x9a,0x03,0xcd,0x3a,0xb8 -,0x9b,0x03,0xcd,0x3a,0xb8,0x7f,0x03,0xcd,0x3a,0xb8,0x80,0x03,0xcd,0x3a,0x07,0xc3 -,0xf7,0x49,0xf1,0x4e,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xf8,0x51,0xdf,0x4f -,0xfa,0x4f,0x0b,0x50,0xd1,0x51,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f,0xdf,0x4f -,0xe4,0x4e,0x06,0x00,0xcd,0x4a,0x04,0x00,0xe4,0x4e,0x19,0x00,0xad,0x4b,0xfa,0x00 -,0x82,0x4c,0x08,0x07,0x09,0x4c,0x14,0x00,0x24,0x4e,0x64,0x00,0xd7,0x4d,0xf4,0x01 -,0x64,0x4e,0xbc,0x02,0x7a,0x4e,0xe8,0x03,0x43,0x4e,0x02,0x00,0xb3,0x4e,0xf4,0x01 -,0x5b,0x4e,0xf4,0x01,0xe5,0x4e,0x14,0x00,0x06,0x50,0x06,0x50,0x95,0x4c,0xc1,0x52 -,0xc1,0x52,0xfe,0x4c,0xda,0x4c,0x06,0x50,0x06,0x50,0x06,0x50,0x06,0x50,0xb7,0x51 -,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0xb7,0x51,0x06,0x50,0xd5,0x4a,0x06,0x50 -,0x1d,0x4c,0x06,0x50,0x83,0x4d,0x1f,0x4d,0x1f,0x4d,0xed,0x40,0xfa,0x40,0x07,0x41 -,0x37,0x37,0x2e,0x37,0x37,0x20,0x20,0x79,0x79,0x2f,0x79,0x79,0x2f,0x79,0x79,0x20 -,0x30,0x31,0x2e,0x39,0x30,0x20,0x20,0x30,0x32,0x2f,0x31,0x37,0x2f,0x39,0x39,0x20 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -,0x90,0xea,0xc0,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x06 -} ; diff --git a/trunk/drivers/net/ucc_geth.c b/trunk/drivers/net/ucc_geth.c index 933fcfbf35e1..d3f39e86eb95 100644 --- a/trunk/drivers/net/ucc_geth.c +++ b/trunk/drivers/net/ucc_geth.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -223,10 +222,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT - 1))); - skb->dev = ugeth->dev; + skb->dev = ugeth->ndev; out_be32(&((struct qe_bd __iomem *)bd)->buf, - dma_map_single(&ugeth->dev->dev, + dma_map_single(ugeth->dev, skb->data, ugeth->ug_info->uf_info.max_rx_buf_length + UCC_GETH_RX_DATA_BUF_ALIGNMENT, @@ -1872,7 +1871,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) continue; for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { if (ugeth->tx_skbuff[i][j]) { - dma_unmap_single(&ugeth->dev->dev, + dma_unmap_single(ugeth->dev, in_be32(&((struct qe_bd __iomem *)bd)->buf), (in_be32((u32 __iomem *)bd) & BD_LENGTH_MASK), @@ -1900,7 +1899,7 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) bd = ugeth->p_rx_bd_ring[i]; for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) { if (ugeth->rx_skbuff[i][j]) { - dma_unmap_single(&ugeth->dev->dev, + dma_unmap_single(ugeth->dev, in_be32(&((struct qe_bd __iomem *)bd)->buf), ugeth->ug_info-> uf_info.max_rx_buf_length + @@ -3071,7 +3070,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) /* set up the buffer descriptor */ out_be32(&((struct qe_bd __iomem *)bd)->buf, - dma_map_single(&ugeth->dev->dev, skb->data, + dma_map_single(ugeth->dev, skb->data, skb->len, DMA_TO_DEVICE)); /* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */ @@ -3127,7 +3126,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit ugeth_vdbg("%s: IN", __func__); - dev = ugeth->dev; + dev = ugeth->ndev; /* collect received buffers */ bd = ugeth->rxBd[rxQ]; @@ -3161,7 +3160,7 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit skb_put(skb, length); /* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, ugeth->dev); + skb->protocol = eth_type_trans(skb, ugeth->ndev); dev->stats.rx_bytes += length; /* Send the packet up the stack */ @@ -3432,7 +3431,7 @@ static int ucc_geth_close(struct net_device *dev) ucc_geth_stop(ugeth); - free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); + free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev); netif_stop_queue(dev); @@ -3446,7 +3445,7 @@ static void ucc_geth_timeout_work(struct work_struct *work) struct net_device *dev; ugeth = container_of(work, struct ucc_geth_private, timeout_work); - dev = ugeth->dev; + dev = ugeth->ndev; ugeth_vdbg("%s: IN", __func__); @@ -3756,7 +3755,8 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma memcpy(dev->dev_addr, mac_addr, 6); ugeth->ug_info = ug_info; - ugeth->dev = dev; + ugeth->dev = device; + ugeth->ndev = dev; ugeth->node = np; return 0; diff --git a/trunk/drivers/net/ucc_geth.h b/trunk/drivers/net/ucc_geth.h index e3a25e64a652..2f8ee7c87efe 100644 --- a/trunk/drivers/net/ucc_geth.h +++ b/trunk/drivers/net/ucc_geth.h @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -1129,7 +1128,8 @@ struct ucc_geth_info { struct ucc_geth_private { struct ucc_geth_info *ug_info; struct ucc_fast_private *uccf; - struct net_device *dev; + struct device *dev; + struct net_device *ndev; struct napi_struct napi; struct work_struct timeout_work; struct ucc_geth __iomem *ug_regs; diff --git a/trunk/drivers/net/ucc_geth_ethtool.c b/trunk/drivers/net/ucc_geth_ethtool.c index a755bea559b9..6fcb500257bc 100644 --- a/trunk/drivers/net/ucc_geth_ethtool.c +++ b/trunk/drivers/net/ucc_geth_ethtool.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/net/usb/hso.c b/trunk/drivers/net/usb/hso.c index cde423c6d040..f84b78d94c40 100644 --- a/trunk/drivers/net/usb/hso.c +++ b/trunk/drivers/net/usb/hso.c @@ -5,6 +5,7 @@ * Copyright (C) 2008 Option International * Filip Aben * Denis Joseph Barrow + * Jan Dumon * Copyright (C) 2007 Andrew Bird (Sphere Systems Ltd) * * Copyright (C) 2008 Greg Kroah-Hartman @@ -462,9 +463,16 @@ static const struct usb_device_id hso_ids[] = { {USB_DEVICE(0x0af0, 0x7701)}, {USB_DEVICE(0x0af0, 0x7801)}, {USB_DEVICE(0x0af0, 0x7901)}, - {USB_DEVICE(0x0af0, 0x7361)}, - {USB_DEVICE(0x0af0, 0xd057)}, + {USB_DEVICE(0x0af0, 0x8200)}, + {USB_DEVICE(0x0af0, 0x8201)}, + {USB_DEVICE(0x0af0, 0xd035)}, {USB_DEVICE(0x0af0, 0xd055)}, + {USB_DEVICE(0x0af0, 0xd155)}, + {USB_DEVICE(0x0af0, 0xd255)}, + {USB_DEVICE(0x0af0, 0xd057)}, + {USB_DEVICE(0x0af0, 0xd157)}, + {USB_DEVICE(0x0af0, 0xd257)}, + {USB_DEVICE(0x0af0, 0xd357)}, {} }; MODULE_DEVICE_TABLE(usb, hso_ids); @@ -2410,20 +2418,22 @@ static void hso_free_net_device(struct hso_device *hso_dev) if (!hso_net) return; + remove_net_device(hso_net->parent); + + if (hso_net->net) { + unregister_netdev(hso_net->net); + free_netdev(hso_net->net); + } + /* start freeing */ for (i = 0; i < MUX_BULK_RX_BUF_COUNT; i++) { usb_free_urb(hso_net->mux_bulk_rx_urb_pool[i]); kfree(hso_net->mux_bulk_rx_buf_pool[i]); + hso_net->mux_bulk_rx_buf_pool[i] = NULL; } usb_free_urb(hso_net->mux_bulk_tx_urb); kfree(hso_net->mux_bulk_tx_buf); - - remove_net_device(hso_net->parent); - - if (hso_net->net) { - unregister_netdev(hso_net->net); - free_netdev(hso_net->net); - } + hso_net->mux_bulk_tx_buf = NULL; kfree(hso_dev); } @@ -2526,14 +2536,15 @@ static void hso_create_rfkill(struct hso_device *hso_dev, } /* Creates our network device */ -static struct hso_device *hso_create_net_device(struct usb_interface *interface) +static struct hso_device *hso_create_net_device(struct usb_interface *interface, + int port_spec) { int result, i; struct net_device *net; struct hso_net *hso_net; struct hso_device *hso_dev; - hso_dev = hso_create_device(interface, HSO_INTF_MUX | HSO_PORT_NETWORK); + hso_dev = hso_create_device(interface, port_spec); if (!hso_dev) return NULL; @@ -2613,12 +2624,12 @@ static void hso_free_tiomget(struct hso_serial *serial) { struct hso_tiocmget *tiocmget = serial->tiocmget; if (tiocmget) { - kfree(tiocmget); if (tiocmget->urb) { usb_free_urb(tiocmget->urb); tiocmget->urb = NULL; } serial->tiocmget = NULL; + kfree(tiocmget); } } @@ -2933,7 +2944,8 @@ static int hso_probe(struct usb_interface *interface, if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) { /* Create the network device */ if (!disable_net) { - hso_dev = hso_create_net_device(interface); + hso_dev = hso_create_net_device(interface, + port_spec); if (!hso_dev) goto exit; tmp_dev = hso_dev; @@ -2965,7 +2977,7 @@ static int hso_probe(struct usb_interface *interface, /* It's a regular bulk interface */ if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) && !disable_net) - hso_dev = hso_create_net_device(interface); + hso_dev = hso_create_net_device(interface, port_spec); else hso_dev = hso_create_bulk_serial_device(interface, port_spec); diff --git a/trunk/drivers/net/usb/kaweth.c b/trunk/drivers/net/usb/kaweth.c index 7cb10a0a5316..3d0d0b0b37c5 100644 --- a/trunk/drivers/net/usb/kaweth.c +++ b/trunk/drivers/net/usb/kaweth.c @@ -36,7 +36,6 @@ * Run test procedures * Fix bugs from previous two steps * Snoop other OSs for any tricks we're not doing - * SMP locking * Reduce arbitrary timeouts * Smart multicast support * Temporary MAC change support @@ -796,7 +795,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) int res; - spin_lock(&kaweth->device_lock); + spin_lock_irq(&kaweth->device_lock); kaweth_async_set_rx_mode(kaweth); netif_stop_queue(net); @@ -814,7 +813,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) if (!copied_skb) { kaweth->stats.tx_errors++; netif_start_queue(net); - spin_unlock(&kaweth->device_lock); + spin_unlock_irq(&kaweth->device_lock); return 0; } } @@ -848,7 +847,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) net->trans_start = jiffies; } - spin_unlock(&kaweth->device_lock); + spin_unlock_irq(&kaweth->device_lock); return 0; } diff --git a/trunk/drivers/net/vxge/Makefile b/trunk/drivers/net/vxge/Makefile new file mode 100644 index 000000000000..8992ca26b277 --- /dev/null +++ b/trunk/drivers/net/vxge/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for Neterion Inc's X3100 Series 10 GbE PCIe # I/O +# Virtualized Server Adapter linux driver + +obj-$(CONFIG_VXGE) += vxge.o + +vxge-objs := vxge-config.o vxge-traffic.o vxge-ethtool.o vxge-main.o diff --git a/trunk/drivers/net/vxge/vxge-config.c b/trunk/drivers/net/vxge/vxge-config.c new file mode 100644 index 000000000000..6b41c884a337 --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-config.c @@ -0,0 +1,5264 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-config.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#include +#include +#include +#include + +#include "vxge-traffic.h" +#include "vxge-config.h" + +/* + * __vxge_hw_channel_allocate - Allocate memory for channel + * This function allocates required memory for the channel and various arrays + * in the channel + */ +struct __vxge_hw_channel* +__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph, + enum __vxge_hw_channel_type type, + u32 length, u32 per_dtr_space, void *userdata) +{ + struct __vxge_hw_channel *channel; + struct __vxge_hw_device *hldev; + int size = 0; + u32 vp_id; + + hldev = vph->vpath->hldev; + vp_id = vph->vpath->vp_id; + + switch (type) { + case VXGE_HW_CHANNEL_TYPE_FIFO: + size = sizeof(struct __vxge_hw_fifo); + break; + case VXGE_HW_CHANNEL_TYPE_RING: + size = sizeof(struct __vxge_hw_ring); + break; + default: + break; + } + + channel = kzalloc(size, GFP_KERNEL); + if (channel == NULL) + goto exit0; + INIT_LIST_HEAD(&channel->item); + + channel->common_reg = hldev->common_reg; + channel->first_vp_id = hldev->first_vp_id; + channel->type = type; + channel->devh = hldev; + channel->vph = vph; + channel->userdata = userdata; + channel->per_dtr_space = per_dtr_space; + channel->length = length; + channel->vp_id = vp_id; + + channel->work_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + if (channel->work_arr == NULL) + goto exit1; + + channel->free_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + if (channel->free_arr == NULL) + goto exit1; + channel->free_ptr = length; + + channel->reserve_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + if (channel->reserve_arr == NULL) + goto exit1; + channel->reserve_ptr = length; + channel->reserve_top = 0; + + channel->orig_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + if (channel->orig_arr == NULL) + goto exit1; + + return channel; +exit1: + __vxge_hw_channel_free(channel); + +exit0: + return NULL; +} + +/* + * __vxge_hw_channel_free - Free memory allocated for channel + * This function deallocates memory from the channel and various arrays + * in the channel + */ +void __vxge_hw_channel_free(struct __vxge_hw_channel *channel) +{ + kfree(channel->work_arr); + kfree(channel->free_arr); + kfree(channel->reserve_arr); + kfree(channel->orig_arr); + kfree(channel); +} + +/* + * __vxge_hw_channel_initialize - Initialize a channel + * This function initializes a channel by properly setting the + * various references + */ +enum vxge_hw_status +__vxge_hw_channel_initialize(struct __vxge_hw_channel *channel) +{ + u32 i; + struct __vxge_hw_virtualpath *vpath; + + vpath = channel->vph->vpath; + + if ((channel->reserve_arr != NULL) && (channel->orig_arr != NULL)) { + for (i = 0; i < channel->length; i++) + channel->orig_arr[i] = channel->reserve_arr[i]; + } + + switch (channel->type) { + case VXGE_HW_CHANNEL_TYPE_FIFO: + vpath->fifoh = (struct __vxge_hw_fifo *)channel; + channel->stats = &((struct __vxge_hw_fifo *) + channel)->stats->common_stats; + break; + case VXGE_HW_CHANNEL_TYPE_RING: + vpath->ringh = (struct __vxge_hw_ring *)channel; + channel->stats = &((struct __vxge_hw_ring *) + channel)->stats->common_stats; + break; + default: + break; + } + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_channel_reset - Resets a channel + * This function resets a channel by properly setting the various references + */ +enum vxge_hw_status +__vxge_hw_channel_reset(struct __vxge_hw_channel *channel) +{ + u32 i; + + for (i = 0; i < channel->length; i++) { + if (channel->reserve_arr != NULL) + channel->reserve_arr[i] = channel->orig_arr[i]; + if (channel->free_arr != NULL) + channel->free_arr[i] = NULL; + if (channel->work_arr != NULL) + channel->work_arr[i] = NULL; + } + channel->free_ptr = channel->length; + channel->reserve_ptr = channel->length; + channel->reserve_top = 0; + channel->post_index = 0; + channel->compl_index = 0; + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_device_pci_e_init + * Initialize certain PCI/PCI-X configuration registers + * with recommended values. Save config space for future hw resets. + */ +void +__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev) +{ + u16 cmd = 0; + + /* Set the PErr Repconse bit and SERR in PCI command register. */ + pci_read_config_word(hldev->pdev, PCI_COMMAND, &cmd); + cmd |= 0x140; + pci_write_config_word(hldev->pdev, PCI_COMMAND, cmd); + + pci_save_state(hldev->pdev); + + return; +} + +/* + * __vxge_hw_device_register_poll + * Will poll certain register for specified amount of time. + * Will poll until masked bit is not cleared. + */ +enum vxge_hw_status +__vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis) +{ + u64 val64; + u32 i = 0; + enum vxge_hw_status ret = VXGE_HW_FAIL; + + udelay(10); + + do { + val64 = readq(reg); + if (!(val64 & mask)) + return VXGE_HW_OK; + udelay(100); + } while (++i <= 9); + + i = 0; + do { + val64 = readq(reg); + if (!(val64 & mask)) + return VXGE_HW_OK; + mdelay(1); + } while (++i <= max_millis); + + return ret; +} + + /* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset + * in progress + * This routine checks the vpath reset in progress register is turned zero + */ +enum vxge_hw_status +__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog) +{ + enum vxge_hw_status status; + status = __vxge_hw_device_register_poll(vpath_rst_in_prog, + VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(0x1ffff), + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + return status; +} + +/* + * __vxge_hw_device_toc_get + * This routine sets the swapper and reads the toc pointer and returns the + * memory mapped address of the toc + */ +struct vxge_hw_toc_reg __iomem * +__vxge_hw_device_toc_get(void __iomem *bar0) +{ + u64 val64; + struct vxge_hw_toc_reg __iomem *toc = NULL; + enum vxge_hw_status status; + + struct vxge_hw_legacy_reg __iomem *legacy_reg = + (struct vxge_hw_legacy_reg __iomem *)bar0; + + status = __vxge_hw_legacy_swapper_set(legacy_reg); + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&legacy_reg->toc_first_pointer); + toc = (struct vxge_hw_toc_reg __iomem *)(bar0+val64); +exit: + return toc; +} + +/* + * __vxge_hw_device_reg_addr_get + * This routine sets the swapper and reads the toc pointer and initializes the + * register location pointers in the device object. It waits until the ric is + * completed initializing registers. + */ +enum vxge_hw_status +__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev) +{ + u64 val64; + u32 i; + enum vxge_hw_status status = VXGE_HW_OK; + + hldev->legacy_reg = (struct vxge_hw_legacy_reg __iomem *)hldev->bar0; + + hldev->toc_reg = __vxge_hw_device_toc_get(hldev->bar0); + if (hldev->toc_reg == NULL) { + status = VXGE_HW_FAIL; + goto exit; + } + + val64 = readq(&hldev->toc_reg->toc_common_pointer); + hldev->common_reg = + (struct vxge_hw_common_reg __iomem *)(hldev->bar0 + val64); + + val64 = readq(&hldev->toc_reg->toc_mrpcim_pointer); + hldev->mrpcim_reg = + (struct vxge_hw_mrpcim_reg __iomem *)(hldev->bar0 + val64); + + for (i = 0; i < VXGE_HW_TITAN_SRPCIM_REG_SPACES; i++) { + val64 = readq(&hldev->toc_reg->toc_srpcim_pointer[i]); + hldev->srpcim_reg[i] = + (struct vxge_hw_srpcim_reg __iomem *) + (hldev->bar0 + val64); + } + + for (i = 0; i < VXGE_HW_TITAN_VPMGMT_REG_SPACES; i++) { + val64 = readq(&hldev->toc_reg->toc_vpmgmt_pointer[i]); + hldev->vpmgmt_reg[i] = + (struct vxge_hw_vpmgmt_reg __iomem *)(hldev->bar0 + val64); + } + + for (i = 0; i < VXGE_HW_TITAN_VPATH_REG_SPACES; i++) { + val64 = readq(&hldev->toc_reg->toc_vpath_pointer[i]); + hldev->vpath_reg[i] = + (struct vxge_hw_vpath_reg __iomem *) + (hldev->bar0 + val64); + } + + val64 = readq(&hldev->toc_reg->toc_kdfc); + + switch (VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val64)) { + case 0: + hldev->kdfc = (u8 __iomem *)(hldev->bar0 + + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); + break; + case 2: + hldev->kdfc = (u8 __iomem *)(hldev->bar1 + + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); + break; + case 4: + hldev->kdfc = (u8 __iomem *)(hldev->bar2 + + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); + break; + default: + break; + } + + status = __vxge_hw_device_vpath_reset_in_prog_check( + (u64 __iomem *)&hldev->common_reg->vpath_rst_in_prog); +exit: + return status; +} + +/* + * __vxge_hw_device_id_get + * This routine returns sets the device id and revision numbers into the device + * structure + */ +void __vxge_hw_device_id_get(struct __vxge_hw_device *hldev) +{ + u64 val64; + + val64 = readq(&hldev->common_reg->titan_asic_id); + hldev->device_id = + (u16)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(val64); + + hldev->major_revision = + (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(val64); + + hldev->minor_revision = + (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(val64); + + return; +} + +/* + * __vxge_hw_device_access_rights_get: Get Access Rights of the driver + * This routine returns the Access Rights of the driver + */ +static u32 +__vxge_hw_device_access_rights_get(u32 host_type, u32 func_id) +{ + u32 access_rights = VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH; + + switch (host_type) { + case VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION: + if (func_id == 0) { + access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM | + VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM; + } + break; + case VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION: + access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM | + VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM; + break; + case VXGE_HW_NO_MR_SR_VH0_FUNCTION0: + access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM | + VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM; + break; + case VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION: + case VXGE_HW_SR_VH_VIRTUAL_FUNCTION: + case VXGE_HW_MR_SR_VH0_INVALID_CONFIG: + break; + case VXGE_HW_SR_VH_FUNCTION0: + case VXGE_HW_VH_NORMAL_FUNCTION: + access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM; + break; + } + + return access_rights; +} +/* + * __vxge_hw_device_host_info_get + * This routine returns the host type assignments + */ +void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev) +{ + u64 val64; + u32 i; + + val64 = readq(&hldev->common_reg->host_type_assignments); + + hldev->host_type = + (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64); + + hldev->vpath_assignments = readq(&hldev->common_reg->vpath_assignments); + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpath_assignments & vxge_mBIT(i))) + continue; + + hldev->func_id = + __vxge_hw_vpath_func_id_get(i, hldev->vpmgmt_reg[i]); + + hldev->access_rights = __vxge_hw_device_access_rights_get( + hldev->host_type, hldev->func_id); + + hldev->first_vp_id = i; + break; + } + + return; +} + +/* + * __vxge_hw_verify_pci_e_info - Validate the pci-e link parameters such as + * link width and signalling rate. + */ +static enum vxge_hw_status +__vxge_hw_verify_pci_e_info(struct __vxge_hw_device *hldev) +{ + int exp_cap; + u16 lnk; + + /* Get the negotiated link width and speed from PCI config space */ + exp_cap = pci_find_capability(hldev->pdev, PCI_CAP_ID_EXP); + pci_read_config_word(hldev->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk); + + if ((lnk & PCI_EXP_LNKSTA_CLS) != 1) + return VXGE_HW_ERR_INVALID_PCI_INFO; + + switch ((lnk & PCI_EXP_LNKSTA_NLW) >> 4) { + case PCIE_LNK_WIDTH_RESRV: + case PCIE_LNK_X1: + case PCIE_LNK_X2: + case PCIE_LNK_X4: + case PCIE_LNK_X8: + break; + default: + return VXGE_HW_ERR_INVALID_PCI_INFO; + } + + return VXGE_HW_OK; +} + +static enum vxge_hw_status +__vxge_hw_device_is_privilaged(struct __vxge_hw_device *hldev) +{ + if ((hldev->host_type == VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION || + hldev->host_type == VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION || + hldev->host_type == VXGE_HW_NO_MR_SR_VH0_FUNCTION0) && + (hldev->func_id == 0)) + return VXGE_HW_OK; + else + return VXGE_HW_ERR_PRIVILAGED_OPEARATION; +} + +/* + * vxge_hw_wrr_rebalance - Rebalance the RX_WRR and KDFC_WRR calandars. + * Rebalance the RX_WRR and KDFC_WRR calandars. + */ +static enum +vxge_hw_status vxge_hw_wrr_rebalance(struct __vxge_hw_device *hldev) +{ + u64 val64; + u32 wrr_states[VXGE_HW_WEIGHTED_RR_SERVICE_STATES]; + u32 i, j, how_often = 1; + enum vxge_hw_status status = VXGE_HW_OK; + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + /* Reset the priorities assigned to the WRR arbitration + phases for the receive traffic */ + for (i = 0; i < VXGE_HW_WRR_RING_COUNT; i++) + writeq(0, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i)); + + /* Reset the transmit FIFO servicing calendar for FIFOs */ + for (i = 0; i < VXGE_HW_WRR_FIFO_COUNT; i++) { + writeq(0, ((&hldev->mrpcim_reg->kdfc_w_round_robin_0) + i)); + writeq(0, ((&hldev->mrpcim_reg->kdfc_w_round_robin_20) + i)); + } + + /* Assign WRR priority 0 for all FIFOs */ + for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(0), + ((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl) + i)); + + writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(0), + ((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i)); + } + + /* Reset to service non-offload doorbells */ + writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_0); + writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_1); + + /* Set priority 0 to all receive queues */ + writeq(0, &hldev->mrpcim_reg->rx_queue_priority_0); + writeq(0, &hldev->mrpcim_reg->rx_queue_priority_1); + writeq(0, &hldev->mrpcim_reg->rx_queue_priority_2); + + /* Initialize all the slots as unused */ + for (i = 0; i < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; i++) + wrr_states[i] = -1; + + /* Prepare the Fifo service states */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!hldev->config.vp_config[i].min_bandwidth) + continue; + + how_often = VXGE_HW_VPATH_BANDWIDTH_MAX / + hldev->config.vp_config[i].min_bandwidth; + if (how_often) { + + for (j = 0; j < VXGE_HW_WRR_FIFO_SERVICE_STATES;) { + if (wrr_states[j] == -1) { + wrr_states[j] = i; + /* Make sure each fifo is serviced + * atleast once */ + if (i == j) + j += VXGE_HW_MAX_VIRTUAL_PATHS; + else + j += how_often; + } else + j++; + } + } + } + + /* Fill the unused slots with 0 */ + for (j = 0; j < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; j++) { + if (wrr_states[j] == -1) + wrr_states[j] = 0; + } + + /* Assign WRR priority number for FIFOs */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(i), + ((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl) + i)); + + writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(i), + ((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i)); + } + + /* Modify the servicing algorithm applied to the 3 types of doorbells. + i.e, none-offload, message and offload */ + writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(1) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(0), + &hldev->mrpcim_reg->kdfc_entry_type_sel_0); + + writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(1), + &hldev->mrpcim_reg->kdfc_entry_type_sel_1); + + for (i = 0, j = 0; i < VXGE_HW_WRR_FIFO_COUNT; i++) { + + val64 = VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(wrr_states[j++]); + + writeq(val64, (&hldev->mrpcim_reg->kdfc_w_round_robin_0 + i)); + writeq(val64, (&hldev->mrpcim_reg->kdfc_w_round_robin_20 + i)); + } + + /* Set up the priorities assigned to receive queues */ + writeq(VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(0) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(1) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(2) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(3) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(4) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(5) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(6) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(7), + &hldev->mrpcim_reg->rx_queue_priority_0); + + writeq(VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(8) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(9) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(10) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(11) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(12) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(13) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(14) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(15), + &hldev->mrpcim_reg->rx_queue_priority_1); + + writeq(VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(16), + &hldev->mrpcim_reg->rx_queue_priority_2); + + /* Initialize all the slots as unused */ + for (i = 0; i < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; i++) + wrr_states[i] = -1; + + /* Prepare the Ring service states */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!hldev->config.vp_config[i].min_bandwidth) + continue; + + how_often = VXGE_HW_VPATH_BANDWIDTH_MAX / + hldev->config.vp_config[i].min_bandwidth; + + if (how_often) { + for (j = 0; j < VXGE_HW_WRR_RING_SERVICE_STATES;) { + if (wrr_states[j] == -1) { + wrr_states[j] = i; + /* Make sure each ring is + * serviced atleast once */ + if (i == j) + j += VXGE_HW_MAX_VIRTUAL_PATHS; + else + j += how_often; + } else + j++; + } + } + } + + /* Fill the unused slots with 0 */ + for (j = 0; j < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; j++) { + if (wrr_states[j] == -1) + wrr_states[j] = 0; + } + + for (i = 0, j = 0; i < VXGE_HW_WRR_RING_COUNT; i++) { + val64 = VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7( + wrr_states[j++]); + + writeq(val64, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i)); + } +exit: + return status; +} + +/* + * __vxge_hw_device_initialize + * Initialize Titan-V hardware. + */ +enum vxge_hw_status __vxge_hw_device_initialize(struct __vxge_hw_device *hldev) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + /* Validate the pci-e link width and speed */ + status = __vxge_hw_verify_pci_e_info(hldev); + if (status != VXGE_HW_OK) + goto exit; + + vxge_hw_wrr_rebalance(hldev); +exit: + return status; +} + +/** + * vxge_hw_device_hw_info_get - Get the hw information + * Returns the vpath mask that has the bits set for each vpath allocated + * for the driver, FW version information and the first mac addresse for + * each vpath + */ +enum vxge_hw_status __devinit +vxge_hw_device_hw_info_get(void __iomem *bar0, + struct vxge_hw_device_hw_info *hw_info) +{ + u32 i; + u64 val64; + struct vxge_hw_toc_reg __iomem *toc; + struct vxge_hw_mrpcim_reg __iomem *mrpcim_reg; + struct vxge_hw_common_reg __iomem *common_reg; + struct vxge_hw_vpath_reg __iomem *vpath_reg; + struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg; + enum vxge_hw_status status; + + memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info)); + + toc = __vxge_hw_device_toc_get(bar0); + if (toc == NULL) { + status = VXGE_HW_ERR_CRITICAL; + goto exit; + } + + val64 = readq(&toc->toc_common_pointer); + common_reg = (struct vxge_hw_common_reg __iomem *)(bar0 + val64); + + status = __vxge_hw_device_vpath_reset_in_prog_check( + (u64 __iomem *)&common_reg->vpath_rst_in_prog); + if (status != VXGE_HW_OK) + goto exit; + + hw_info->vpath_mask = readq(&common_reg->vpath_assignments); + + val64 = readq(&common_reg->host_type_assignments); + + hw_info->host_type = + (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64); + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!((hw_info->vpath_mask) & vxge_mBIT(i))) + continue; + + val64 = readq(&toc->toc_vpmgmt_pointer[i]); + + vpmgmt_reg = (struct vxge_hw_vpmgmt_reg __iomem *) + (bar0 + val64); + + hw_info->func_id = __vxge_hw_vpath_func_id_get(i, vpmgmt_reg); + if (__vxge_hw_device_access_rights_get(hw_info->host_type, + hw_info->func_id) & + VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) { + + val64 = readq(&toc->toc_mrpcim_pointer); + + mrpcim_reg = (struct vxge_hw_mrpcim_reg __iomem *) + (bar0 + val64); + + writeq(0, &mrpcim_reg->xgmac_gen_fw_memo_mask); + wmb(); + } + + val64 = readq(&toc->toc_vpath_pointer[i]); + + vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64); + + hw_info->function_mode = + __vxge_hw_vpath_pci_func_mode_get(i, vpath_reg); + + status = __vxge_hw_vpath_fw_ver_get(i, vpath_reg, hw_info); + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_card_info_get(i, vpath_reg, hw_info); + if (status != VXGE_HW_OK) + goto exit; + + break; + } + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!((hw_info->vpath_mask) & vxge_mBIT(i))) + continue; + + val64 = readq(&toc->toc_vpath_pointer[i]); + vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64); + + status = __vxge_hw_vpath_addr_get(i, vpath_reg, + hw_info->mac_addrs[i], + hw_info->mac_addr_masks[i]); + if (status != VXGE_HW_OK) + goto exit; + } +exit: + return status; +} + +/* + * vxge_hw_device_initialize - Initialize Titan device. + * Initialize Titan device. Note that all the arguments of this public API + * are 'IN', including @hldev. Driver cooperates with + * OS to find new Titan device, locate its PCI and memory spaces. + * + * When done, the driver allocates sizeof(struct __vxge_hw_device) bytes for HW + * to enable the latter to perform Titan hardware initialization. + */ +enum vxge_hw_status __devinit +vxge_hw_device_initialize( + struct __vxge_hw_device **devh, + struct vxge_hw_device_attr *attr, + struct vxge_hw_device_config *device_config) +{ + u32 i; + u32 nblocks = 0; + struct __vxge_hw_device *hldev = NULL; + enum vxge_hw_status status = VXGE_HW_OK; + + status = __vxge_hw_device_config_check(device_config); + if (status != VXGE_HW_OK) + goto exit; + + hldev = (struct __vxge_hw_device *) + vmalloc(sizeof(struct __vxge_hw_device)); + if (hldev == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + memset(hldev, 0, sizeof(struct __vxge_hw_device)); + hldev->magic = VXGE_HW_DEVICE_MAGIC; + + vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_ALL); + + /* apply config */ + memcpy(&hldev->config, device_config, + sizeof(struct vxge_hw_device_config)); + + hldev->bar0 = attr->bar0; + hldev->bar1 = attr->bar1; + hldev->bar2 = attr->bar2; + hldev->pdev = attr->pdev; + + hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up; + hldev->uld_callbacks.link_down = attr->uld_callbacks.link_down; + hldev->uld_callbacks.crit_err = attr->uld_callbacks.crit_err; + + __vxge_hw_device_pci_e_init(hldev); + + status = __vxge_hw_device_reg_addr_get(hldev); + if (status != VXGE_HW_OK) + goto exit; + __vxge_hw_device_id_get(hldev); + + __vxge_hw_device_host_info_get(hldev); + + /* Incrementing for stats blocks */ + nblocks++; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpath_assignments & vxge_mBIT(i))) + continue; + + if (device_config->vp_config[i].ring.enable == + VXGE_HW_RING_ENABLE) + nblocks += device_config->vp_config[i].ring.ring_blocks; + + if (device_config->vp_config[i].fifo.enable == + VXGE_HW_FIFO_ENABLE) + nblocks += device_config->vp_config[i].fifo.fifo_blocks; + nblocks++; + } + + if (__vxge_hw_blockpool_create(hldev, + &hldev->block_pool, + device_config->dma_blockpool_initial + nblocks, + device_config->dma_blockpool_max + nblocks) != VXGE_HW_OK) { + + vxge_hw_device_terminate(hldev); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + status = __vxge_hw_device_initialize(hldev); + + if (status != VXGE_HW_OK) { + vxge_hw_device_terminate(hldev); + goto exit; + } + + *devh = hldev; +exit: + return status; +} + +/* + * vxge_hw_device_terminate - Terminate Titan device. + * Terminate HW device. + */ +void +vxge_hw_device_terminate(struct __vxge_hw_device *hldev) +{ + vxge_assert(hldev->magic == VXGE_HW_DEVICE_MAGIC); + + hldev->magic = VXGE_HW_DEVICE_DEAD; + __vxge_hw_blockpool_destroy(&hldev->block_pool); + vfree(hldev); +} + +/* + * vxge_hw_device_stats_get - Get the device hw statistics. + * Returns the vpath h/w stats for the device. + */ +enum vxge_hw_status +vxge_hw_device_stats_get(struct __vxge_hw_device *hldev, + struct vxge_hw_device_stats_hw_info *hw_stats) +{ + u32 i; + enum vxge_hw_status status = VXGE_HW_OK; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpaths_deployed & vxge_mBIT(i)) || + (hldev->virtual_paths[i].vp_open == + VXGE_HW_VP_NOT_OPEN)) + continue; + + memcpy(hldev->virtual_paths[i].hw_stats_sav, + hldev->virtual_paths[i].hw_stats, + sizeof(struct vxge_hw_vpath_stats_hw_info)); + + status = __vxge_hw_vpath_stats_get( + &hldev->virtual_paths[i], + hldev->virtual_paths[i].hw_stats); + } + + memcpy(hw_stats, &hldev->stats.hw_dev_info_stats, + sizeof(struct vxge_hw_device_stats_hw_info)); + + return status; +} + +/* + * vxge_hw_driver_stats_get - Get the device sw statistics. + * Returns the vpath s/w stats for the device. + */ +enum vxge_hw_status vxge_hw_driver_stats_get( + struct __vxge_hw_device *hldev, + struct vxge_hw_device_stats_sw_info *sw_stats) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + memcpy(sw_stats, &hldev->stats.sw_dev_info_stats, + sizeof(struct vxge_hw_device_stats_sw_info)); + + return status; +} + +/* + * vxge_hw_mrpcim_stats_access - Access the statistics from the given location + * and offset and perform an operation + * Get the statistics from the given location and offset. + */ +enum vxge_hw_status +vxge_hw_mrpcim_stats_access(struct __vxge_hw_device *hldev, + u32 operation, u32 location, u32 offset, u64 *stat) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + val64 = VXGE_HW_XMAC_STATS_SYS_CMD_OP(operation) | + VXGE_HW_XMAC_STATS_SYS_CMD_STROBE | + VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(location) | + VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(offset); + + status = __vxge_hw_pio_mem_write64(val64, + &hldev->mrpcim_reg->xmac_stats_sys_cmd, + VXGE_HW_XMAC_STATS_SYS_CMD_STROBE, + hldev->config.device_poll_millis); + + if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ)) + *stat = readq(&hldev->mrpcim_reg->xmac_stats_sys_data); + else + *stat = 0; +exit: + return status; +} + +/* + * vxge_hw_device_xmac_aggr_stats_get - Get the Statistics on aggregate port + * Get the Statistics on aggregate port + */ +enum vxge_hw_status +vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *hldev, u32 port, + struct vxge_hw_xmac_aggr_stats *aggr_stats) +{ + u64 *val64; + int i; + u32 offset = VXGE_HW_STATS_AGGRn_OFFSET; + enum vxge_hw_status status = VXGE_HW_OK; + + val64 = (u64 *)aggr_stats; + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + for (i = 0; i < sizeof(struct vxge_hw_xmac_aggr_stats) / 8; i++) { + status = vxge_hw_mrpcim_stats_access(hldev, + VXGE_HW_STATS_OP_READ, + VXGE_HW_STATS_LOC_AGGR, + ((offset + (104 * port)) >> 3), val64); + if (status != VXGE_HW_OK) + goto exit; + + offset += 8; + val64++; + } +exit: + return status; +} + +/* + * vxge_hw_device_xmac_port_stats_get - Get the Statistics on a port + * Get the Statistics on port + */ +enum vxge_hw_status +vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *hldev, u32 port, + struct vxge_hw_xmac_port_stats *port_stats) +{ + u64 *val64; + enum vxge_hw_status status = VXGE_HW_OK; + int i; + u32 offset = 0x0; + val64 = (u64 *) port_stats; + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + for (i = 0; i < sizeof(struct vxge_hw_xmac_port_stats) / 8; i++) { + status = vxge_hw_mrpcim_stats_access(hldev, + VXGE_HW_STATS_OP_READ, + VXGE_HW_STATS_LOC_AGGR, + ((offset + (608 * port)) >> 3), val64); + if (status != VXGE_HW_OK) + goto exit; + + offset += 8; + val64++; + } + +exit: + return status; +} + +/* + * vxge_hw_device_xmac_stats_get - Get the XMAC Statistics + * Get the XMAC Statistics + */ +enum vxge_hw_status +vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *hldev, + struct vxge_hw_xmac_stats *xmac_stats) +{ + enum vxge_hw_status status = VXGE_HW_OK; + u32 i; + + status = vxge_hw_device_xmac_aggr_stats_get(hldev, + 0, &xmac_stats->aggr_stats[0]); + + if (status != VXGE_HW_OK) + goto exit; + + status = vxge_hw_device_xmac_aggr_stats_get(hldev, + 1, &xmac_stats->aggr_stats[1]); + if (status != VXGE_HW_OK) + goto exit; + + for (i = 0; i <= VXGE_HW_MAC_MAX_MAC_PORT_ID; i++) { + + status = vxge_hw_device_xmac_port_stats_get(hldev, + i, &xmac_stats->port_stats[i]); + if (status != VXGE_HW_OK) + goto exit; + } + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpaths_deployed & vxge_mBIT(i))) + continue; + + status = __vxge_hw_vpath_xmac_tx_stats_get( + &hldev->virtual_paths[i], + &xmac_stats->vpath_tx_stats[i]); + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_xmac_rx_stats_get( + &hldev->virtual_paths[i], + &xmac_stats->vpath_rx_stats[i]); + if (status != VXGE_HW_OK) + goto exit; + } +exit: + return status; +} + +/* + * vxge_hw_device_debug_set - Set the debug module, level and timestamp + * This routine is used to dynamically change the debug output + */ +void vxge_hw_device_debug_set(struct __vxge_hw_device *hldev, + enum vxge_debug_level level, u32 mask) +{ + if (hldev == NULL) + return; + +#if defined(VXGE_DEBUG_TRACE_MASK) || \ + defined(VXGE_DEBUG_ERR_MASK) + hldev->debug_module_mask = mask; + hldev->debug_level = level; +#endif + +#if defined(VXGE_DEBUG_ERR_MASK) + hldev->level_err = level & VXGE_ERR; +#endif + +#if defined(VXGE_DEBUG_TRACE_MASK) + hldev->level_trace = level & VXGE_TRACE; +#endif +} + +/* + * vxge_hw_device_error_level_get - Get the error level + * This routine returns the current error level set + */ +u32 vxge_hw_device_error_level_get(struct __vxge_hw_device *hldev) +{ +#if defined(VXGE_DEBUG_ERR_MASK) + if (hldev == NULL) + return VXGE_ERR; + else + return hldev->level_err; +#else + return 0; +#endif +} + +/* + * vxge_hw_device_trace_level_get - Get the trace level + * This routine returns the current trace level set + */ +u32 vxge_hw_device_trace_level_get(struct __vxge_hw_device *hldev) +{ +#if defined(VXGE_DEBUG_TRACE_MASK) + if (hldev == NULL) + return VXGE_TRACE; + else + return hldev->level_trace; +#else + return 0; +#endif +} +/* + * vxge_hw_device_debug_mask_get - Get the debug mask + * This routine returns the current debug mask set + */ +u32 vxge_hw_device_debug_mask_get(struct __vxge_hw_device *hldev) +{ +#if defined(VXGE_DEBUG_TRACE_MASK) || defined(VXGE_DEBUG_ERR_MASK) + if (hldev == NULL) + return 0; + return hldev->debug_module_mask; +#else + return 0; +#endif +} + +/* + * vxge_hw_getpause_data -Pause frame frame generation and reception. + * Returns the Pause frame generation and reception capability of the NIC. + */ +enum vxge_hw_status vxge_hw_device_getpause_data(struct __vxge_hw_device *hldev, + u32 port, u32 *tx, u32 *rx) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + + if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) { + status = VXGE_HW_ERR_INVALID_DEVICE; + goto exit; + } + + if (port > VXGE_HW_MAC_MAX_MAC_PORT_ID) { + status = VXGE_HW_ERR_INVALID_PORT; + goto exit; + } + + if (!(hldev->access_rights & VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) { + status = VXGE_HW_ERR_PRIVILAGED_OPEARATION; + goto exit; + } + + val64 = readq(&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]); + if (val64 & VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN) + *tx = 1; + if (val64 & VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN) + *rx = 1; +exit: + return status; +} + +/* + * vxge_hw_device_setpause_data - set/reset pause frame generation. + * It can be used to set or reset Pause frame generation or reception + * support of the NIC. + */ + +enum vxge_hw_status vxge_hw_device_setpause_data(struct __vxge_hw_device *hldev, + u32 port, u32 tx, u32 rx) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + + if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) { + status = VXGE_HW_ERR_INVALID_DEVICE; + goto exit; + } + + if (port > VXGE_HW_MAC_MAX_MAC_PORT_ID) { + status = VXGE_HW_ERR_INVALID_PORT; + goto exit; + } + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]); + if (tx) + val64 |= VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN; + else + val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN; + if (rx) + val64 |= VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN; + else + val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN; + + writeq(val64, &hldev->mrpcim_reg->rxmac_pause_cfg_port[port]); +exit: + return status; +} + +u16 vxge_hw_device_link_width_get(struct __vxge_hw_device *hldev) +{ + int link_width, exp_cap; + u16 lnk; + + exp_cap = pci_find_capability(hldev->pdev, PCI_CAP_ID_EXP); + pci_read_config_word(hldev->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk); + link_width = (lnk & VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH) >> 4; + return link_width; +} + +/* + * __vxge_hw_ring_block_memblock_idx - Return the memblock index + * This function returns the index of memory block + */ +static inline u32 +__vxge_hw_ring_block_memblock_idx(u8 *block) +{ + return (u32)*((u64 *)(block + VXGE_HW_RING_MEMBLOCK_IDX_OFFSET)); +} + +/* + * __vxge_hw_ring_block_memblock_idx_set - Sets the memblock index + * This function sets index to a memory block + */ +static inline void +__vxge_hw_ring_block_memblock_idx_set(u8 *block, u32 memblock_idx) +{ + *((u64 *)(block + VXGE_HW_RING_MEMBLOCK_IDX_OFFSET)) = memblock_idx; +} + +/* + * __vxge_hw_ring_block_next_pointer_set - Sets the next block pointer + * in RxD block + * Sets the next block pointer in RxD block + */ +static inline void +__vxge_hw_ring_block_next_pointer_set(u8 *block, dma_addr_t dma_next) +{ + *((u64 *)(block + VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET)) = dma_next; +} + +/* + * __vxge_hw_ring_first_block_address_get - Returns the dma address of the + * first block + * Returns the dma address of the first RxD block + */ +u64 __vxge_hw_ring_first_block_address_get(struct __vxge_hw_ring *ring) +{ + struct vxge_hw_mempool_dma *dma_object; + + dma_object = ring->mempool->memblocks_dma_arr; + vxge_assert(dma_object != NULL); + + return dma_object->addr; +} + +/* + * __vxge_hw_ring_item_dma_addr - Return the dma address of an item + * This function returns the dma address of a given item + */ +static dma_addr_t __vxge_hw_ring_item_dma_addr(struct vxge_hw_mempool *mempoolh, + void *item) +{ + u32 memblock_idx; + void *memblock; + struct vxge_hw_mempool_dma *memblock_dma_object; + ptrdiff_t dma_item_offset; + + /* get owner memblock index */ + memblock_idx = __vxge_hw_ring_block_memblock_idx(item); + + /* get owner memblock by memblock index */ + memblock = mempoolh->memblocks_arr[memblock_idx]; + + /* get memblock DMA object by memblock index */ + memblock_dma_object = mempoolh->memblocks_dma_arr + memblock_idx; + + /* calculate offset in the memblock of this item */ + dma_item_offset = (u8 *)item - (u8 *)memblock; + + return memblock_dma_object->addr + dma_item_offset; +} + +/* + * __vxge_hw_ring_rxdblock_link - Link the RxD blocks + * This function returns the dma address of a given item + */ +static void __vxge_hw_ring_rxdblock_link(struct vxge_hw_mempool *mempoolh, + struct __vxge_hw_ring *ring, u32 from, + u32 to) +{ + u8 *to_item , *from_item; + dma_addr_t to_dma; + + /* get "from" RxD block */ + from_item = mempoolh->items_arr[from]; + vxge_assert(from_item); + + /* get "to" RxD block */ + to_item = mempoolh->items_arr[to]; + vxge_assert(to_item); + + /* return address of the beginning of previous RxD block */ + to_dma = __vxge_hw_ring_item_dma_addr(mempoolh, to_item); + + /* set next pointer for this RxD block to point on + * previous item's DMA start address */ + __vxge_hw_ring_block_next_pointer_set(from_item, to_dma); +} + +/* + * __vxge_hw_ring_mempool_item_alloc - Allocate List blocks for RxD + * block callback + * This function is callback passed to __vxge_hw_mempool_create to create memory + * pool for RxD block + */ +static void +__vxge_hw_ring_mempool_item_alloc(struct vxge_hw_mempool *mempoolh, + u32 memblock_index, + struct vxge_hw_mempool_dma *dma_object, + u32 index, u32 is_last) +{ + u32 i; + void *item = mempoolh->items_arr[index]; + struct __vxge_hw_ring *ring = + (struct __vxge_hw_ring *)mempoolh->userdata; + + /* format rxds array */ + for (i = 0; i < ring->rxds_per_block; i++) { + void *rxdblock_priv; + void *uld_priv; + struct vxge_hw_ring_rxd_1 *rxdp; + + u32 reserve_index = ring->channel.reserve_ptr - + (index * ring->rxds_per_block + i + 1); + u32 memblock_item_idx; + + ring->channel.reserve_arr[reserve_index] = ((u8 *)item) + + i * ring->rxd_size; + + /* Note: memblock_item_idx is index of the item within + * the memblock. For instance, in case of three RxD-blocks + * per memblock this value can be 0, 1 or 2. */ + rxdblock_priv = __vxge_hw_mempool_item_priv(mempoolh, + memblock_index, item, + &memblock_item_idx); + + rxdp = (struct vxge_hw_ring_rxd_1 *) + ring->channel.reserve_arr[reserve_index]; + + uld_priv = ((u8 *)rxdblock_priv + ring->rxd_priv_size * i); + + /* pre-format Host_Control */ + rxdp->host_control = (u64)(size_t)uld_priv; + } + + __vxge_hw_ring_block_memblock_idx_set(item, memblock_index); + + if (is_last) { + /* link last one with first one */ + __vxge_hw_ring_rxdblock_link(mempoolh, ring, index, 0); + } + + if (index > 0) { + /* link this RxD block with previous one */ + __vxge_hw_ring_rxdblock_link(mempoolh, ring, index - 1, index); + } + + return; +} + +/* + * __vxge_hw_ring_initial_replenish - Initial replenish of RxDs + * This function replenishes the RxDs from reserve array to work array + */ +enum vxge_hw_status +vxge_hw_ring_replenish(struct __vxge_hw_ring *ring, u16 min_flag) +{ + void *rxd; + int i = 0; + struct __vxge_hw_channel *channel; + enum vxge_hw_status status = VXGE_HW_OK; + + channel = &ring->channel; + + while (vxge_hw_channel_dtr_count(channel) > 0) { + + status = vxge_hw_ring_rxd_reserve(ring, &rxd); + + vxge_assert(status == VXGE_HW_OK); + + if (ring->rxd_init) { + status = ring->rxd_init(rxd, channel->userdata); + if (status != VXGE_HW_OK) { + vxge_hw_ring_rxd_free(ring, rxd); + goto exit; + } + } + + vxge_hw_ring_rxd_post(ring, rxd); + if (min_flag) { + i++; + if (i == VXGE_HW_RING_MIN_BUFF_ALLOCATION) + break; + } + } + status = VXGE_HW_OK; +exit: + return status; +} + +/* + * __vxge_hw_ring_create - Create a Ring + * This function creates Ring and initializes it. + * + */ +enum vxge_hw_status +__vxge_hw_ring_create(struct __vxge_hw_vpath_handle *vp, + struct vxge_hw_ring_attr *attr) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_ring *ring; + u32 ring_length; + struct vxge_hw_ring_config *config; + struct __vxge_hw_device *hldev; + u32 vp_id; + struct vxge_hw_mempool_cbs ring_mp_callback; + + if ((vp == NULL) || (attr == NULL)) { + status = VXGE_HW_FAIL; + goto exit; + } + + hldev = vp->vpath->hldev; + vp_id = vp->vpath->vp_id; + + config = &hldev->config.vp_config[vp_id].ring; + + ring_length = config->ring_blocks * + vxge_hw_ring_rxds_per_block_get(config->buffer_mode); + + ring = (struct __vxge_hw_ring *)__vxge_hw_channel_allocate(vp, + VXGE_HW_CHANNEL_TYPE_RING, + ring_length, + attr->per_rxd_space, + attr->userdata); + + if (ring == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + vp->vpath->ringh = ring; + ring->vp_id = vp_id; + ring->vp_reg = vp->vpath->vp_reg; + ring->common_reg = hldev->common_reg; + ring->stats = &vp->vpath->sw_stats->ring_stats; + ring->config = config; + ring->callback = attr->callback; + ring->rxd_init = attr->rxd_init; + ring->rxd_term = attr->rxd_term; + ring->buffer_mode = config->buffer_mode; + ring->rxds_limit = config->rxds_limit; + + ring->rxd_size = vxge_hw_ring_rxd_size_get(config->buffer_mode); + ring->rxd_priv_size = + sizeof(struct __vxge_hw_ring_rxd_priv) + attr->per_rxd_space; + ring->per_rxd_space = attr->per_rxd_space; + + ring->rxd_priv_size = + ((ring->rxd_priv_size + VXGE_CACHE_LINE_SIZE - 1) / + VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE; + + /* how many RxDs can fit into one block. Depends on configured + * buffer_mode. */ + ring->rxds_per_block = + vxge_hw_ring_rxds_per_block_get(config->buffer_mode); + + /* calculate actual RxD block private size */ + ring->rxdblock_priv_size = ring->rxd_priv_size * ring->rxds_per_block; + ring_mp_callback.item_func_alloc = __vxge_hw_ring_mempool_item_alloc; + ring->mempool = __vxge_hw_mempool_create(hldev, + VXGE_HW_BLOCK_SIZE, + VXGE_HW_BLOCK_SIZE, + ring->rxdblock_priv_size, + ring->config->ring_blocks, + ring->config->ring_blocks, + &ring_mp_callback, + ring); + + if (ring->mempool == NULL) { + __vxge_hw_ring_delete(vp); + return VXGE_HW_ERR_OUT_OF_MEMORY; + } + + status = __vxge_hw_channel_initialize(&ring->channel); + if (status != VXGE_HW_OK) { + __vxge_hw_ring_delete(vp); + goto exit; + } + + /* Note: + * Specifying rxd_init callback means two things: + * 1) rxds need to be initialized by driver at channel-open time; + * 2) rxds need to be posted at channel-open time + * (that's what the initial_replenish() below does) + * Currently we don't have a case when the 1) is done without the 2). + */ + if (ring->rxd_init) { + status = vxge_hw_ring_replenish(ring, 1); + if (status != VXGE_HW_OK) { + __vxge_hw_ring_delete(vp); + goto exit; + } + } + + /* initial replenish will increment the counter in its post() routine, + * we have to reset it */ + ring->stats->common_stats.usage_cnt = 0; +exit: + return status; +} + +/* + * __vxge_hw_ring_abort - Returns the RxD + * This function terminates the RxDs of ring + */ +enum vxge_hw_status __vxge_hw_ring_abort(struct __vxge_hw_ring *ring) +{ + void *rxdh; + struct __vxge_hw_channel *channel; + + channel = &ring->channel; + + for (;;) { + vxge_hw_channel_dtr_try_complete(channel, &rxdh); + + if (rxdh == NULL) + break; + + vxge_hw_channel_dtr_complete(channel); + + if (ring->rxd_term) + ring->rxd_term(rxdh, VXGE_HW_RXD_STATE_POSTED, + channel->userdata); + + vxge_hw_channel_dtr_free(channel, rxdh); + } + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_ring_reset - Resets the ring + * This function resets the ring during vpath reset operation + */ +enum vxge_hw_status __vxge_hw_ring_reset(struct __vxge_hw_ring *ring) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_channel *channel; + + channel = &ring->channel; + + __vxge_hw_ring_abort(ring); + + status = __vxge_hw_channel_reset(channel); + + if (status != VXGE_HW_OK) + goto exit; + + if (ring->rxd_init) { + status = vxge_hw_ring_replenish(ring, 1); + if (status != VXGE_HW_OK) + goto exit; + } +exit: + return status; +} + +/* + * __vxge_hw_ring_delete - Removes the ring + * This function freeup the memory pool and removes the ring + */ +enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_vpath_handle *vp) +{ + struct __vxge_hw_ring *ring = vp->vpath->ringh; + + __vxge_hw_ring_abort(ring); + + if (ring->mempool) + __vxge_hw_mempool_destroy(ring->mempool); + + vp->vpath->ringh = NULL; + __vxge_hw_channel_free(&ring->channel); + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_mempool_grow + * Will resize mempool up to %num_allocate value. + */ +enum vxge_hw_status +__vxge_hw_mempool_grow(struct vxge_hw_mempool *mempool, u32 num_allocate, + u32 *num_allocated) +{ + u32 i, first_time = mempool->memblocks_allocated == 0 ? 1 : 0; + u32 n_items = mempool->items_per_memblock; + u32 start_block_idx = mempool->memblocks_allocated; + u32 end_block_idx = mempool->memblocks_allocated + num_allocate; + enum vxge_hw_status status = VXGE_HW_OK; + + *num_allocated = 0; + + if (end_block_idx > mempool->memblocks_max) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + for (i = start_block_idx; i < end_block_idx; i++) { + u32 j; + u32 is_last = ((end_block_idx - 1) == i); + struct vxge_hw_mempool_dma *dma_object = + mempool->memblocks_dma_arr + i; + void *the_memblock; + + /* allocate memblock's private part. Each DMA memblock + * has a space allocated for item's private usage upon + * mempool's user request. Each time mempool grows, it will + * allocate new memblock and its private part at once. + * This helps to minimize memory usage a lot. */ + mempool->memblocks_priv_arr[i] = + vmalloc(mempool->items_priv_size * n_items); + if (mempool->memblocks_priv_arr[i] == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + memset(mempool->memblocks_priv_arr[i], 0, + mempool->items_priv_size * n_items); + + /* allocate DMA-capable memblock */ + mempool->memblocks_arr[i] = + __vxge_hw_blockpool_malloc(mempool->devh, + mempool->memblock_size, dma_object); + if (mempool->memblocks_arr[i] == NULL) { + vfree(mempool->memblocks_priv_arr[i]); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + (*num_allocated)++; + mempool->memblocks_allocated++; + + memset(mempool->memblocks_arr[i], 0, mempool->memblock_size); + + the_memblock = mempool->memblocks_arr[i]; + + /* fill the items hash array */ + for (j = 0; j < n_items; j++) { + u32 index = i * n_items + j; + + if (first_time && index >= mempool->items_initial) + break; + + mempool->items_arr[index] = + ((char *)the_memblock + j*mempool->item_size); + + /* let caller to do more job on each item */ + if (mempool->item_func_alloc != NULL) + mempool->item_func_alloc(mempool, i, + dma_object, index, is_last); + + mempool->items_current = index + 1; + } + + if (first_time && mempool->items_current == + mempool->items_initial) + break; + } +exit: + return status; +} + +/* + * vxge_hw_mempool_create + * This function will create memory pool object. Pool may grow but will + * never shrink. Pool consists of number of dynamically allocated blocks + * with size enough to hold %items_initial number of items. Memory is + * DMA-able but client must map/unmap before interoperating with the device. + */ +struct vxge_hw_mempool* +__vxge_hw_mempool_create( + struct __vxge_hw_device *devh, + u32 memblock_size, + u32 item_size, + u32 items_priv_size, + u32 items_initial, + u32 items_max, + struct vxge_hw_mempool_cbs *mp_callback, + void *userdata) +{ + enum vxge_hw_status status = VXGE_HW_OK; + u32 memblocks_to_allocate; + struct vxge_hw_mempool *mempool = NULL; + u32 allocated; + + if (memblock_size < item_size) { + status = VXGE_HW_FAIL; + goto exit; + } + + mempool = (struct vxge_hw_mempool *) + vmalloc(sizeof(struct vxge_hw_mempool)); + if (mempool == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + memset(mempool, 0, sizeof(struct vxge_hw_mempool)); + + mempool->devh = devh; + mempool->memblock_size = memblock_size; + mempool->items_max = items_max; + mempool->items_initial = items_initial; + mempool->item_size = item_size; + mempool->items_priv_size = items_priv_size; + mempool->item_func_alloc = mp_callback->item_func_alloc; + mempool->userdata = userdata; + + mempool->memblocks_allocated = 0; + + mempool->items_per_memblock = memblock_size / item_size; + + mempool->memblocks_max = (items_max + mempool->items_per_memblock - 1) / + mempool->items_per_memblock; + + /* allocate array of memblocks */ + mempool->memblocks_arr = + (void **) vmalloc(sizeof(void *) * mempool->memblocks_max); + if (mempool->memblocks_arr == NULL) { + __vxge_hw_mempool_destroy(mempool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + mempool = NULL; + goto exit; + } + memset(mempool->memblocks_arr, 0, + sizeof(void *) * mempool->memblocks_max); + + /* allocate array of private parts of items per memblocks */ + mempool->memblocks_priv_arr = + (void **) vmalloc(sizeof(void *) * mempool->memblocks_max); + if (mempool->memblocks_priv_arr == NULL) { + __vxge_hw_mempool_destroy(mempool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + mempool = NULL; + goto exit; + } + memset(mempool->memblocks_priv_arr, 0, + sizeof(void *) * mempool->memblocks_max); + + /* allocate array of memblocks DMA objects */ + mempool->memblocks_dma_arr = (struct vxge_hw_mempool_dma *) + vmalloc(sizeof(struct vxge_hw_mempool_dma) * + mempool->memblocks_max); + + if (mempool->memblocks_dma_arr == NULL) { + __vxge_hw_mempool_destroy(mempool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + mempool = NULL; + goto exit; + } + memset(mempool->memblocks_dma_arr, 0, + sizeof(struct vxge_hw_mempool_dma) * + mempool->memblocks_max); + + /* allocate hash array of items */ + mempool->items_arr = + (void **) vmalloc(sizeof(void *) * mempool->items_max); + if (mempool->items_arr == NULL) { + __vxge_hw_mempool_destroy(mempool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + mempool = NULL; + goto exit; + } + memset(mempool->items_arr, 0, sizeof(void *) * mempool->items_max); + + /* calculate initial number of memblocks */ + memblocks_to_allocate = (mempool->items_initial + + mempool->items_per_memblock - 1) / + mempool->items_per_memblock; + + /* pre-allocate the mempool */ + status = __vxge_hw_mempool_grow(mempool, memblocks_to_allocate, + &allocated); + if (status != VXGE_HW_OK) { + __vxge_hw_mempool_destroy(mempool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + mempool = NULL; + goto exit; + } + +exit: + return mempool; +} + +/* + * vxge_hw_mempool_destroy + */ +void __vxge_hw_mempool_destroy(struct vxge_hw_mempool *mempool) +{ + u32 i, j; + struct __vxge_hw_device *devh = mempool->devh; + + for (i = 0; i < mempool->memblocks_allocated; i++) { + struct vxge_hw_mempool_dma *dma_object; + + vxge_assert(mempool->memblocks_arr[i]); + vxge_assert(mempool->memblocks_dma_arr + i); + + dma_object = mempool->memblocks_dma_arr + i; + + for (j = 0; j < mempool->items_per_memblock; j++) { + u32 index = i * mempool->items_per_memblock + j; + + /* to skip last partially filled(if any) memblock */ + if (index >= mempool->items_current) + break; + } + + vfree(mempool->memblocks_priv_arr[i]); + + __vxge_hw_blockpool_free(devh, mempool->memblocks_arr[i], + mempool->memblock_size, dma_object); + } + + if (mempool->items_arr) + vfree(mempool->items_arr); + + if (mempool->memblocks_dma_arr) + vfree(mempool->memblocks_dma_arr); + + if (mempool->memblocks_priv_arr) + vfree(mempool->memblocks_priv_arr); + + if (mempool->memblocks_arr) + vfree(mempool->memblocks_arr); + + vfree(mempool); +} + +/* + * __vxge_hw_device_fifo_config_check - Check fifo configuration. + * Check the fifo configuration + */ +enum vxge_hw_status +__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config) +{ + if ((fifo_config->fifo_blocks < VXGE_HW_MIN_FIFO_BLOCKS) || + (fifo_config->fifo_blocks > VXGE_HW_MAX_FIFO_BLOCKS)) + return VXGE_HW_BADCFG_FIFO_BLOCKS; + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_device_vpath_config_check - Check vpath configuration. + * Check the vpath configuration + */ +enum vxge_hw_status +__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config) +{ + enum vxge_hw_status status; + + if ((vp_config->min_bandwidth < VXGE_HW_VPATH_BANDWIDTH_MIN) || + (vp_config->min_bandwidth > + VXGE_HW_VPATH_BANDWIDTH_MAX)) + return VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH; + + status = __vxge_hw_device_fifo_config_check(&vp_config->fifo); + if (status != VXGE_HW_OK) + return status; + + if ((vp_config->mtu != VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU) && + ((vp_config->mtu < VXGE_HW_VPATH_MIN_INITIAL_MTU) || + (vp_config->mtu > VXGE_HW_VPATH_MAX_INITIAL_MTU))) + return VXGE_HW_BADCFG_VPATH_MTU; + + if ((vp_config->rpa_strip_vlan_tag != + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT) && + (vp_config->rpa_strip_vlan_tag != + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE) && + (vp_config->rpa_strip_vlan_tag != + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_DISABLE)) + return VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG; + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_device_config_check - Check device configuration. + * Check the device configuration + */ +enum vxge_hw_status +__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config) +{ + u32 i; + enum vxge_hw_status status; + + if ((new_config->intr_mode != VXGE_HW_INTR_MODE_IRQLINE) && + (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX) && + (new_config->intr_mode != VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) && + (new_config->intr_mode != VXGE_HW_INTR_MODE_DEF)) + return VXGE_HW_BADCFG_INTR_MODE; + + if ((new_config->rts_mac_en != VXGE_HW_RTS_MAC_DISABLE) && + (new_config->rts_mac_en != VXGE_HW_RTS_MAC_ENABLE)) + return VXGE_HW_BADCFG_RTS_MAC_EN; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + status = __vxge_hw_device_vpath_config_check( + &new_config->vp_config[i]); + if (status != VXGE_HW_OK) + return status; + } + + return VXGE_HW_OK; +} + +/* + * vxge_hw_device_config_default_get - Initialize device config with defaults. + * Initialize Titan device config with default values. + */ +enum vxge_hw_status __devinit +vxge_hw_device_config_default_get(struct vxge_hw_device_config *device_config) +{ + u32 i; + + device_config->dma_blockpool_initial = + VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE; + device_config->dma_blockpool_max = VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE; + device_config->intr_mode = VXGE_HW_INTR_MODE_DEF; + device_config->rth_en = VXGE_HW_RTH_DEFAULT; + device_config->rth_it_type = VXGE_HW_RTH_IT_TYPE_DEFAULT; + device_config->device_poll_millis = VXGE_HW_DEF_DEVICE_POLL_MILLIS; + device_config->rts_mac_en = VXGE_HW_RTS_MAC_DEFAULT; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + device_config->vp_config[i].vp_id = i; + + device_config->vp_config[i].min_bandwidth = + VXGE_HW_VPATH_BANDWIDTH_DEFAULT; + + device_config->vp_config[i].ring.enable = VXGE_HW_RING_DEFAULT; + + device_config->vp_config[i].ring.ring_blocks = + VXGE_HW_DEF_RING_BLOCKS; + + device_config->vp_config[i].ring.buffer_mode = + VXGE_HW_RING_RXD_BUFFER_MODE_DEFAULT; + + device_config->vp_config[i].ring.scatter_mode = + VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT; + + device_config->vp_config[i].ring.rxds_limit = + VXGE_HW_DEF_RING_RXDS_LIMIT; + + device_config->vp_config[i].fifo.enable = VXGE_HW_FIFO_ENABLE; + + device_config->vp_config[i].fifo.fifo_blocks = + VXGE_HW_MIN_FIFO_BLOCKS; + + device_config->vp_config[i].fifo.max_frags = + VXGE_HW_MAX_FIFO_FRAGS; + + device_config->vp_config[i].fifo.memblock_size = + VXGE_HW_DEF_FIFO_MEMBLOCK_SIZE; + + device_config->vp_config[i].fifo.alignment_size = + VXGE_HW_DEF_FIFO_ALIGNMENT_SIZE; + + device_config->vp_config[i].fifo.intr = + VXGE_HW_FIFO_QUEUE_INTR_DEFAULT; + + device_config->vp_config[i].fifo.no_snoop_bits = + VXGE_HW_FIFO_NO_SNOOP_DEFAULT; + device_config->vp_config[i].tti.intr_enable = + VXGE_HW_TIM_INTR_DEFAULT; + + device_config->vp_config[i].tti.btimer_val = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.timer_ac_en = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.timer_ci_en = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.timer_ri_en = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.rtimer_val = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.util_sel = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.ltimer_val = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.urange_a = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.uec_a = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.urange_b = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.uec_b = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.urange_c = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.uec_c = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].tti.uec_d = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.intr_enable = + VXGE_HW_TIM_INTR_DEFAULT; + + device_config->vp_config[i].rti.btimer_val = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.timer_ac_en = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.timer_ci_en = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.timer_ri_en = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.rtimer_val = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.util_sel = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.ltimer_val = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.urange_a = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.uec_a = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.urange_b = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.uec_b = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.urange_c = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.uec_c = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].rti.uec_d = + VXGE_HW_USE_FLASH_DEFAULT; + + device_config->vp_config[i].mtu = + VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU; + + device_config->vp_config[i].rpa_strip_vlan_tag = + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT; + } + + return VXGE_HW_OK; +} + +/* + * _hw_legacy_swapper_set - Set the swapper bits for the legacy secion. + * Set the swapper bits appropriately for the lagacy section. + */ +enum vxge_hw_status +__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + + val64 = readq(&legacy_reg->toc_swapper_fb); + + wmb(); + + switch (val64) { + + case VXGE_HW_SWAPPER_INITIAL_VALUE: + return status; + + case VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED: + writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE, + &legacy_reg->pifm_rd_swap_en); + writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE, + &legacy_reg->pifm_rd_flip_en); + writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE, + &legacy_reg->pifm_wr_swap_en); + writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE, + &legacy_reg->pifm_wr_flip_en); + break; + + case VXGE_HW_SWAPPER_BYTE_SWAPPED: + writeq(VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE, + &legacy_reg->pifm_rd_swap_en); + writeq(VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE, + &legacy_reg->pifm_wr_swap_en); + break; + + case VXGE_HW_SWAPPER_BIT_FLIPPED: + writeq(VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE, + &legacy_reg->pifm_rd_flip_en); + writeq(VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE, + &legacy_reg->pifm_wr_flip_en); + break; + } + + wmb(); + + val64 = readq(&legacy_reg->toc_swapper_fb); + + if (val64 != VXGE_HW_SWAPPER_INITIAL_VALUE) + status = VXGE_HW_ERR_SWAPPER_CTRL; + + return status; +} + +/* + * __vxge_hw_vpath_swapper_set - Set the swapper bits for the vpath. + * Set the swapper bits appropriately for the vpath. + */ +enum vxge_hw_status +__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg) +{ +#ifndef __BIG_ENDIAN + u64 val64; + + val64 = readq(&vpath_reg->vpath_general_cfg1); + wmb(); + val64 |= VXGE_HW_VPATH_GENERAL_CFG1_CTL_BYTE_SWAPEN; + writeq(val64, &vpath_reg->vpath_general_cfg1); + wmb(); +#endif + return VXGE_HW_OK; +} + +/* + * __vxge_hw_kdfc_swapper_set - Set the swapper bits for the kdfc. + * Set the swapper bits appropriately for the vpath. + */ +enum vxge_hw_status +__vxge_hw_kdfc_swapper_set( + struct vxge_hw_legacy_reg __iomem *legacy_reg, + struct vxge_hw_vpath_reg __iomem *vpath_reg) +{ + u64 val64; + + val64 = readq(&legacy_reg->pifm_wr_swap_en); + + if (val64 == VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE) { + val64 = readq(&vpath_reg->kdfcctl_cfg0); + wmb(); + + val64 |= VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO0 | + VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO1 | + VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO2; + + writeq(val64, &vpath_reg->kdfcctl_cfg0); + wmb(); + } + + return VXGE_HW_OK; +} + +/* + * vxge_hw_mgmt_device_config - Retrieve device configuration. + * Get device configuration. Permits to retrieve at run-time configuration + * values that were used to initialize and configure the device. + */ +enum vxge_hw_status +vxge_hw_mgmt_device_config(struct __vxge_hw_device *hldev, + struct vxge_hw_device_config *dev_config, int size) +{ + + if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) + return VXGE_HW_ERR_INVALID_DEVICE; + + if (size != sizeof(struct vxge_hw_device_config)) + return VXGE_HW_ERR_VERSION_CONFLICT; + + memcpy(dev_config, &hldev->config, + sizeof(struct vxge_hw_device_config)); + + return VXGE_HW_OK; +} + +/* + * vxge_hw_mgmt_reg_read - Read Titan register. + */ +enum vxge_hw_status +vxge_hw_mgmt_reg_read(struct __vxge_hw_device *hldev, + enum vxge_hw_mgmt_reg_type type, + u32 index, u32 offset, u64 *value) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) { + status = VXGE_HW_ERR_INVALID_DEVICE; + goto exit; + } + + switch (type) { + case vxge_hw_mgmt_reg_type_legacy: + if (offset > sizeof(struct vxge_hw_legacy_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + *value = readq((void __iomem *)hldev->legacy_reg + offset); + break; + case vxge_hw_mgmt_reg_type_toc: + if (offset > sizeof(struct vxge_hw_toc_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + *value = readq((void __iomem *)hldev->toc_reg + offset); + break; + case vxge_hw_mgmt_reg_type_common: + if (offset > sizeof(struct vxge_hw_common_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + *value = readq((void __iomem *)hldev->common_reg + offset); + break; + case vxge_hw_mgmt_reg_type_mrpcim: + if (!(hldev->access_rights & + VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) { + status = VXGE_HW_ERR_PRIVILAGED_OPEARATION; + break; + } + if (offset > sizeof(struct vxge_hw_mrpcim_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + *value = readq((void __iomem *)hldev->mrpcim_reg + offset); + break; + case vxge_hw_mgmt_reg_type_srpcim: + if (!(hldev->access_rights & + VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM)) { + status = VXGE_HW_ERR_PRIVILAGED_OPEARATION; + break; + } + if (index > VXGE_HW_TITAN_SRPCIM_REG_SPACES - 1) { + status = VXGE_HW_ERR_INVALID_INDEX; + break; + } + if (offset > sizeof(struct vxge_hw_srpcim_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + *value = readq((void __iomem *)hldev->srpcim_reg[index] + + offset); + break; + case vxge_hw_mgmt_reg_type_vpmgmt: + if ((index > VXGE_HW_TITAN_VPMGMT_REG_SPACES - 1) || + (!(hldev->vpath_assignments & vxge_mBIT(index)))) { + status = VXGE_HW_ERR_INVALID_INDEX; + break; + } + if (offset > sizeof(struct vxge_hw_vpmgmt_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + *value = readq((void __iomem *)hldev->vpmgmt_reg[index] + + offset); + break; + case vxge_hw_mgmt_reg_type_vpath: + if ((index > VXGE_HW_TITAN_VPATH_REG_SPACES - 1) || + (!(hldev->vpath_assignments & vxge_mBIT(index)))) { + status = VXGE_HW_ERR_INVALID_INDEX; + break; + } + if (index > VXGE_HW_TITAN_VPATH_REG_SPACES - 1) { + status = VXGE_HW_ERR_INVALID_INDEX; + break; + } + if (offset > sizeof(struct vxge_hw_vpath_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + *value = readq((void __iomem *)hldev->vpath_reg[index] + + offset); + break; + default: + status = VXGE_HW_ERR_INVALID_TYPE; + break; + } + +exit: + return status; +} + +/* + * vxge_hw_mgmt_reg_Write - Write Titan register. + */ +enum vxge_hw_status +vxge_hw_mgmt_reg_write(struct __vxge_hw_device *hldev, + enum vxge_hw_mgmt_reg_type type, + u32 index, u32 offset, u64 value) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) { + status = VXGE_HW_ERR_INVALID_DEVICE; + goto exit; + } + + switch (type) { + case vxge_hw_mgmt_reg_type_legacy: + if (offset > sizeof(struct vxge_hw_legacy_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + writeq(value, (void __iomem *)hldev->legacy_reg + offset); + break; + case vxge_hw_mgmt_reg_type_toc: + if (offset > sizeof(struct vxge_hw_toc_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + writeq(value, (void __iomem *)hldev->toc_reg + offset); + break; + case vxge_hw_mgmt_reg_type_common: + if (offset > sizeof(struct vxge_hw_common_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + writeq(value, (void __iomem *)hldev->common_reg + offset); + break; + case vxge_hw_mgmt_reg_type_mrpcim: + if (!(hldev->access_rights & + VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) { + status = VXGE_HW_ERR_PRIVILAGED_OPEARATION; + break; + } + if (offset > sizeof(struct vxge_hw_mrpcim_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + writeq(value, (void __iomem *)hldev->mrpcim_reg + offset); + break; + case vxge_hw_mgmt_reg_type_srpcim: + if (!(hldev->access_rights & + VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM)) { + status = VXGE_HW_ERR_PRIVILAGED_OPEARATION; + break; + } + if (index > VXGE_HW_TITAN_SRPCIM_REG_SPACES - 1) { + status = VXGE_HW_ERR_INVALID_INDEX; + break; + } + if (offset > sizeof(struct vxge_hw_srpcim_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + writeq(value, (void __iomem *)hldev->srpcim_reg[index] + + offset); + + break; + case vxge_hw_mgmt_reg_type_vpmgmt: + if ((index > VXGE_HW_TITAN_VPMGMT_REG_SPACES - 1) || + (!(hldev->vpath_assignments & vxge_mBIT(index)))) { + status = VXGE_HW_ERR_INVALID_INDEX; + break; + } + if (offset > sizeof(struct vxge_hw_vpmgmt_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + writeq(value, (void __iomem *)hldev->vpmgmt_reg[index] + + offset); + break; + case vxge_hw_mgmt_reg_type_vpath: + if ((index > VXGE_HW_TITAN_VPATH_REG_SPACES-1) || + (!(hldev->vpath_assignments & vxge_mBIT(index)))) { + status = VXGE_HW_ERR_INVALID_INDEX; + break; + } + if (offset > sizeof(struct vxge_hw_vpath_reg) - 8) { + status = VXGE_HW_ERR_INVALID_OFFSET; + break; + } + writeq(value, (void __iomem *)hldev->vpath_reg[index] + + offset); + break; + default: + status = VXGE_HW_ERR_INVALID_TYPE; + break; + } +exit: + return status; +} + +/* + * __vxge_hw_fifo_mempool_item_alloc - Allocate List blocks for TxD + * list callback + * This function is callback passed to __vxge_hw_mempool_create to create memory + * pool for TxD list + */ +static void +__vxge_hw_fifo_mempool_item_alloc( + struct vxge_hw_mempool *mempoolh, + u32 memblock_index, struct vxge_hw_mempool_dma *dma_object, + u32 index, u32 is_last) +{ + u32 memblock_item_idx; + struct __vxge_hw_fifo_txdl_priv *txdl_priv; + struct vxge_hw_fifo_txd *txdp = + (struct vxge_hw_fifo_txd *)mempoolh->items_arr[index]; + struct __vxge_hw_fifo *fifo = + (struct __vxge_hw_fifo *)mempoolh->userdata; + void *memblock = mempoolh->memblocks_arr[memblock_index]; + + vxge_assert(txdp); + + txdp->host_control = (u64) (size_t) + __vxge_hw_mempool_item_priv(mempoolh, memblock_index, txdp, + &memblock_item_idx); + + txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdp); + + vxge_assert(txdl_priv); + + fifo->channel.reserve_arr[fifo->channel.reserve_ptr - 1 - index] = txdp; + + /* pre-format HW's TxDL's private */ + txdl_priv->dma_offset = (char *)txdp - (char *)memblock; + txdl_priv->dma_addr = dma_object->addr + txdl_priv->dma_offset; + txdl_priv->dma_handle = dma_object->handle; + txdl_priv->memblock = memblock; + txdl_priv->first_txdp = txdp; + txdl_priv->next_txdl_priv = NULL; + txdl_priv->alloc_frags = 0; + + return; +} + +/* + * __vxge_hw_fifo_create - Create a FIFO + * This function creates FIFO and initializes it. + */ +enum vxge_hw_status +__vxge_hw_fifo_create(struct __vxge_hw_vpath_handle *vp, + struct vxge_hw_fifo_attr *attr) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_fifo *fifo; + struct vxge_hw_fifo_config *config; + u32 txdl_size, txdl_per_memblock; + struct vxge_hw_mempool_cbs fifo_mp_callback; + struct __vxge_hw_virtualpath *vpath; + + if ((vp == NULL) || (attr == NULL)) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + vpath = vp->vpath; + config = &vpath->hldev->config.vp_config[vpath->vp_id].fifo; + + txdl_size = config->max_frags * sizeof(struct vxge_hw_fifo_txd); + + txdl_per_memblock = config->memblock_size / txdl_size; + + fifo = (struct __vxge_hw_fifo *)__vxge_hw_channel_allocate(vp, + VXGE_HW_CHANNEL_TYPE_FIFO, + config->fifo_blocks * txdl_per_memblock, + attr->per_txdl_space, attr->userdata); + + if (fifo == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + vpath->fifoh = fifo; + fifo->nofl_db = vpath->nofl_db; + + fifo->vp_id = vpath->vp_id; + fifo->vp_reg = vpath->vp_reg; + fifo->stats = &vpath->sw_stats->fifo_stats; + + fifo->config = config; + + /* apply "interrupts per txdl" attribute */ + fifo->interrupt_type = VXGE_HW_FIFO_TXD_INT_TYPE_UTILZ; + + if (fifo->config->intr) + fifo->interrupt_type = VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST; + + fifo->no_snoop_bits = config->no_snoop_bits; + + /* + * FIFO memory management strategy: + * + * TxDL split into three independent parts: + * - set of TxD's + * - TxD HW private part + * - driver private part + * + * Adaptative memory allocation used. i.e. Memory allocated on + * demand with the size which will fit into one memory block. + * One memory block may contain more than one TxDL. + * + * During "reserve" operations more memory can be allocated on demand + * for example due to FIFO full condition. + * + * Pool of memory memblocks never shrinks except in __vxge_hw_fifo_close + * routine which will essentially stop the channel and free resources. + */ + + /* TxDL common private size == TxDL private + driver private */ + fifo->priv_size = + sizeof(struct __vxge_hw_fifo_txdl_priv) + attr->per_txdl_space; + fifo->priv_size = ((fifo->priv_size + VXGE_CACHE_LINE_SIZE - 1) / + VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE; + + fifo->per_txdl_space = attr->per_txdl_space; + + /* recompute txdl size to be cacheline aligned */ + fifo->txdl_size = txdl_size; + fifo->txdl_per_memblock = txdl_per_memblock; + + fifo->txdl_term = attr->txdl_term; + fifo->callback = attr->callback; + + if (fifo->txdl_per_memblock == 0) { + __vxge_hw_fifo_delete(vp); + status = VXGE_HW_ERR_INVALID_BLOCK_SIZE; + goto exit; + } + + fifo_mp_callback.item_func_alloc = __vxge_hw_fifo_mempool_item_alloc; + + fifo->mempool = + __vxge_hw_mempool_create(vpath->hldev, + fifo->config->memblock_size, + fifo->txdl_size, + fifo->priv_size, + (fifo->config->fifo_blocks * fifo->txdl_per_memblock), + (fifo->config->fifo_blocks * fifo->txdl_per_memblock), + &fifo_mp_callback, + fifo); + + if (fifo->mempool == NULL) { + __vxge_hw_fifo_delete(vp); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + status = __vxge_hw_channel_initialize(&fifo->channel); + if (status != VXGE_HW_OK) { + __vxge_hw_fifo_delete(vp); + goto exit; + } + + vxge_assert(fifo->channel.reserve_ptr); +exit: + return status; +} + +/* + * __vxge_hw_fifo_abort - Returns the TxD + * This function terminates the TxDs of fifo + */ +enum vxge_hw_status __vxge_hw_fifo_abort(struct __vxge_hw_fifo *fifo) +{ + void *txdlh; + + for (;;) { + vxge_hw_channel_dtr_try_complete(&fifo->channel, &txdlh); + + if (txdlh == NULL) + break; + + vxge_hw_channel_dtr_complete(&fifo->channel); + + if (fifo->txdl_term) { + fifo->txdl_term(txdlh, + VXGE_HW_TXDL_STATE_POSTED, + fifo->channel.userdata); + } + + vxge_hw_channel_dtr_free(&fifo->channel, txdlh); + } + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_fifo_reset - Resets the fifo + * This function resets the fifo during vpath reset operation + */ +enum vxge_hw_status __vxge_hw_fifo_reset(struct __vxge_hw_fifo *fifo) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + __vxge_hw_fifo_abort(fifo); + status = __vxge_hw_channel_reset(&fifo->channel); + + return status; +} + +/* + * __vxge_hw_fifo_delete - Removes the FIFO + * This function freeup the memory pool and removes the FIFO + */ +enum vxge_hw_status __vxge_hw_fifo_delete(struct __vxge_hw_vpath_handle *vp) +{ + struct __vxge_hw_fifo *fifo = vp->vpath->fifoh; + + __vxge_hw_fifo_abort(fifo); + + if (fifo->mempool) + __vxge_hw_mempool_destroy(fifo->mempool); + + vp->vpath->fifoh = NULL; + + __vxge_hw_channel_free(&fifo->channel); + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_vpath_pci_read - Read the content of given address + * in pci config space. + * Read from the vpath pci config space. + */ +enum vxge_hw_status +__vxge_hw_vpath_pci_read(struct __vxge_hw_virtualpath *vpath, + u32 phy_func_0, u32 offset, u32 *val) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg; + + val64 = VXGE_HW_PCI_CONFIG_ACCESS_CFG1_ADDRESS(offset); + + if (phy_func_0) + val64 |= VXGE_HW_PCI_CONFIG_ACCESS_CFG1_SEL_FUNC0; + + writeq(val64, &vp_reg->pci_config_access_cfg1); + wmb(); + writeq(VXGE_HW_PCI_CONFIG_ACCESS_CFG2_REQ, + &vp_reg->pci_config_access_cfg2); + wmb(); + + status = __vxge_hw_device_register_poll( + &vp_reg->pci_config_access_cfg2, + VXGE_HW_INTR_MASK_ALL, VXGE_HW_DEF_DEVICE_POLL_MILLIS); + + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&vp_reg->pci_config_access_status); + + if (val64 & VXGE_HW_PCI_CONFIG_ACCESS_STATUS_ACCESS_ERR) { + status = VXGE_HW_FAIL; + *val = 0; + } else + *val = (u32)vxge_bVALn(val64, 32, 32); +exit: + return status; +} + +/* + * __vxge_hw_vpath_func_id_get - Get the function id of the vpath. + * Returns the function number of the vpath. + */ +u32 +__vxge_hw_vpath_func_id_get(u32 vp_id, + struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg) +{ + u64 val64; + + val64 = readq(&vpmgmt_reg->vpath_to_func_map_cfg1); + + return + (u32)VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(val64); +} + +/* + * __vxge_hw_read_rts_ds - Program RTS steering critieria + */ +static inline void +__vxge_hw_read_rts_ds(struct vxge_hw_vpath_reg __iomem *vpath_reg, + u64 dta_struct_sel) +{ + writeq(0, &vpath_reg->rts_access_steer_ctrl); + wmb(); + writeq(dta_struct_sel, &vpath_reg->rts_access_steer_data0); + writeq(0, &vpath_reg->rts_access_steer_data1); + wmb(); + return; +} + + +/* + * __vxge_hw_vpath_card_info_get - Get the serial numbers, + * part number and product description. + */ +enum vxge_hw_status +__vxge_hw_vpath_card_info_get( + u32 vp_id, + struct vxge_hw_vpath_reg __iomem *vpath_reg, + struct vxge_hw_device_hw_info *hw_info) +{ + u32 i, j; + u64 val64; + u64 data1 = 0ULL; + u64 data2 = 0ULL; + enum vxge_hw_status status = VXGE_HW_OK; + u8 *serial_number = hw_info->serial_number; + u8 *part_number = hw_info->part_number; + u8 *product_desc = hw_info->product_desc; + + __vxge_hw_read_rts_ds(vpath_reg, + VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER); + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); + + status = __vxge_hw_pio_mem_write64(val64, + &vpath_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + + if (status != VXGE_HW_OK) + return status; + + val64 = readq(&vpath_reg->rts_access_steer_ctrl); + + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { + data1 = readq(&vpath_reg->rts_access_steer_data0); + ((u64 *)serial_number)[0] = be64_to_cpu(data1); + + data2 = readq(&vpath_reg->rts_access_steer_data1); + ((u64 *)serial_number)[1] = be64_to_cpu(data2); + status = VXGE_HW_OK; + } else + *serial_number = 0; + + __vxge_hw_read_rts_ds(vpath_reg, + VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER); + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); + + status = __vxge_hw_pio_mem_write64(val64, + &vpath_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + + if (status != VXGE_HW_OK) + return status; + + val64 = readq(&vpath_reg->rts_access_steer_ctrl); + + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { + + data1 = readq(&vpath_reg->rts_access_steer_data0); + ((u64 *)part_number)[0] = be64_to_cpu(data1); + + data2 = readq(&vpath_reg->rts_access_steer_data1); + ((u64 *)part_number)[1] = be64_to_cpu(data2); + + status = VXGE_HW_OK; + + } else + *part_number = 0; + + j = 0; + + for (i = VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0; + i <= VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3; i++) { + + __vxge_hw_read_rts_ds(vpath_reg, i); + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); + + status = __vxge_hw_pio_mem_write64(val64, + &vpath_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + + if (status != VXGE_HW_OK) + return status; + + val64 = readq(&vpath_reg->rts_access_steer_ctrl); + + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { + + data1 = readq(&vpath_reg->rts_access_steer_data0); + ((u64 *)product_desc)[j++] = be64_to_cpu(data1); + + data2 = readq(&vpath_reg->rts_access_steer_data1); + ((u64 *)product_desc)[j++] = be64_to_cpu(data2); + + status = VXGE_HW_OK; + } else + *product_desc = 0; + } + + return status; +} + +/* + * __vxge_hw_vpath_fw_ver_get - Get the fw version + * Returns FW Version + */ +enum vxge_hw_status +__vxge_hw_vpath_fw_ver_get( + u32 vp_id, + struct vxge_hw_vpath_reg __iomem *vpath_reg, + struct vxge_hw_device_hw_info *hw_info) +{ + u64 val64; + u64 data1 = 0ULL; + u64 data2 = 0ULL; + struct vxge_hw_device_version *fw_version = &hw_info->fw_version; + struct vxge_hw_device_date *fw_date = &hw_info->fw_date; + struct vxge_hw_device_version *flash_version = &hw_info->flash_version; + struct vxge_hw_device_date *flash_date = &hw_info->flash_date; + enum vxge_hw_status status = VXGE_HW_OK; + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); + + status = __vxge_hw_pio_mem_write64(val64, + &vpath_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&vpath_reg->rts_access_steer_ctrl); + + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { + + data1 = readq(&vpath_reg->rts_access_steer_data0); + data2 = readq(&vpath_reg->rts_access_steer_data1); + + fw_date->day = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY( + data1); + fw_date->month = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH( + data1); + fw_date->year = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR( + data1); + + snprintf(fw_date->date, VXGE_HW_FW_STRLEN, "%2.2d/%2.2d/%4.4d", + fw_date->month, fw_date->day, fw_date->year); + + fw_version->major = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(data1); + fw_version->minor = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(data1); + fw_version->build = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(data1); + + snprintf(fw_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d", + fw_version->major, fw_version->minor, fw_version->build); + + flash_date->day = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(data2); + flash_date->month = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(data2); + flash_date->year = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(data2); + + snprintf(flash_date->date, VXGE_HW_FW_STRLEN, + "%2.2d/%2.2d/%4.4d", + flash_date->month, flash_date->day, flash_date->year); + + flash_version->major = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(data2); + flash_version->minor = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(data2); + flash_version->build = + (u32)VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(data2); + + snprintf(flash_version->version, VXGE_HW_FW_STRLEN, "%d.%d.%d", + flash_version->major, flash_version->minor, + flash_version->build); + + status = VXGE_HW_OK; + + } else + status = VXGE_HW_FAIL; +exit: + return status; +} + +/* + * __vxge_hw_vpath_pci_func_mode_get - Get the pci mode + * Returns pci function mode + */ +u64 +__vxge_hw_vpath_pci_func_mode_get( + u32 vp_id, + struct vxge_hw_vpath_reg __iomem *vpath_reg) +{ + u64 val64; + u64 data1 = 0ULL; + enum vxge_hw_status status = VXGE_HW_OK; + + __vxge_hw_read_rts_ds(vpath_reg, + VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE); + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); + + status = __vxge_hw_pio_mem_write64(val64, + &vpath_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&vpath_reg->rts_access_steer_ctrl); + + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { + data1 = readq(&vpath_reg->rts_access_steer_data0); + status = VXGE_HW_OK; + } else { + data1 = 0; + status = VXGE_HW_FAIL; + } +exit: + return data1; +} + +/** + * vxge_hw_device_flick_link_led - Flick (blink) link LED. + * @hldev: HW device. + * @on_off: TRUE if flickering to be on, FALSE to be off + * + * Flicker the link LED. + */ +enum vxge_hw_status +vxge_hw_device_flick_link_led(struct __vxge_hw_device *hldev, + u64 on_off) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + if (hldev == NULL) { + status = VXGE_HW_ERR_INVALID_DEVICE; + goto exit; + } + + vp_reg = hldev->vpath_reg[hldev->first_vp_id]; + + writeq(0, &vp_reg->rts_access_steer_ctrl); + wmb(); + writeq(on_off, &vp_reg->rts_access_steer_data0); + writeq(0, &vp_reg->rts_access_steer_data1); + wmb(); + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); + + status = __vxge_hw_pio_mem_write64(val64, + &vp_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); +exit: + return status; +} + +/* + * __vxge_hw_vpath_rts_table_get - Get the entries from RTS access tables + */ +enum vxge_hw_status +__vxge_hw_vpath_rts_table_get( + struct __vxge_hw_vpath_handle *vp, + u32 action, u32 rts_table, u32 offset, u64 *data1, u64 *data2) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + vp_reg = vpath->vp_reg; + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(rts_table) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset); + + if ((rts_table == + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT) || + (rts_table == + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT) || + (rts_table == + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK) || + (rts_table == + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY)) { + val64 = val64 | VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL; + } + + status = __vxge_hw_pio_mem_write64(val64, + &vp_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + vpath->hldev->config.device_poll_millis); + + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&vp_reg->rts_access_steer_ctrl); + + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { + + *data1 = readq(&vp_reg->rts_access_steer_data0); + + if ((rts_table == + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) || + (rts_table == + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) { + *data2 = readq(&vp_reg->rts_access_steer_data1); + } + status = VXGE_HW_OK; + } else + status = VXGE_HW_FAIL; +exit: + return status; +} + +/* + * __vxge_hw_vpath_rts_table_set - Set the entries of RTS access tables + */ +enum vxge_hw_status +__vxge_hw_vpath_rts_table_set( + struct __vxge_hw_vpath_handle *vp, u32 action, u32 rts_table, + u32 offset, u64 data1, u64 data2) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + vp_reg = vpath->vp_reg; + + writeq(data1, &vp_reg->rts_access_steer_data0); + wmb(); + + if ((rts_table == VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) || + (rts_table == + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT)) { + writeq(data2, &vp_reg->rts_access_steer_data1); + wmb(); + } + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(action) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(rts_table) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(offset); + + status = __vxge_hw_pio_mem_write64(val64, + &vp_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + vpath->hldev->config.device_poll_millis); + + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&vp_reg->rts_access_steer_ctrl); + + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) + status = VXGE_HW_OK; + else + status = VXGE_HW_FAIL; +exit: + return status; +} + +/* + * __vxge_hw_vpath_addr_get - Get the hw address entry for this vpath + * from MAC address table. + */ +enum vxge_hw_status +__vxge_hw_vpath_addr_get( + u32 vp_id, struct vxge_hw_vpath_reg __iomem *vpath_reg, + u8 (macaddr)[ETH_ALEN], u8 (macaddr_mask)[ETH_ALEN]) +{ + u32 i; + u64 val64; + u64 data1 = 0ULL; + u64 data2 = 0ULL; + enum vxge_hw_status status = VXGE_HW_OK; + + val64 = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION( + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL( + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA) | + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE | + VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(0); + + status = __vxge_hw_pio_mem_write64(val64, + &vpath_reg->rts_access_steer_ctrl, + VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE, + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&vpath_reg->rts_access_steer_ctrl); + + if (val64 & VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS) { + + data1 = readq(&vpath_reg->rts_access_steer_data0); + data2 = readq(&vpath_reg->rts_access_steer_data1); + + data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1); + data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK( + data2); + + for (i = ETH_ALEN; i > 0; i--) { + macaddr[i-1] = (u8)(data1 & 0xFF); + data1 >>= 8; + + macaddr_mask[i-1] = (u8)(data2 & 0xFF); + data2 >>= 8; + } + status = VXGE_HW_OK; + } else + status = VXGE_HW_FAIL; +exit: + return status; +} + +/* + * vxge_hw_vpath_rts_rth_set - Set/configure RTS hashing. + */ +enum vxge_hw_status vxge_hw_vpath_rts_rth_set( + struct __vxge_hw_vpath_handle *vp, + enum vxge_hw_rth_algoritms algorithm, + struct vxge_hw_rth_hash_types *hash_type, + u16 bucket_size) +{ + u64 data0, data1; + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + status = __vxge_hw_vpath_rts_table_get(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG, + 0, &data0, &data1); + + data0 &= ~(VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(0xf) | + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(0x3)); + + data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_EN | + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(bucket_size) | + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(algorithm); + + if (hash_type->hash_type_tcpipv4_en) + data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV4_EN; + + if (hash_type->hash_type_ipv4_en) + data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV4_EN; + + if (hash_type->hash_type_tcpipv6_en) + data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EN; + + if (hash_type->hash_type_ipv6_en) + data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EN; + + if (hash_type->hash_type_tcpipv6ex_en) + data0 |= + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EX_EN; + + if (hash_type->hash_type_ipv6ex_en) + data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EX_EN; + + if (VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ACTIVE_TABLE(data0)) + data0 &= ~VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE; + else + data0 |= VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE; + + status = __vxge_hw_vpath_rts_table_set(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG, + 0, data0, 0); +exit: + return status; +} + +static void +vxge_hw_rts_rth_data0_data1_get(u32 j, u64 *data0, u64 *data1, + u16 flag, u8 *itable) +{ + switch (flag) { + case 1: + *data0 = VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_NUM(j)| + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_ENTRY_EN | + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_DATA( + itable[j]); + case 2: + *data0 |= + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_NUM(j)| + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_ENTRY_EN | + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_DATA( + itable[j]); + case 3: + *data1 = VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_NUM(j)| + VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_ENTRY_EN | + VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_DATA( + itable[j]); + case 4: + *data1 |= + VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_NUM(j)| + VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN | + VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA( + itable[j]); + default: + return; + } +} +/* + * vxge_hw_vpath_rts_rth_itable_set - Set/configure indirection table (IT). + */ +enum vxge_hw_status vxge_hw_vpath_rts_rth_itable_set( + struct __vxge_hw_vpath_handle **vpath_handles, + u32 vpath_count, + u8 *mtable, + u8 *itable, + u32 itable_size) +{ + u32 i, j, action, rts_table; + u64 data0; + u64 data1; + u32 max_entries; + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_vpath_handle *vp = vpath_handles[0]; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + max_entries = (((u32)1) << itable_size); + + if (vp->vpath->hldev->config.rth_it_type + == VXGE_HW_RTH_IT_TYPE_SOLO_IT) { + action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY; + rts_table = + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT; + + for (j = 0; j < max_entries; j++) { + + data1 = 0; + + data0 = + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA( + itable[j]); + + status = __vxge_hw_vpath_rts_table_set(vpath_handles[0], + action, rts_table, j, data0, data1); + + if (status != VXGE_HW_OK) + goto exit; + } + + for (j = 0; j < max_entries; j++) { + + data1 = 0; + + data0 = + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_ENTRY_EN | + VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA( + itable[j]); + + status = __vxge_hw_vpath_rts_table_set( + vpath_handles[mtable[itable[j]]], action, + rts_table, j, data0, data1); + + if (status != VXGE_HW_OK) + goto exit; + } + } else { + action = VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY; + rts_table = + VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT; + for (i = 0; i < vpath_count; i++) { + + for (j = 0; j < max_entries;) { + + data0 = 0; + data1 = 0; + + while (j < max_entries) { + if (mtable[itable[j]] != i) { + j++; + continue; + } + vxge_hw_rts_rth_data0_data1_get(j, + &data0, &data1, 1, itable); + j++; + break; + } + + while (j < max_entries) { + if (mtable[itable[j]] != i) { + j++; + continue; + } + vxge_hw_rts_rth_data0_data1_get(j, + &data0, &data1, 2, itable); + j++; + break; + } + + while (j < max_entries) { + if (mtable[itable[j]] != i) { + j++; + continue; + } + vxge_hw_rts_rth_data0_data1_get(j, + &data0, &data1, 3, itable); + j++; + break; + } + + while (j < max_entries) { + if (mtable[itable[j]] != i) { + j++; + continue; + } + vxge_hw_rts_rth_data0_data1_get(j, + &data0, &data1, 4, itable); + j++; + break; + } + + if (data0 != 0) { + status = __vxge_hw_vpath_rts_table_set( + vpath_handles[i], + action, rts_table, + 0, data0, data1); + + if (status != VXGE_HW_OK) + goto exit; + } + } + } + } +exit: + return status; +} + +/** + * vxge_hw_vpath_check_leak - Check for memory leak + * @ringh: Handle to the ring object used for receive + * + * If PRC_RXD_DOORBELL_VPn.NEW_QW_CNT is larger or equal to + * PRC_CFG6_VPn.RXD_SPAT then a leak has occurred. + * Returns: VXGE_HW_FAIL, if leak has occurred. + * + */ +enum vxge_hw_status +vxge_hw_vpath_check_leak(struct __vxge_hw_ring *ring) +{ + enum vxge_hw_status status = VXGE_HW_OK; + u64 rxd_new_count, rxd_spat; + + if (ring == NULL) + return status; + + rxd_new_count = readl(&ring->vp_reg->prc_rxd_doorbell); + rxd_spat = readq(&ring->vp_reg->prc_cfg6); + rxd_spat = VXGE_HW_PRC_CFG6_RXD_SPAT(rxd_spat); + + if (rxd_new_count >= rxd_spat) + status = VXGE_HW_FAIL; + + return status; +} + +/* + * __vxge_hw_vpath_mgmt_read + * This routine reads the vpath_mgmt registers + */ +static enum vxge_hw_status +__vxge_hw_vpath_mgmt_read( + struct __vxge_hw_device *hldev, + struct __vxge_hw_virtualpath *vpath) +{ + u32 i, mtu = 0, max_pyld = 0; + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + + for (i = 0; i < VXGE_HW_MAC_MAX_MAC_PORT_ID; i++) { + + val64 = readq(&vpath->vpmgmt_reg-> + rxmac_cfg0_port_vpmgmt_clone[i]); + max_pyld = + (u32) + VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_GET_MAX_PYLD_LEN + (val64); + if (mtu < max_pyld) + mtu = max_pyld; + } + + vpath->max_mtu = mtu + VXGE_HW_MAC_HEADER_MAX_SIZE; + + val64 = readq(&vpath->vpmgmt_reg->xmac_vsport_choices_vp); + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + if (val64 & vxge_mBIT(i)) + vpath->vsport_number = i; + } + + val64 = readq(&vpath->vpmgmt_reg->xgmac_gen_status_vpmgmt_clone); + + if (val64 & VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_OK) + VXGE_HW_DEVICE_LINK_STATE_SET(vpath->hldev, VXGE_HW_LINK_UP); + else + VXGE_HW_DEVICE_LINK_STATE_SET(vpath->hldev, VXGE_HW_LINK_DOWN); + + return status; +} + +/* + * __vxge_hw_vpath_reset_check - Check if resetting the vpath completed + * This routine checks the vpath_rst_in_prog register to see if + * adapter completed the reset process for the vpath + */ +enum vxge_hw_status +__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath) +{ + enum vxge_hw_status status; + + status = __vxge_hw_device_register_poll( + &vpath->hldev->common_reg->vpath_rst_in_prog, + VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG( + 1 << (16 - vpath->vp_id)), + vpath->hldev->config.device_poll_millis); + + return status; +} + +/* + * __vxge_hw_vpath_reset + * This routine resets the vpath on the device + */ +enum vxge_hw_status +__vxge_hw_vpath_reset(struct __vxge_hw_device *hldev, u32 vp_id) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + + val64 = VXGE_HW_CMN_RSTHDLR_CFG0_SW_RESET_VPATH(1 << (16 - vp_id)); + + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), + &hldev->common_reg->cmn_rsthdlr_cfg0); + + return status; +} + +/* + * __vxge_hw_vpath_sw_reset + * This routine resets the vpath structures + */ +enum vxge_hw_status +__vxge_hw_vpath_sw_reset(struct __vxge_hw_device *hldev, u32 vp_id) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_virtualpath *vpath; + + vpath = (struct __vxge_hw_virtualpath *)&hldev->virtual_paths[vp_id]; + + if (vpath->ringh) { + status = __vxge_hw_ring_reset(vpath->ringh); + if (status != VXGE_HW_OK) + goto exit; + } + + if (vpath->fifoh) + status = __vxge_hw_fifo_reset(vpath->fifoh); +exit: + return status; +} + +/* + * __vxge_hw_vpath_prc_configure + * This routine configures the prc registers of virtual path using the config + * passed + */ +void +__vxge_hw_vpath_prc_configure(struct __vxge_hw_device *hldev, u32 vp_id) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath; + struct vxge_hw_vp_config *vp_config; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + vpath = &hldev->virtual_paths[vp_id]; + vp_reg = vpath->vp_reg; + vp_config = vpath->vp_config; + + if (vp_config->ring.enable == VXGE_HW_RING_DISABLE) + return; + + val64 = readq(&vp_reg->prc_cfg1); + val64 |= VXGE_HW_PRC_CFG1_RTI_TINT_DISABLE; + writeq(val64, &vp_reg->prc_cfg1); + + val64 = readq(&vpath->vp_reg->prc_cfg6); + val64 |= VXGE_HW_PRC_CFG6_DOORBELL_MODE_EN; + writeq(val64, &vpath->vp_reg->prc_cfg6); + + val64 = readq(&vp_reg->prc_cfg7); + + if (vpath->vp_config->ring.scatter_mode != + VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT) { + + val64 &= ~VXGE_HW_PRC_CFG7_SCATTER_MODE(0x3); + + switch (vpath->vp_config->ring.scatter_mode) { + case VXGE_HW_RING_SCATTER_MODE_A: + val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE( + VXGE_HW_PRC_CFG7_SCATTER_MODE_A); + break; + case VXGE_HW_RING_SCATTER_MODE_B: + val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE( + VXGE_HW_PRC_CFG7_SCATTER_MODE_B); + break; + case VXGE_HW_RING_SCATTER_MODE_C: + val64 |= VXGE_HW_PRC_CFG7_SCATTER_MODE( + VXGE_HW_PRC_CFG7_SCATTER_MODE_C); + break; + } + } + + writeq(val64, &vp_reg->prc_cfg7); + + writeq(VXGE_HW_PRC_CFG5_RXD0_ADD( + __vxge_hw_ring_first_block_address_get( + vpath->ringh) >> 3), &vp_reg->prc_cfg5); + + val64 = readq(&vp_reg->prc_cfg4); + val64 |= VXGE_HW_PRC_CFG4_IN_SVC; + val64 &= ~VXGE_HW_PRC_CFG4_RING_MODE(0x3); + + val64 |= VXGE_HW_PRC_CFG4_RING_MODE( + VXGE_HW_PRC_CFG4_RING_MODE_ONE_BUFFER); + + if (hldev->config.rth_en == VXGE_HW_RTH_DISABLE) + val64 |= VXGE_HW_PRC_CFG4_RTH_DISABLE; + else + val64 &= ~VXGE_HW_PRC_CFG4_RTH_DISABLE; + + writeq(val64, &vp_reg->prc_cfg4); + return; +} + +/* + * __vxge_hw_vpath_kdfc_configure + * This routine configures the kdfc registers of virtual path using the + * config passed + */ +enum vxge_hw_status +__vxge_hw_vpath_kdfc_configure(struct __vxge_hw_device *hldev, u32 vp_id) +{ + u64 val64; + u64 vpath_stride; + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_virtualpath *vpath; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + vpath = &hldev->virtual_paths[vp_id]; + vp_reg = vpath->vp_reg; + status = __vxge_hw_kdfc_swapper_set(hldev->legacy_reg, vp_reg); + + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&vp_reg->kdfc_drbl_triplet_total); + + vpath->max_kdfc_db = + (u32)VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_GET_KDFC_MAX_SIZE( + val64+1)/2; + + if (vpath->vp_config->fifo.enable == VXGE_HW_FIFO_ENABLE) { + + vpath->max_nofl_db = vpath->max_kdfc_db; + + if (vpath->max_nofl_db < + ((vpath->vp_config->fifo.memblock_size / + (vpath->vp_config->fifo.max_frags * + sizeof(struct vxge_hw_fifo_txd))) * + vpath->vp_config->fifo.fifo_blocks)) { + + return VXGE_HW_BADCFG_FIFO_BLOCKS; + } + val64 = VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_0( + (vpath->max_nofl_db*2)-1); + } + + writeq(val64, &vp_reg->kdfc_fifo_trpl_partition); + + writeq(VXGE_HW_KDFC_FIFO_TRPL_CTRL_TRIPLET_ENABLE, + &vp_reg->kdfc_fifo_trpl_ctrl); + + val64 = readq(&vp_reg->kdfc_trpl_fifo_0_ctrl); + + val64 &= ~(VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(0x3) | + VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(0xFF)); + + val64 |= VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE( + VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_NON_OFFLOAD_ONLY) | +#ifndef __BIG_ENDIAN + VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SWAP_EN | +#endif + VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(0); + + writeq(val64, &vp_reg->kdfc_trpl_fifo_0_ctrl); + writeq((u64)0, &vp_reg->kdfc_trpl_fifo_0_wb_address); + wmb(); + vpath_stride = readq(&hldev->toc_reg->toc_kdfc_vpath_stride); + + vpath->nofl_db = + (struct __vxge_hw_non_offload_db_wrapper __iomem *) + (hldev->kdfc + (vp_id * + VXGE_HW_TOC_KDFC_VPATH_STRIDE_GET_TOC_KDFC_VPATH_STRIDE( + vpath_stride))); +exit: + return status; +} + +/* + * __vxge_hw_vpath_mac_configure + * This routine configures the mac of virtual path using the config passed + */ +enum vxge_hw_status +__vxge_hw_vpath_mac_configure(struct __vxge_hw_device *hldev, u32 vp_id) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_virtualpath *vpath; + struct vxge_hw_vp_config *vp_config; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + vpath = &hldev->virtual_paths[vp_id]; + vp_reg = vpath->vp_reg; + vp_config = vpath->vp_config; + + writeq(VXGE_HW_XMAC_VSPORT_CHOICE_VSPORT_NUMBER( + vpath->vsport_number), &vp_reg->xmac_vsport_choice); + + if (vp_config->ring.enable == VXGE_HW_RING_ENABLE) { + + val64 = readq(&vp_reg->xmac_rpa_vcfg); + + if (vp_config->rpa_strip_vlan_tag != + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT) { + if (vp_config->rpa_strip_vlan_tag) + val64 |= VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG; + else + val64 &= ~VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG; + } + + writeq(val64, &vp_reg->xmac_rpa_vcfg); + val64 = readq(&vp_reg->rxmac_vcfg0); + + if (vp_config->mtu != + VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU) { + val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff); + if ((vp_config->mtu + + VXGE_HW_MAC_HEADER_MAX_SIZE) < vpath->max_mtu) + val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN( + vp_config->mtu + + VXGE_HW_MAC_HEADER_MAX_SIZE); + else + val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN( + vpath->max_mtu); + } + + writeq(val64, &vp_reg->rxmac_vcfg0); + + val64 = readq(&vp_reg->rxmac_vcfg1); + + val64 &= ~(VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(0x3) | + VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE); + + if (hldev->config.rth_it_type == + VXGE_HW_RTH_IT_TYPE_MULTI_IT) { + val64 |= VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE( + 0x2) | + VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE; + } + + writeq(val64, &vp_reg->rxmac_vcfg1); + } + return status; +} + +/* + * __vxge_hw_vpath_tim_configure + * This routine configures the tim registers of virtual path using the config + * passed + */ +enum vxge_hw_status +__vxge_hw_vpath_tim_configure(struct __vxge_hw_device *hldev, u32 vp_id) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_virtualpath *vpath; + struct vxge_hw_vpath_reg __iomem *vp_reg; + struct vxge_hw_vp_config *config; + + vpath = &hldev->virtual_paths[vp_id]; + vp_reg = vpath->vp_reg; + config = vpath->vp_config; + + writeq((u64)0, &vp_reg->tim_dest_addr); + writeq((u64)0, &vp_reg->tim_vpath_map); + writeq((u64)0, &vp_reg->tim_bitmap); + writeq((u64)0, &vp_reg->tim_remap); + + if (config->ring.enable == VXGE_HW_RING_ENABLE) + writeq(VXGE_HW_TIM_RING_ASSN_INT_NUM( + (vp_id * VXGE_HW_MAX_INTR_PER_VP) + + VXGE_HW_VPATH_INTR_RX), &vp_reg->tim_ring_assn); + + val64 = readq(&vp_reg->tim_pci_cfg); + val64 |= VXGE_HW_TIM_PCI_CFG_ADD_PAD; + writeq(val64, &vp_reg->tim_pci_cfg); + + if (config->fifo.enable == VXGE_HW_FIFO_ENABLE) { + + val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]); + + if (config->tti.btimer_val != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL( + 0x3ffffff); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL( + config->tti.btimer_val); + } + + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN; + + if (config->tti.timer_ac_en != VXGE_HW_USE_FLASH_DEFAULT) { + if (config->tti.timer_ac_en) + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC; + else + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC; + } + + if (config->tti.timer_ci_en != VXGE_HW_USE_FLASH_DEFAULT) { + if (config->tti.timer_ci_en) + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI; + else + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI; + } + + if (config->tti.urange_a != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(0x3f); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_A( + config->tti.urange_a); + } + + if (config->tti.urange_b != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(0x3f); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_B( + config->tti.urange_b); + } + + if (config->tti.urange_c != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(0x3f); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_C( + config->tti.urange_c); + } + + writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_TX]); + val64 = readq(&vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_TX]); + + if (config->tti.uec_a != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(0xffff); + val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_A( + config->tti.uec_a); + } + + if (config->tti.uec_b != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(0xffff); + val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_B( + config->tti.uec_b); + } + + if (config->tti.uec_c != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(0xffff); + val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_C( + config->tti.uec_c); + } + + if (config->tti.uec_d != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(0xffff); + val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_D( + config->tti.uec_d); + } + + writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_TX]); + val64 = readq(&vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]); + + if (config->tti.timer_ri_en != VXGE_HW_USE_FLASH_DEFAULT) { + if (config->tti.timer_ri_en) + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI; + else + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI; + } + + if (config->tti.rtimer_val != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL( + 0x3ffffff); + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL( + config->tti.rtimer_val); + } + + if (config->tti.util_sel != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(0x3f); + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL( + config->tti.util_sel); + } + + if (config->tti.ltimer_val != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL( + 0x3ffffff); + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL( + config->tti.ltimer_val); + } + + writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_TX]); + } + + if (config->ring.enable == VXGE_HW_RING_ENABLE) { + + val64 = readq(&vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]); + + if (config->rti.btimer_val != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL( + 0x3ffffff); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL( + config->rti.btimer_val); + } + + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN; + + if (config->rti.timer_ac_en != VXGE_HW_USE_FLASH_DEFAULT) { + if (config->rti.timer_ac_en) + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC; + else + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC; + } + + if (config->rti.timer_ci_en != VXGE_HW_USE_FLASH_DEFAULT) { + if (config->rti.timer_ci_en) + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI; + else + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI; + } + + if (config->rti.urange_a != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(0x3f); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_A( + config->rti.urange_a); + } + + if (config->rti.urange_b != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(0x3f); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_B( + config->rti.urange_b); + } + + if (config->rti.urange_c != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(0x3f); + val64 |= VXGE_HW_TIM_CFG1_INT_NUM_URNG_C( + config->rti.urange_c); + } + + writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_RX]); + val64 = readq(&vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_RX]); + + if (config->rti.uec_a != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(0xffff); + val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_A( + config->rti.uec_a); + } + + if (config->rti.uec_b != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(0xffff); + val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_B( + config->rti.uec_b); + } + + if (config->rti.uec_c != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(0xffff); + val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_C( + config->rti.uec_c); + } + + if (config->rti.uec_d != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(0xffff); + val64 |= VXGE_HW_TIM_CFG2_INT_NUM_UEC_D( + config->rti.uec_d); + } + + writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_RX]); + val64 = readq(&vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]); + + if (config->rti.timer_ri_en != VXGE_HW_USE_FLASH_DEFAULT) { + if (config->rti.timer_ri_en) + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI; + else + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI; + } + + if (config->rti.rtimer_val != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL( + 0x3ffffff); + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL( + config->rti.rtimer_val); + } + + if (config->rti.util_sel != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(0x3f); + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL( + config->rti.util_sel); + } + + if (config->rti.ltimer_val != VXGE_HW_USE_FLASH_DEFAULT) { + val64 &= ~VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL( + 0x3ffffff); + val64 |= VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL( + config->rti.ltimer_val); + } + + writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_RX]); + } + + val64 = 0; + writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_EINTA]); + writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_EINTA]); + writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_EINTA]); + writeq(val64, &vp_reg->tim_cfg1_int_num[VXGE_HW_VPATH_INTR_BMAP]); + writeq(val64, &vp_reg->tim_cfg2_int_num[VXGE_HW_VPATH_INTR_BMAP]); + writeq(val64, &vp_reg->tim_cfg3_int_num[VXGE_HW_VPATH_INTR_BMAP]); + + return status; +} + +/* + * __vxge_hw_vpath_initialize + * This routine is the final phase of init which initializes the + * registers of the vpath using the configuration passed. + */ +enum vxge_hw_status +__vxge_hw_vpath_initialize(struct __vxge_hw_device *hldev, u32 vp_id) +{ + u64 val64; + u32 val32; + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_virtualpath *vpath; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + vpath = &hldev->virtual_paths[vp_id]; + + if (!(hldev->vpath_assignments & vxge_mBIT(vp_id))) { + status = VXGE_HW_ERR_VPATH_NOT_AVAILABLE; + goto exit; + } + vp_reg = vpath->vp_reg; + + status = __vxge_hw_vpath_swapper_set(vpath->vp_reg); + + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_mac_configure(hldev, vp_id); + + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_kdfc_configure(hldev, vp_id); + + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_tim_configure(hldev, vp_id); + + if (status != VXGE_HW_OK) + goto exit; + + writeq(0, &vp_reg->gendma_int); + + val64 = readq(&vp_reg->rtdma_rd_optimization_ctrl); + + /* Get MRRS value from device control */ + status = __vxge_hw_vpath_pci_read(vpath, 1, 0x78, &val32); + + if (status == VXGE_HW_OK) { + val32 = (val32 & VXGE_HW_PCI_EXP_DEVCTL_READRQ) >> 12; + val64 &= + ~(VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(7)); + val64 |= + VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(val32); + + val64 |= VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_WAIT_FOR_SPACE; + } + + val64 &= ~(VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(7)); + val64 |= + VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY( + VXGE_HW_MAX_PAYLOAD_SIZE_512); + + val64 |= VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY_EN; + writeq(val64, &vp_reg->rtdma_rd_optimization_ctrl); + +exit: + return status; +} + +/* + * __vxge_hw_vp_initialize - Initialize Virtual Path structure + * This routine is the initial phase of init which resets the vpath and + * initializes the software support structures. + */ +enum vxge_hw_status +__vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id, + struct vxge_hw_vp_config *config) +{ + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status = VXGE_HW_OK; + + if (!(hldev->vpath_assignments & vxge_mBIT(vp_id))) { + status = VXGE_HW_ERR_VPATH_NOT_AVAILABLE; + goto exit; + } + + vpath = &hldev->virtual_paths[vp_id]; + + vpath->vp_id = vp_id; + vpath->vp_open = VXGE_HW_VP_OPEN; + vpath->hldev = hldev; + vpath->vp_config = config; + vpath->vp_reg = hldev->vpath_reg[vp_id]; + vpath->vpmgmt_reg = hldev->vpmgmt_reg[vp_id]; + + __vxge_hw_vpath_reset(hldev, vp_id); + + status = __vxge_hw_vpath_reset_check(vpath); + + if (status != VXGE_HW_OK) { + memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); + goto exit; + } + + status = __vxge_hw_vpath_mgmt_read(hldev, vpath); + + if (status != VXGE_HW_OK) { + memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); + goto exit; + } + + INIT_LIST_HEAD(&vpath->vpath_handles); + + vpath->sw_stats = &hldev->stats.sw_dev_info_stats.vpath_info[vp_id]; + + VXGE_HW_DEVICE_TIM_INT_MASK_SET(hldev->tim_int_mask0, + hldev->tim_int_mask1, vp_id); + + status = __vxge_hw_vpath_initialize(hldev, vp_id); + + if (status != VXGE_HW_OK) + __vxge_hw_vp_terminate(hldev, vp_id); +exit: + return status; +} + +/* + * __vxge_hw_vp_terminate - Terminate Virtual Path structure + * This routine closes all channels it opened and freeup memory + */ +void +__vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id) +{ + struct __vxge_hw_virtualpath *vpath; + + vpath = &hldev->virtual_paths[vp_id]; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) + goto exit; + + VXGE_HW_DEVICE_TIM_INT_MASK_RESET(vpath->hldev->tim_int_mask0, + vpath->hldev->tim_int_mask1, vpath->vp_id); + hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL; + + memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); +exit: + return; +} + +/* + * vxge_hw_vpath_mtu_set - Set MTU. + * Set new MTU value. Example, to use jumbo frames: + * vxge_hw_vpath_mtu_set(my_device, 9600); + */ +enum vxge_hw_status +vxge_hw_vpath_mtu_set(struct __vxge_hw_vpath_handle *vp, u32 new_mtu) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_virtualpath *vpath; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + vpath = vp->vpath; + + new_mtu += VXGE_HW_MAC_HEADER_MAX_SIZE; + + if ((new_mtu < VXGE_HW_MIN_MTU) || (new_mtu > vpath->max_mtu)) + status = VXGE_HW_ERR_INVALID_MTU_SIZE; + + val64 = readq(&vpath->vp_reg->rxmac_vcfg0); + + val64 &= ~VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(0x3fff); + val64 |= VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(new_mtu); + + writeq(val64, &vpath->vp_reg->rxmac_vcfg0); + + vpath->vp_config->mtu = new_mtu - VXGE_HW_MAC_HEADER_MAX_SIZE; + +exit: + return status; +} + +/* + * vxge_hw_vpath_open - Open a virtual path on a given adapter + * This function is used to open access to virtual path of an + * adapter for offload, GRO operations. This function returns + * synchronously. + */ +enum vxge_hw_status +vxge_hw_vpath_open(struct __vxge_hw_device *hldev, + struct vxge_hw_vpath_attr *attr, + struct __vxge_hw_vpath_handle **vpath_handle) +{ + struct __vxge_hw_virtualpath *vpath; + struct __vxge_hw_vpath_handle *vp; + enum vxge_hw_status status; + + vpath = &hldev->virtual_paths[attr->vp_id]; + + if (vpath->vp_open == VXGE_HW_VP_OPEN) { + status = VXGE_HW_ERR_INVALID_STATE; + goto vpath_open_exit1; + } + + status = __vxge_hw_vp_initialize(hldev, attr->vp_id, + &hldev->config.vp_config[attr->vp_id]); + + if (status != VXGE_HW_OK) + goto vpath_open_exit1; + + vp = (struct __vxge_hw_vpath_handle *) + vmalloc(sizeof(struct __vxge_hw_vpath_handle)); + if (vp == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto vpath_open_exit2; + } + + memset(vp, 0, sizeof(struct __vxge_hw_vpath_handle)); + + vp->vpath = vpath; + + if (vpath->vp_config->fifo.enable == VXGE_HW_FIFO_ENABLE) { + status = __vxge_hw_fifo_create(vp, &attr->fifo_attr); + if (status != VXGE_HW_OK) + goto vpath_open_exit6; + } + + if (vpath->vp_config->ring.enable == VXGE_HW_RING_ENABLE) { + status = __vxge_hw_ring_create(vp, &attr->ring_attr); + if (status != VXGE_HW_OK) + goto vpath_open_exit7; + + __vxge_hw_vpath_prc_configure(hldev, attr->vp_id); + } + + vpath->fifoh->tx_intr_num = + (attr->vp_id * VXGE_HW_MAX_INTR_PER_VP) + + VXGE_HW_VPATH_INTR_TX; + + vpath->stats_block = __vxge_hw_blockpool_block_allocate(hldev, + VXGE_HW_BLOCK_SIZE); + + if (vpath->stats_block == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto vpath_open_exit8; + } + + vpath->hw_stats = (struct vxge_hw_vpath_stats_hw_info *)vpath-> + stats_block->memblock; + memset(vpath->hw_stats, 0, + sizeof(struct vxge_hw_vpath_stats_hw_info)); + + hldev->stats.hw_dev_info_stats.vpath_info[attr->vp_id] = + vpath->hw_stats; + + vpath->hw_stats_sav = + &hldev->stats.hw_dev_info_stats.vpath_info_sav[attr->vp_id]; + memset(vpath->hw_stats_sav, 0, + sizeof(struct vxge_hw_vpath_stats_hw_info)); + + writeq(vpath->stats_block->dma_addr, &vpath->vp_reg->stats_cfg); + + status = vxge_hw_vpath_stats_enable(vp); + if (status != VXGE_HW_OK) + goto vpath_open_exit8; + + list_add(&vp->item, &vpath->vpath_handles); + + hldev->vpaths_deployed |= vxge_mBIT(vpath->vp_id); + + *vpath_handle = vp; + + attr->fifo_attr.userdata = vpath->fifoh; + attr->ring_attr.userdata = vpath->ringh; + + return VXGE_HW_OK; + +vpath_open_exit8: + if (vpath->ringh != NULL) + __vxge_hw_ring_delete(vp); +vpath_open_exit7: + if (vpath->fifoh != NULL) + __vxge_hw_fifo_delete(vp); +vpath_open_exit6: + vfree(vp); +vpath_open_exit2: + __vxge_hw_vp_terminate(hldev, attr->vp_id); +vpath_open_exit1: + + return status; +} + +/** + * vxge_hw_vpath_rx_doorbell_post - Close the handle got from previous vpath + * (vpath) open + * @vp: Handle got from previous vpath open + * + * This function is used to close access to virtual path opened + * earlier. + */ +void +vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp) +{ + struct __vxge_hw_virtualpath *vpath = NULL; + u64 new_count, val64, val164; + struct __vxge_hw_ring *ring; + + vpath = vp->vpath; + ring = vpath->ringh; + + new_count = readq(&vpath->vp_reg->rxdmem_size); + new_count &= 0x1fff; + val164 = (VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(new_count)); + + writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val164), + &vpath->vp_reg->prc_rxd_doorbell); + readl(&vpath->vp_reg->prc_rxd_doorbell); + + val164 /= 2; + val64 = readq(&vpath->vp_reg->prc_cfg6); + val64 = VXGE_HW_PRC_CFG6_RXD_SPAT(val64); + val64 &= 0x1ff; + + /* + * Each RxD is of 4 qwords + */ + new_count -= (val64 + 1); + val64 = min(val164, new_count) / 4; + + ring->rxds_limit = min(ring->rxds_limit, val64); + if (ring->rxds_limit < 4) + ring->rxds_limit = 4; +} + +/* + * vxge_hw_vpath_close - Close the handle got from previous vpath (vpath) open + * This function is used to close access to virtual path opened + * earlier. + */ +enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp) +{ + struct __vxge_hw_virtualpath *vpath = NULL; + struct __vxge_hw_device *devh = NULL; + u32 vp_id = vp->vpath->vp_id; + u32 is_empty = TRUE; + enum vxge_hw_status status = VXGE_HW_OK; + + vpath = vp->vpath; + devh = vpath->hldev; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto vpath_close_exit; + } + + list_del(&vp->item); + + if (!list_empty(&vpath->vpath_handles)) { + list_add(&vp->item, &vpath->vpath_handles); + is_empty = FALSE; + } + + if (!is_empty) { + status = VXGE_HW_FAIL; + goto vpath_close_exit; + } + + devh->vpaths_deployed &= ~vxge_mBIT(vp_id); + + if (vpath->ringh != NULL) + __vxge_hw_ring_delete(vp); + + if (vpath->fifoh != NULL) + __vxge_hw_fifo_delete(vp); + + if (vpath->stats_block != NULL) + __vxge_hw_blockpool_block_free(devh, vpath->stats_block); + + vfree(vp); + + __vxge_hw_vp_terminate(devh, vp_id); + + vpath->vp_open = VXGE_HW_VP_NOT_OPEN; + +vpath_close_exit: + return status; +} + +/* + * vxge_hw_vpath_reset - Resets vpath + * This function is used to request a reset of vpath + */ +enum vxge_hw_status vxge_hw_vpath_reset(struct __vxge_hw_vpath_handle *vp) +{ + enum vxge_hw_status status; + u32 vp_id; + struct __vxge_hw_virtualpath *vpath = vp->vpath; + + vp_id = vpath->vp_id; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto exit; + } + + status = __vxge_hw_vpath_reset(vpath->hldev, vp_id); + if (status == VXGE_HW_OK) + vpath->sw_stats->soft_reset_cnt++; +exit: + return status; +} + +/* + * vxge_hw_vpath_recover_from_reset - Poll for reset complete and re-initialize. + * This function poll's for the vpath reset completion and re initializes + * the vpath. + */ +enum vxge_hw_status +vxge_hw_vpath_recover_from_reset(struct __vxge_hw_vpath_handle *vp) +{ + struct __vxge_hw_virtualpath *vpath = NULL; + enum vxge_hw_status status; + struct __vxge_hw_device *hldev; + u32 vp_id; + + vp_id = vp->vpath->vp_id; + vpath = vp->vpath; + hldev = vpath->hldev; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto exit; + } + + status = __vxge_hw_vpath_reset_check(vpath); + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_sw_reset(hldev, vp_id); + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_initialize(hldev, vp_id); + if (status != VXGE_HW_OK) + goto exit; + + if (vpath->ringh != NULL) + __vxge_hw_vpath_prc_configure(hldev, vp_id); + + memset(vpath->hw_stats, 0, + sizeof(struct vxge_hw_vpath_stats_hw_info)); + + memset(vpath->hw_stats_sav, 0, + sizeof(struct vxge_hw_vpath_stats_hw_info)); + + writeq(vpath->stats_block->dma_addr, + &vpath->vp_reg->stats_cfg); + + status = vxge_hw_vpath_stats_enable(vp); + +exit: + return status; +} + +/* + * vxge_hw_vpath_enable - Enable vpath. + * This routine clears the vpath reset thereby enabling a vpath + * to start forwarding frames and generating interrupts. + */ +void +vxge_hw_vpath_enable(struct __vxge_hw_vpath_handle *vp) +{ + struct __vxge_hw_device *hldev; + u64 val64; + + hldev = vp->vpath->hldev; + + val64 = VXGE_HW_CMN_RSTHDLR_CFG1_CLR_VPATH_RESET( + 1 << (16 - vp->vpath->vp_id)); + + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), + &hldev->common_reg->cmn_rsthdlr_cfg1); +} + +/* + * vxge_hw_vpath_stats_enable - Enable vpath h/wstatistics. + * Enable the DMA vpath statistics. The function is to be called to re-enable + * the adapter to update stats into the host memory + */ +enum vxge_hw_status +vxge_hw_vpath_stats_enable(struct __vxge_hw_vpath_handle *vp) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_virtualpath *vpath; + + vpath = vp->vpath; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto exit; + } + + memcpy(vpath->hw_stats_sav, vpath->hw_stats, + sizeof(struct vxge_hw_vpath_stats_hw_info)); + + status = __vxge_hw_vpath_stats_get(vpath, vpath->hw_stats); +exit: + return status; +} + +/* + * __vxge_hw_vpath_stats_access - Get the statistics from the given location + * and offset and perform an operation + */ +enum vxge_hw_status +__vxge_hw_vpath_stats_access(struct __vxge_hw_virtualpath *vpath, + u32 operation, u32 offset, u64 *stat) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto vpath_stats_access_exit; + } + + vp_reg = vpath->vp_reg; + + val64 = VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(operation) | + VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE | + VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(offset); + + status = __vxge_hw_pio_mem_write64(val64, + &vp_reg->xmac_stats_access_cmd, + VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE, + vpath->hldev->config.device_poll_millis); + + if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ)) + *stat = readq(&vp_reg->xmac_stats_access_data); + else + *stat = 0; + +vpath_stats_access_exit: + return status; +} + +/* + * __vxge_hw_vpath_xmac_tx_stats_get - Get the TX Statistics of a vpath + */ +enum vxge_hw_status +__vxge_hw_vpath_xmac_tx_stats_get( + struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats) +{ + u64 *val64; + int i; + u32 offset = VXGE_HW_STATS_VPATH_TX_OFFSET; + enum vxge_hw_status status = VXGE_HW_OK; + + val64 = (u64 *) vpath_tx_stats; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto exit; + } + + for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_tx_stats) / 8; i++) { + status = __vxge_hw_vpath_stats_access(vpath, + VXGE_HW_STATS_OP_READ, + offset, val64); + if (status != VXGE_HW_OK) + goto exit; + offset++; + val64++; + } +exit: + return status; +} + +/* + * __vxge_hw_vpath_xmac_rx_stats_get - Get the RX Statistics of a vpath + */ +enum vxge_hw_status +__vxge_hw_vpath_xmac_rx_stats_get(struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats) +{ + u64 *val64; + enum vxge_hw_status status = VXGE_HW_OK; + int i; + u32 offset = VXGE_HW_STATS_VPATH_RX_OFFSET; + val64 = (u64 *) vpath_rx_stats; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto exit; + } + for (i = 0; i < sizeof(struct vxge_hw_xmac_vpath_rx_stats) / 8; i++) { + status = __vxge_hw_vpath_stats_access(vpath, + VXGE_HW_STATS_OP_READ, + offset >> 3, val64); + if (status != VXGE_HW_OK) + goto exit; + + offset += 8; + val64++; + } +exit: + return status; +} + +/* + * __vxge_hw_vpath_stats_get - Get the vpath hw statistics. + */ +enum vxge_hw_status __vxge_hw_vpath_stats_get( + struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_vpath_stats_hw_info *hw_stats) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto exit; + } + vp_reg = vpath->vp_reg; + + val64 = readq(&vp_reg->vpath_debug_stats0); + hw_stats->ini_num_mwr_sent = + (u32)VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(val64); + + val64 = readq(&vp_reg->vpath_debug_stats1); + hw_stats->ini_num_mrd_sent = + (u32)VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(val64); + + val64 = readq(&vp_reg->vpath_debug_stats2); + hw_stats->ini_num_cpl_rcvd = + (u32)VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(val64); + + val64 = readq(&vp_reg->vpath_debug_stats3); + hw_stats->ini_num_mwr_byte_sent = + VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(val64); + + val64 = readq(&vp_reg->vpath_debug_stats4); + hw_stats->ini_num_cpl_byte_rcvd = + VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(val64); + + val64 = readq(&vp_reg->vpath_debug_stats5); + hw_stats->wrcrdtarb_xoff = + (u32)VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(val64); + + val64 = readq(&vp_reg->vpath_debug_stats6); + hw_stats->rdcrdtarb_xoff = + (u32)VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(val64); + + val64 = readq(&vp_reg->vpath_genstats_count01); + hw_stats->vpath_genstats_count0 = + (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0( + val64); + + val64 = readq(&vp_reg->vpath_genstats_count01); + hw_stats->vpath_genstats_count1 = + (u32)VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1( + val64); + + val64 = readq(&vp_reg->vpath_genstats_count23); + hw_stats->vpath_genstats_count2 = + (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2( + val64); + + val64 = readq(&vp_reg->vpath_genstats_count01); + hw_stats->vpath_genstats_count3 = + (u32)VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3( + val64); + + val64 = readq(&vp_reg->vpath_genstats_count4); + hw_stats->vpath_genstats_count4 = + (u32)VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4( + val64); + + val64 = readq(&vp_reg->vpath_genstats_count5); + hw_stats->vpath_genstats_count5 = + (u32)VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5( + val64); + + status = __vxge_hw_vpath_xmac_tx_stats_get(vpath, &hw_stats->tx_stats); + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_xmac_rx_stats_get(vpath, &hw_stats->rx_stats); + if (status != VXGE_HW_OK) + goto exit; + + VXGE_HW_VPATH_STATS_PIO_READ( + VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM0_OFFSET); + + hw_stats->prog_event_vnum0 = + (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM0(val64); + + hw_stats->prog_event_vnum1 = + (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM1(val64); + + VXGE_HW_VPATH_STATS_PIO_READ( + VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM2_OFFSET); + + hw_stats->prog_event_vnum2 = + (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM2(val64); + + hw_stats->prog_event_vnum3 = + (u32)VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM3(val64); + + val64 = readq(&vp_reg->rx_multi_cast_stats); + hw_stats->rx_multi_cast_frame_discard = + (u16)VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(val64); + + val64 = readq(&vp_reg->rx_frm_transferred); + hw_stats->rx_frm_transferred = + (u32)VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(val64); + + val64 = readq(&vp_reg->rxd_returned); + hw_stats->rxd_returned = + (u16)VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(val64); + + val64 = readq(&vp_reg->dbg_stats_rx_mpa); + hw_stats->rx_mpa_len_fail_frms = + (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(val64); + hw_stats->rx_mpa_mrk_fail_frms = + (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(val64); + hw_stats->rx_mpa_crc_fail_frms = + (u16)VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(val64); + + val64 = readq(&vp_reg->dbg_stats_rx_fau); + hw_stats->rx_permitted_frms = + (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(val64); + hw_stats->rx_vp_reset_discarded_frms = + (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val64); + hw_stats->rx_wol_frms = + (u16)VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(val64); + + val64 = readq(&vp_reg->tx_vp_reset_discarded_frms); + hw_stats->tx_vp_reset_discarded_frms = + (u16)VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS( + val64); +exit: + return status; +} + +/* + * __vxge_hw_blockpool_create - Create block pool + */ + +enum vxge_hw_status +__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev, + struct __vxge_hw_blockpool *blockpool, + u32 pool_size, + u32 pool_max) +{ + u32 i; + struct __vxge_hw_blockpool_entry *entry = NULL; + void *memblock; + dma_addr_t dma_addr; + struct pci_dev *dma_handle; + struct pci_dev *acc_handle; + enum vxge_hw_status status = VXGE_HW_OK; + + if (blockpool == NULL) { + status = VXGE_HW_FAIL; + goto blockpool_create_exit; + } + + blockpool->hldev = hldev; + blockpool->block_size = VXGE_HW_BLOCK_SIZE; + blockpool->pool_size = 0; + blockpool->pool_max = pool_max; + blockpool->req_out = 0; + + INIT_LIST_HEAD(&blockpool->free_block_list); + INIT_LIST_HEAD(&blockpool->free_entry_list); + + for (i = 0; i < pool_size + pool_max; i++) { + entry = kzalloc(sizeof(struct __vxge_hw_blockpool_entry), + GFP_KERNEL); + if (entry == NULL) { + __vxge_hw_blockpool_destroy(blockpool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto blockpool_create_exit; + } + list_add(&entry->item, &blockpool->free_entry_list); + } + + for (i = 0; i < pool_size; i++) { + + memblock = vxge_os_dma_malloc( + hldev->pdev, + VXGE_HW_BLOCK_SIZE, + &dma_handle, + &acc_handle); + + if (memblock == NULL) { + __vxge_hw_blockpool_destroy(blockpool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto blockpool_create_exit; + } + + dma_addr = pci_map_single(hldev->pdev, memblock, + VXGE_HW_BLOCK_SIZE, PCI_DMA_BIDIRECTIONAL); + + if (unlikely(pci_dma_mapping_error(hldev->pdev, + dma_addr))) { + + vxge_os_dma_free(hldev->pdev, memblock, &acc_handle); + __vxge_hw_blockpool_destroy(blockpool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto blockpool_create_exit; + } + + if (!list_empty(&blockpool->free_entry_list)) + entry = (struct __vxge_hw_blockpool_entry *) + list_first_entry(&blockpool->free_entry_list, + struct __vxge_hw_blockpool_entry, + item); + + if (entry == NULL) + entry = + kzalloc(sizeof(struct __vxge_hw_blockpool_entry), + GFP_KERNEL); + if (entry != NULL) { + list_del(&entry->item); + entry->length = VXGE_HW_BLOCK_SIZE; + entry->memblock = memblock; + entry->dma_addr = dma_addr; + entry->acc_handle = acc_handle; + entry->dma_handle = dma_handle; + list_add(&entry->item, + &blockpool->free_block_list); + blockpool->pool_size++; + } else { + __vxge_hw_blockpool_destroy(blockpool); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto blockpool_create_exit; + } + } + +blockpool_create_exit: + return status; +} + +/* + * __vxge_hw_blockpool_destroy - Deallocates the block pool + */ + +void __vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool) +{ + + struct __vxge_hw_device *hldev; + struct list_head *p, *n; + u16 ret; + + if (blockpool == NULL) { + ret = 1; + goto exit; + } + + hldev = blockpool->hldev; + + list_for_each_safe(p, n, &blockpool->free_block_list) { + + pci_unmap_single(hldev->pdev, + ((struct __vxge_hw_blockpool_entry *)p)->dma_addr, + ((struct __vxge_hw_blockpool_entry *)p)->length, + PCI_DMA_BIDIRECTIONAL); + + vxge_os_dma_free(hldev->pdev, + ((struct __vxge_hw_blockpool_entry *)p)->memblock, + &((struct __vxge_hw_blockpool_entry *) p)->acc_handle); + + list_del( + &((struct __vxge_hw_blockpool_entry *)p)->item); + kfree(p); + blockpool->pool_size--; + } + + list_for_each_safe(p, n, &blockpool->free_entry_list) { + list_del( + &((struct __vxge_hw_blockpool_entry *)p)->item); + kfree((void *)p); + } + ret = 0; +exit: + return; +} + +/* + * __vxge_hw_blockpool_blocks_add - Request additional blocks + */ +static +void __vxge_hw_blockpool_blocks_add(struct __vxge_hw_blockpool *blockpool) +{ + u32 nreq = 0, i; + + if ((blockpool->pool_size + blockpool->req_out) < + VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE) { + nreq = VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE; + blockpool->req_out += nreq; + } + + for (i = 0; i < nreq; i++) + vxge_os_dma_malloc_async( + ((struct __vxge_hw_device *)blockpool->hldev)->pdev, + blockpool->hldev, VXGE_HW_BLOCK_SIZE); +} + +/* + * __vxge_hw_blockpool_blocks_remove - Free additional blocks + */ +static +void __vxge_hw_blockpool_blocks_remove(struct __vxge_hw_blockpool *blockpool) +{ + struct list_head *p, *n; + + list_for_each_safe(p, n, &blockpool->free_block_list) { + + if (blockpool->pool_size < blockpool->pool_max) + break; + + pci_unmap_single( + ((struct __vxge_hw_device *)blockpool->hldev)->pdev, + ((struct __vxge_hw_blockpool_entry *)p)->dma_addr, + ((struct __vxge_hw_blockpool_entry *)p)->length, + PCI_DMA_BIDIRECTIONAL); + + vxge_os_dma_free( + ((struct __vxge_hw_device *)blockpool->hldev)->pdev, + ((struct __vxge_hw_blockpool_entry *)p)->memblock, + &((struct __vxge_hw_blockpool_entry *)p)->acc_handle); + + list_del(&((struct __vxge_hw_blockpool_entry *)p)->item); + + list_add(p, &blockpool->free_entry_list); + + blockpool->pool_size--; + + } +} + +/* + * vxge_hw_blockpool_block_add - callback for vxge_os_dma_malloc_async + * Adds a block to block pool + */ +void vxge_hw_blockpool_block_add( + struct __vxge_hw_device *devh, + void *block_addr, + u32 length, + struct pci_dev *dma_h, + struct pci_dev *acc_handle) +{ + struct __vxge_hw_blockpool *blockpool; + struct __vxge_hw_blockpool_entry *entry = NULL; + dma_addr_t dma_addr; + enum vxge_hw_status status = VXGE_HW_OK; + u32 req_out; + + blockpool = &devh->block_pool; + + if (block_addr == NULL) { + blockpool->req_out--; + status = VXGE_HW_FAIL; + goto exit; + } + + dma_addr = pci_map_single(devh->pdev, block_addr, length, + PCI_DMA_BIDIRECTIONAL); + + if (unlikely(pci_dma_mapping_error(devh->pdev, dma_addr))) { + + vxge_os_dma_free(devh->pdev, block_addr, &acc_handle); + blockpool->req_out--; + status = VXGE_HW_FAIL; + goto exit; + } + + + if (!list_empty(&blockpool->free_entry_list)) + entry = (struct __vxge_hw_blockpool_entry *) + list_first_entry(&blockpool->free_entry_list, + struct __vxge_hw_blockpool_entry, + item); + + if (entry == NULL) + entry = (struct __vxge_hw_blockpool_entry *) + vmalloc(sizeof(struct __vxge_hw_blockpool_entry)); + else + list_del(&entry->item); + + if (entry != NULL) { + entry->length = length; + entry->memblock = block_addr; + entry->dma_addr = dma_addr; + entry->acc_handle = acc_handle; + entry->dma_handle = dma_h; + list_add(&entry->item, &blockpool->free_block_list); + blockpool->pool_size++; + status = VXGE_HW_OK; + } else + status = VXGE_HW_ERR_OUT_OF_MEMORY; + + blockpool->req_out--; + + req_out = blockpool->req_out; +exit: + return; +} + +/* + * __vxge_hw_blockpool_malloc - Allocate a memory block from pool + * Allocates a block of memory of given size, either from block pool + * or by calling vxge_os_dma_malloc() + */ +void * +__vxge_hw_blockpool_malloc(struct __vxge_hw_device *devh, u32 size, + struct vxge_hw_mempool_dma *dma_object) +{ + struct __vxge_hw_blockpool_entry *entry = NULL; + struct __vxge_hw_blockpool *blockpool; + void *memblock = NULL; + enum vxge_hw_status status = VXGE_HW_OK; + + blockpool = &devh->block_pool; + + if (size != blockpool->block_size) { + + memblock = vxge_os_dma_malloc(devh->pdev, size, + &dma_object->handle, + &dma_object->acc_handle); + + if (memblock == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + dma_object->addr = pci_map_single(devh->pdev, memblock, size, + PCI_DMA_BIDIRECTIONAL); + + if (unlikely(pci_dma_mapping_error(devh->pdev, + dma_object->addr))) { + vxge_os_dma_free(devh->pdev, memblock, + &dma_object->acc_handle); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + } else { + + if (!list_empty(&blockpool->free_block_list)) + entry = (struct __vxge_hw_blockpool_entry *) + list_first_entry(&blockpool->free_block_list, + struct __vxge_hw_blockpool_entry, + item); + + if (entry != NULL) { + list_del(&entry->item); + dma_object->addr = entry->dma_addr; + dma_object->handle = entry->dma_handle; + dma_object->acc_handle = entry->acc_handle; + memblock = entry->memblock; + + list_add(&entry->item, + &blockpool->free_entry_list); + blockpool->pool_size--; + } + + if (memblock != NULL) + __vxge_hw_blockpool_blocks_add(blockpool); + } +exit: + return memblock; +} + +/* + * __vxge_hw_blockpool_free - Frees the memory allcoated with + __vxge_hw_blockpool_malloc + */ +void +__vxge_hw_blockpool_free(struct __vxge_hw_device *devh, + void *memblock, u32 size, + struct vxge_hw_mempool_dma *dma_object) +{ + struct __vxge_hw_blockpool_entry *entry = NULL; + struct __vxge_hw_blockpool *blockpool; + enum vxge_hw_status status = VXGE_HW_OK; + + blockpool = &devh->block_pool; + + if (size != blockpool->block_size) { + pci_unmap_single(devh->pdev, dma_object->addr, size, + PCI_DMA_BIDIRECTIONAL); + vxge_os_dma_free(devh->pdev, memblock, &dma_object->acc_handle); + } else { + + if (!list_empty(&blockpool->free_entry_list)) + entry = (struct __vxge_hw_blockpool_entry *) + list_first_entry(&blockpool->free_entry_list, + struct __vxge_hw_blockpool_entry, + item); + + if (entry == NULL) + entry = (struct __vxge_hw_blockpool_entry *) + vmalloc(sizeof( + struct __vxge_hw_blockpool_entry)); + else + list_del(&entry->item); + + if (entry != NULL) { + entry->length = size; + entry->memblock = memblock; + entry->dma_addr = dma_object->addr; + entry->acc_handle = dma_object->acc_handle; + entry->dma_handle = dma_object->handle; + list_add(&entry->item, + &blockpool->free_block_list); + blockpool->pool_size++; + status = VXGE_HW_OK; + } else + status = VXGE_HW_ERR_OUT_OF_MEMORY; + + if (status == VXGE_HW_OK) + __vxge_hw_blockpool_blocks_remove(blockpool); + } + + return; +} + +/* + * __vxge_hw_blockpool_block_allocate - Allocates a block from block pool + * This function allocates a block from block pool or from the system + */ +struct __vxge_hw_blockpool_entry * +__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *devh, u32 size) +{ + struct __vxge_hw_blockpool_entry *entry = NULL; + struct __vxge_hw_blockpool *blockpool; + + blockpool = &devh->block_pool; + + if (size == blockpool->block_size) { + + if (!list_empty(&blockpool->free_block_list)) + entry = (struct __vxge_hw_blockpool_entry *) + list_first_entry(&blockpool->free_block_list, + struct __vxge_hw_blockpool_entry, + item); + + if (entry != NULL) { + list_del(&entry->item); + blockpool->pool_size--; + } + } + + if (entry != NULL) + __vxge_hw_blockpool_blocks_add(blockpool); + + return entry; +} + +/* + * __vxge_hw_blockpool_block_free - Frees a block from block pool + * @devh: Hal device + * @entry: Entry of block to be freed + * + * This function frees a block from block pool + */ +void +__vxge_hw_blockpool_block_free(struct __vxge_hw_device *devh, + struct __vxge_hw_blockpool_entry *entry) +{ + struct __vxge_hw_blockpool *blockpool; + + blockpool = &devh->block_pool; + + if (entry->length == blockpool->block_size) { + list_add(&entry->item, &blockpool->free_block_list); + blockpool->pool_size++; + } + + __vxge_hw_blockpool_blocks_remove(blockpool); + + return; +} diff --git a/trunk/drivers/net/vxge/vxge-config.h b/trunk/drivers/net/vxge/vxge-config.h new file mode 100644 index 000000000000..afbdf6f4d224 --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-config.h @@ -0,0 +1,2259 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-config.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#ifndef VXGE_CONFIG_H +#define VXGE_CONFIG_H +#include + +#ifndef VXGE_CACHE_LINE_SIZE +#define VXGE_CACHE_LINE_SIZE 128 +#endif + +#define vxge_os_vaprintf(level, mask, fmt, ...) { \ + char buff[255]; \ + snprintf(buff, 255, fmt, __VA_ARGS__); \ + printk(buff); \ + printk("\n"); \ +} + +#ifndef VXGE_ALIGN +#define VXGE_ALIGN(adrs, size) \ + (((size) - (((u64)adrs) & ((size)-1))) & ((size)-1)) +#endif + +#define VXGE_HW_MIN_MTU 68 +#define VXGE_HW_MAX_MTU 9600 +#define VXGE_HW_DEFAULT_MTU 1500 + +#ifdef VXGE_DEBUG_ASSERT + +/** + * vxge_assert + * @test: C-condition to check + * @fmt: printf like format string + * + * This function implements traditional assert. By default assertions + * are enabled. It can be disabled by undefining VXGE_DEBUG_ASSERT macro in + * compilation + * time. + */ +#define vxge_assert(test) { \ + if (!(test)) \ + vxge_os_bug("bad cond: "#test" at %s:%d\n", \ + __FILE__, __LINE__); } +#else +#define vxge_assert(test) +#endif /* end of VXGE_DEBUG_ASSERT */ + +/** + * enum enum vxge_debug_level + * @VXGE_NONE: debug disabled + * @VXGE_ERR: all errors going to be logged out + * @VXGE_TRACE: all errors plus all kind of verbose tracing print outs + * going to be logged out. Very noisy. + * + * This enumeration going to be used to switch between different + * debug levels during runtime if DEBUG macro defined during + * compilation. If DEBUG macro not defined than code will be + * compiled out. + */ +enum vxge_debug_level { + VXGE_NONE = 0, + VXGE_TRACE = 1, + VXGE_ERR = 2 +}; + +#define NULL_VPID 0xFFFFFFFF +#ifdef CONFIG_VXGE_DEBUG_TRACE_ALL +#define VXGE_DEBUG_MODULE_MASK 0xffffffff +#define VXGE_DEBUG_TRACE_MASK 0xffffffff +#define VXGE_DEBUG_ERR_MASK 0xffffffff +#define VXGE_DEBUG_MASK 0x000001ff +#else +#define VXGE_DEBUG_MODULE_MASK 0x20000000 +#define VXGE_DEBUG_TRACE_MASK 0x20000000 +#define VXGE_DEBUG_ERR_MASK 0x20000000 +#define VXGE_DEBUG_MASK 0x00000001 +#endif + +/* + * @VXGE_COMPONENT_LL: do debug for vxge link layer module + * @VXGE_COMPONENT_ALL: activate debug for all modules with no exceptions + * + * This enumeration going to be used to distinguish modules + * or libraries during compilation and runtime. Makefile must declare + * VXGE_DEBUG_MODULE_MASK macro and set it to proper value. + */ +#define VXGE_COMPONENT_LL 0x20000000 +#define VXGE_COMPONENT_ALL 0xffffffff + +#define VXGE_HW_BASE_INF 100 +#define VXGE_HW_BASE_ERR 200 +#define VXGE_HW_BASE_BADCFG 300 + +enum vxge_hw_status { + VXGE_HW_OK = 0, + VXGE_HW_FAIL = 1, + VXGE_HW_PENDING = 2, + VXGE_HW_COMPLETIONS_REMAIN = 3, + + VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS = VXGE_HW_BASE_INF + 1, + VXGE_HW_INF_OUT_OF_DESCRIPTORS = VXGE_HW_BASE_INF + 2, + + VXGE_HW_ERR_INVALID_HANDLE = VXGE_HW_BASE_ERR + 1, + VXGE_HW_ERR_OUT_OF_MEMORY = VXGE_HW_BASE_ERR + 2, + VXGE_HW_ERR_VPATH_NOT_AVAILABLE = VXGE_HW_BASE_ERR + 3, + VXGE_HW_ERR_VPATH_NOT_OPEN = VXGE_HW_BASE_ERR + 4, + VXGE_HW_ERR_WRONG_IRQ = VXGE_HW_BASE_ERR + 5, + VXGE_HW_ERR_SWAPPER_CTRL = VXGE_HW_BASE_ERR + 6, + VXGE_HW_ERR_INVALID_MTU_SIZE = VXGE_HW_BASE_ERR + 7, + VXGE_HW_ERR_INVALID_INDEX = VXGE_HW_BASE_ERR + 8, + VXGE_HW_ERR_INVALID_TYPE = VXGE_HW_BASE_ERR + 9, + VXGE_HW_ERR_INVALID_OFFSET = VXGE_HW_BASE_ERR + 10, + VXGE_HW_ERR_INVALID_DEVICE = VXGE_HW_BASE_ERR + 11, + VXGE_HW_ERR_VERSION_CONFLICT = VXGE_HW_BASE_ERR + 12, + VXGE_HW_ERR_INVALID_PCI_INFO = VXGE_HW_BASE_ERR + 13, + VXGE_HW_ERR_INVALID_TCODE = VXGE_HW_BASE_ERR + 14, + VXGE_HW_ERR_INVALID_BLOCK_SIZE = VXGE_HW_BASE_ERR + 15, + VXGE_HW_ERR_INVALID_STATE = VXGE_HW_BASE_ERR + 16, + VXGE_HW_ERR_PRIVILAGED_OPEARATION = VXGE_HW_BASE_ERR + 17, + VXGE_HW_ERR_INVALID_PORT = VXGE_HW_BASE_ERR + 18, + VXGE_HW_ERR_FIFO = VXGE_HW_BASE_ERR + 19, + VXGE_HW_ERR_VPATH = VXGE_HW_BASE_ERR + 20, + VXGE_HW_ERR_CRITICAL = VXGE_HW_BASE_ERR + 21, + VXGE_HW_ERR_SLOT_FREEZE = VXGE_HW_BASE_ERR + 22, + + VXGE_HW_BADCFG_RING_INDICATE_MAX_PKTS = VXGE_HW_BASE_BADCFG + 1, + VXGE_HW_BADCFG_FIFO_BLOCKS = VXGE_HW_BASE_BADCFG + 2, + VXGE_HW_BADCFG_VPATH_MTU = VXGE_HW_BASE_BADCFG + 3, + VXGE_HW_BADCFG_VPATH_RPA_STRIP_VLAN_TAG = VXGE_HW_BASE_BADCFG + 4, + VXGE_HW_BADCFG_VPATH_MIN_BANDWIDTH = VXGE_HW_BASE_BADCFG + 5, + VXGE_HW_BADCFG_INTR_MODE = VXGE_HW_BASE_BADCFG + 6, + VXGE_HW_BADCFG_RTS_MAC_EN = VXGE_HW_BASE_BADCFG + 7, + + VXGE_HW_EOF_TRACE_BUF = -1 +}; + +/** + * enum enum vxge_hw_device_link_state - Link state enumeration. + * @VXGE_HW_LINK_NONE: Invalid link state. + * @VXGE_HW_LINK_DOWN: Link is down. + * @VXGE_HW_LINK_UP: Link is up. + * + */ +enum vxge_hw_device_link_state { + VXGE_HW_LINK_NONE, + VXGE_HW_LINK_DOWN, + VXGE_HW_LINK_UP +}; + +/** + * struct vxge_hw_device_date - Date Format + * @day: Day + * @month: Month + * @year: Year + * @date: Date in string format + * + * Structure for returning date + */ + +#define VXGE_HW_FW_STRLEN 32 +struct vxge_hw_device_date { + u32 day; + u32 month; + u32 year; + char date[VXGE_HW_FW_STRLEN]; +}; + +struct vxge_hw_device_version { + u32 major; + u32 minor; + u32 build; + char version[VXGE_HW_FW_STRLEN]; +}; + +u64 +__vxge_hw_vpath_pci_func_mode_get( + u32 vp_id, + struct vxge_hw_vpath_reg __iomem *vpath_reg); + +/** + * struct vxge_hw_fifo_config - Configuration of fifo. + * @enable: Is this fifo to be commissioned + * @fifo_blocks: Numbers of TxDL (that is, lists of Tx descriptors) + * blocks per queue. + * @max_frags: Max number of Tx buffers per TxDL (that is, per single + * transmit operation). + * No more than 256 transmit buffers can be specified. + * @memblock_size: Fifo descriptors are allocated in blocks of @mem_block_size + * bytes. Setting @memblock_size to page size ensures + * by-page allocation of descriptors. 128K bytes is the + * maximum supported block size. + * @alignment_size: per Tx fragment DMA-able memory used to align transmit data + * (e.g., to align on a cache line). + * @intr: Boolean. Use 1 to generate interrupt for each completed TxDL. + * Use 0 otherwise. + * @no_snoop_bits: If non-zero, specifies no-snoop PCI operation, + * which generally improves latency of the host bridge operation + * (see PCI specification). For valid values please refer + * to struct vxge_hw_fifo_config{} in the driver sources. + * Configuration of all Titan fifos. + * Note: Valid (min, max) range for each attribute is specified in the body of + * the struct vxge_hw_fifo_config{} structure. + */ +struct vxge_hw_fifo_config { + u32 enable; +#define VXGE_HW_FIFO_ENABLE 1 +#define VXGE_HW_FIFO_DISABLE 0 + + u32 fifo_blocks; +#define VXGE_HW_MIN_FIFO_BLOCKS 2 +#define VXGE_HW_MAX_FIFO_BLOCKS 128 + + u32 max_frags; +#define VXGE_HW_MIN_FIFO_FRAGS 1 +#define VXGE_HW_MAX_FIFO_FRAGS 256 + + u32 memblock_size; +#define VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE VXGE_HW_BLOCK_SIZE +#define VXGE_HW_MAX_FIFO_MEMBLOCK_SIZE 131072 +#define VXGE_HW_DEF_FIFO_MEMBLOCK_SIZE 8096 + + u32 alignment_size; +#define VXGE_HW_MIN_FIFO_ALIGNMENT_SIZE 0 +#define VXGE_HW_MAX_FIFO_ALIGNMENT_SIZE 65536 +#define VXGE_HW_DEF_FIFO_ALIGNMENT_SIZE VXGE_CACHE_LINE_SIZE + + u32 intr; +#define VXGE_HW_FIFO_QUEUE_INTR_ENABLE 1 +#define VXGE_HW_FIFO_QUEUE_INTR_DISABLE 0 +#define VXGE_HW_FIFO_QUEUE_INTR_DEFAULT 0 + + u32 no_snoop_bits; +#define VXGE_HW_FIFO_NO_SNOOP_DISABLED 0 +#define VXGE_HW_FIFO_NO_SNOOP_TXD 1 +#define VXGE_HW_FIFO_NO_SNOOP_FRM 2 +#define VXGE_HW_FIFO_NO_SNOOP_ALL 3 +#define VXGE_HW_FIFO_NO_SNOOP_DEFAULT 0 + +}; +/** + * struct vxge_hw_ring_config - Ring configurations. + * @enable: Is this ring to be commissioned + * @ring_blocks: Numbers of RxD blocks in the ring + * @buffer_mode: Receive buffer mode (1, 2, 3, or 5); for details please refer + * to Titan User Guide. + * @scatter_mode: Titan supports two receive scatter modes: A and B. + * For details please refer to Titan User Guide. + * @rx_timer_val: The number of 32ns periods that would be counted between two + * timer interrupts. + * @greedy_return: If Set it forces the device to return absolutely all RxD + * that are consumed and still on board when a timer interrupt + * triggers. If Clear, then if the device has already returned + * RxD before current timer interrupt trigerred and after the + * previous timer interrupt triggered, then the device is not + * forced to returned the rest of the consumed RxD that it has + * on board which account for a byte count less than the one + * programmed into PRC_CFG6.RXD_CRXDT field + * @rx_timer_ci: TBD + * @backoff_interval_us: Time (in microseconds), after which Titan + * tries to download RxDs posted by the host. + * Note that the "backoff" does not happen if host posts receive + * descriptors in the timely fashion. + * Ring configuration. + */ +struct vxge_hw_ring_config { + u32 enable; +#define VXGE_HW_RING_ENABLE 1 +#define VXGE_HW_RING_DISABLE 0 +#define VXGE_HW_RING_DEFAULT 1 + + u32 ring_blocks; +#define VXGE_HW_MIN_RING_BLOCKS 1 +#define VXGE_HW_MAX_RING_BLOCKS 128 +#define VXGE_HW_DEF_RING_BLOCKS 2 + + u32 buffer_mode; +#define VXGE_HW_RING_RXD_BUFFER_MODE_1 1 +#define VXGE_HW_RING_RXD_BUFFER_MODE_3 3 +#define VXGE_HW_RING_RXD_BUFFER_MODE_5 5 +#define VXGE_HW_RING_RXD_BUFFER_MODE_DEFAULT 1 + + u32 scatter_mode; +#define VXGE_HW_RING_SCATTER_MODE_A 0 +#define VXGE_HW_RING_SCATTER_MODE_B 1 +#define VXGE_HW_RING_SCATTER_MODE_C 2 +#define VXGE_HW_RING_SCATTER_MODE_USE_FLASH_DEFAULT 0xffffffff + + u64 rxds_limit; +#define VXGE_HW_DEF_RING_RXDS_LIMIT 44 +}; + +/** + * struct vxge_hw_vp_config - Configuration of virtual path + * @vp_id: Virtual Path Id + * @min_bandwidth: Minimum Guaranteed bandwidth + * @ring: See struct vxge_hw_ring_config{}. + * @fifo: See struct vxge_hw_fifo_config{}. + * @tti: Configuration of interrupt associated with Transmit. + * see struct vxge_hw_tim_intr_config(); + * @rti: Configuration of interrupt associated with Receive. + * see struct vxge_hw_tim_intr_config(); + * @mtu: mtu size used on this port. + * @rpa_strip_vlan_tag: Strip VLAN Tag enable/disable. Instructs the device to + * remove the VLAN tag from all received tagged frames that are not + * replicated at the internal L2 switch. + * 0 - Do not strip the VLAN tag. + * 1 - Strip the VLAN tag. Regardless of this setting, VLAN tags are + * always placed into the RxDMA descriptor. + * + * This structure is used by the driver to pass the configuration parameters to + * configure Virtual Path. + */ +struct vxge_hw_vp_config { + u32 vp_id; + +#define VXGE_HW_VPATH_PRIORITY_MIN 0 +#define VXGE_HW_VPATH_PRIORITY_MAX 16 +#define VXGE_HW_VPATH_PRIORITY_DEFAULT 0 + + u32 min_bandwidth; +#define VXGE_HW_VPATH_BANDWIDTH_MIN 0 +#define VXGE_HW_VPATH_BANDWIDTH_MAX 100 +#define VXGE_HW_VPATH_BANDWIDTH_DEFAULT 0 + + struct vxge_hw_ring_config ring; + struct vxge_hw_fifo_config fifo; + struct vxge_hw_tim_intr_config tti; + struct vxge_hw_tim_intr_config rti; + + u32 mtu; +#define VXGE_HW_VPATH_MIN_INITIAL_MTU VXGE_HW_MIN_MTU +#define VXGE_HW_VPATH_MAX_INITIAL_MTU VXGE_HW_MAX_MTU +#define VXGE_HW_VPATH_USE_FLASH_DEFAULT_INITIAL_MTU 0xffffffff + + u32 rpa_strip_vlan_tag; +#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE 1 +#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_DISABLE 0 +#define VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_USE_FLASH_DEFAULT 0xffffffff + +}; +/** + * struct vxge_hw_device_config - Device configuration. + * @dma_blockpool_initial: Initial size of DMA Pool + * @dma_blockpool_max: Maximum blocks in DMA pool + * @intr_mode: Line, or MSI-X interrupt. + * + * @rth_en: Enable Receive Traffic Hashing(RTH) using IT(Indirection Table). + * @rth_it_type: RTH IT table programming type + * @rts_mac_en: Enable Receive Traffic Steering using MAC destination address + * @vp_config: Configuration for virtual paths + * @device_poll_millis: Specify the interval (in mulliseconds) + * to wait for register reads + * + * Titan configuration. + * Contains per-device configuration parameters, including: + * - stats sampling interval, etc. + * + * In addition, struct vxge_hw_device_config{} includes "subordinate" + * configurations, including: + * - fifos and rings; + * - MAC (done at firmware level). + * + * See Titan User Guide for more details. + * Note: Valid (min, max) range for each attribute is specified in the body of + * the struct vxge_hw_device_config{} structure. Please refer to the + * corresponding include file. + * See also: struct vxge_hw_tim_intr_config{}. + */ +struct vxge_hw_device_config { + u32 dma_blockpool_initial; + u32 dma_blockpool_max; +#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0 +#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0 +#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4 +#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096 + +#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2 + + u32 intr_mode; +#define VXGE_HW_INTR_MODE_IRQLINE 0 +#define VXGE_HW_INTR_MODE_MSIX 1 +#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2 + +#define VXGE_HW_INTR_MODE_DEF 0 + + u32 rth_en; +#define VXGE_HW_RTH_DISABLE 0 +#define VXGE_HW_RTH_ENABLE 1 +#define VXGE_HW_RTH_DEFAULT 0 + + u32 rth_it_type; +#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0 +#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1 +#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0 + + u32 rts_mac_en; +#define VXGE_HW_RTS_MAC_DISABLE 0 +#define VXGE_HW_RTS_MAC_ENABLE 1 +#define VXGE_HW_RTS_MAC_DEFAULT 0 + + struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS]; + + u32 device_poll_millis; +#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1 +#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000 +#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000 + +}; + +/** + * function vxge_uld_link_up_f - Link-Up callback provided by driver. + * @devh: HW device handle. + * Link-up notification callback provided by the driver. + * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}. + * + * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_down_f{}, + * vxge_hw_driver_initialize(). + */ + +/** + * function vxge_uld_link_down_f - Link-Down callback provided by + * driver. + * @devh: HW device handle. + * + * Link-Down notification callback provided by the driver. + * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}. + * + * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_up_f{}, + * vxge_hw_driver_initialize(). + */ + +/** + * function vxge_uld_crit_err_f - Critical Error notification callback. + * @devh: HW device handle. + * (typically - at HW device iinitialization time). + * @type: Enumerated hw error, e.g.: double ECC. + * @serr_data: Titan status. + * @ext_data: Extended data. The contents depends on the @type. + * + * Link-Down notification callback provided by the driver. + * This is one of the per-driver callbacks, see struct vxge_hw_uld_cbs{}. + * + * See also: struct vxge_hw_uld_cbs{}, enum vxge_hw_event{}, + * vxge_hw_driver_initialize(). + */ + +/** + * struct vxge_hw_uld_cbs - driver "slow-path" callbacks. + * @link_up: See vxge_uld_link_up_f{}. + * @link_down: See vxge_uld_link_down_f{}. + * @crit_err: See vxge_uld_crit_err_f{}. + * + * Driver slow-path (per-driver) callbacks. + * Implemented by driver and provided to HW via + * vxge_hw_driver_initialize(). + * Note that these callbacks are not mandatory: HW will not invoke + * a callback if NULL is specified. + * + * See also: vxge_hw_driver_initialize(). + */ +struct vxge_hw_uld_cbs { + + void (*link_up)(struct __vxge_hw_device *devh); + void (*link_down)(struct __vxge_hw_device *devh); + void (*crit_err)(struct __vxge_hw_device *devh, + enum vxge_hw_event type, u64 ext_data); +}; + +/* + * struct __vxge_hw_blockpool_entry - Block private data structure + * @item: List header used to link. + * @length: Length of the block + * @memblock: Virtual address block + * @dma_addr: DMA Address of the block. + * @dma_handle: DMA handle of the block. + * @acc_handle: DMA acc handle + * + * Block is allocated with a header to put the blocks into list. + * + */ +struct __vxge_hw_blockpool_entry { + struct list_head item; + u32 length; + void *memblock; + dma_addr_t dma_addr; + struct pci_dev *dma_handle; + struct pci_dev *acc_handle; +}; + +/* + * struct __vxge_hw_blockpool - Block Pool + * @hldev: HW device + * @block_size: size of each block. + * @Pool_size: Number of blocks in the pool + * @pool_max: Maximum number of blocks above which to free additional blocks + * @req_out: Number of block requests with OS out standing + * @free_block_list: List of free blocks + * + * Block pool contains the DMA blocks preallocated. + * + */ +struct __vxge_hw_blockpool { + struct __vxge_hw_device *hldev; + u32 block_size; + u32 pool_size; + u32 pool_max; + u32 req_out; + struct list_head free_block_list; + struct list_head free_entry_list; +}; + +/* + * enum enum __vxge_hw_channel_type - Enumerated channel types. + * @VXGE_HW_CHANNEL_TYPE_UNKNOWN: Unknown channel. + * @VXGE_HW_CHANNEL_TYPE_FIFO: fifo. + * @VXGE_HW_CHANNEL_TYPE_RING: ring. + * @VXGE_HW_CHANNEL_TYPE_MAX: Maximum number of HW-supported + * (and recognized) channel types. Currently: 2. + * + * Enumerated channel types. Currently there are only two link-layer + * channels - Titan fifo and Titan ring. In the future the list will grow. + */ +enum __vxge_hw_channel_type { + VXGE_HW_CHANNEL_TYPE_UNKNOWN = 0, + VXGE_HW_CHANNEL_TYPE_FIFO = 1, + VXGE_HW_CHANNEL_TYPE_RING = 2, + VXGE_HW_CHANNEL_TYPE_MAX = 3 +}; + +/* + * struct __vxge_hw_channel + * @item: List item; used to maintain a list of open channels. + * @type: Channel type. See enum vxge_hw_channel_type{}. + * @devh: Device handle. HW device object that contains _this_ channel. + * @vph: Virtual path handle. Virtual Path Object that contains _this_ channel. + * @length: Channel length. Currently allocated number of descriptors. + * The channel length "grows" when more descriptors get allocated. + * See _hw_mempool_grow. + * @reserve_arr: Reserve array. Contains descriptors that can be reserved + * by driver for the subsequent send or receive operation. + * See vxge_hw_fifo_txdl_reserve(), + * vxge_hw_ring_rxd_reserve(). + * @reserve_ptr: Current pointer in the resrve array + * @reserve_top: Reserve top gives the maximum number of dtrs available in + * reserve array. + * @work_arr: Work array. Contains descriptors posted to the channel. + * Note that at any point in time @work_arr contains 3 types of + * descriptors: + * 1) posted but not yet consumed by Titan device; + * 2) consumed but not yet completed; + * 3) completed but not yet freed + * (via vxge_hw_fifo_txdl_free() or vxge_hw_ring_rxd_free()) + * @post_index: Post index. At any point in time points on the + * position in the channel, which'll contain next to-be-posted + * descriptor. + * @compl_index: Completion index. At any point in time points on the + * position in the channel, which will contain next + * to-be-completed descriptor. + * @free_arr: Free array. Contains completed descriptors that were freed + * (i.e., handed over back to HW) by driver. + * See vxge_hw_fifo_txdl_free(), vxge_hw_ring_rxd_free(). + * @free_ptr: current pointer in free array + * @per_dtr_space: Per-descriptor space (in bytes) that channel user can utilize + * to store per-operation control information. + * @stats: Pointer to common statistics + * @userdata: Per-channel opaque (void*) user-defined context, which may be + * driver object, ULP connection, etc. + * Once channel is open, @userdata is passed back to user via + * vxge_hw_channel_callback_f. + * + * HW channel object. + * + * See also: enum vxge_hw_channel_type{}, enum vxge_hw_channel_flag + */ +struct __vxge_hw_channel { + struct list_head item; + enum __vxge_hw_channel_type type; + struct __vxge_hw_device *devh; + struct __vxge_hw_vpath_handle *vph; + u32 length; + u32 vp_id; + void **reserve_arr; + u32 reserve_ptr; + u32 reserve_top; + void **work_arr; + u32 post_index ____cacheline_aligned; + u32 compl_index ____cacheline_aligned; + void **free_arr; + u32 free_ptr; + void **orig_arr; + u32 per_dtr_space; + void *userdata; + struct vxge_hw_common_reg __iomem *common_reg; + u32 first_vp_id; + struct vxge_hw_vpath_stats_sw_common_info *stats; + +} ____cacheline_aligned; + +/* + * struct __vxge_hw_virtualpath - Virtual Path + * + * @vp_id: Virtual path id + * @vp_open: This flag specifies if vxge_hw_vp_open is called from LL Driver + * @hldev: Hal device + * @vp_config: Virtual Path Config + * @vp_reg: VPATH Register map address in BAR0 + * @vpmgmt_reg: VPATH_MGMT register map address + * @max_mtu: Max mtu that can be supported + * @vsport_number: vsport attached to this vpath + * @max_kdfc_db: Maximum kernel mode doorbells + * @max_nofl_db: Maximum non offload doorbells + * @tx_intr_num: Interrupt Number associated with the TX + + * @ringh: Ring Queue + * @fifoh: FIFO Queue + * @vpath_handles: Virtual Path handles list + * @stats_block: Memory for DMAing stats + * @stats: Vpath statistics + * + * Virtual path structure to encapsulate the data related to a virtual path. + * Virtual paths are allocated by the HW upon getting configuration from the + * driver and inserted into the list of virtual paths. + */ +struct __vxge_hw_virtualpath { + u32 vp_id; + + u32 vp_open; +#define VXGE_HW_VP_NOT_OPEN 0 +#define VXGE_HW_VP_OPEN 1 + + struct __vxge_hw_device *hldev; + struct vxge_hw_vp_config *vp_config; + struct vxge_hw_vpath_reg __iomem *vp_reg; + struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg; + struct __vxge_hw_non_offload_db_wrapper __iomem *nofl_db; + + u32 max_mtu; + u32 vsport_number; + u32 max_kdfc_db; + u32 max_nofl_db; + + struct __vxge_hw_ring *____cacheline_aligned ringh; + struct __vxge_hw_fifo *____cacheline_aligned fifoh; + struct list_head vpath_handles; + struct __vxge_hw_blockpool_entry *stats_block; + struct vxge_hw_vpath_stats_hw_info *hw_stats; + struct vxge_hw_vpath_stats_hw_info *hw_stats_sav; + struct vxge_hw_vpath_stats_sw_info *sw_stats; +}; + +/* + * struct __vxge_hw_vpath_handle - List item to store callback information + * @item: List head to keep the item in linked list + * @vpath: Virtual path to which this item belongs + * + * This structure is used to store the callback information. + */ +struct __vxge_hw_vpath_handle{ + struct list_head item; + struct __vxge_hw_virtualpath *vpath; +}; + +/* + * struct __vxge_hw_device + * + * HW device object. + */ +/** + * struct __vxge_hw_device - Hal device object + * @magic: Magic Number + * @device_id: PCI Device Id of the adapter + * @major_revision: PCI Device major revision + * @minor_revision: PCI Device minor revision + * @bar0: BAR0 virtual address. + * @bar1: BAR1 virtual address. + * @bar2: BAR2 virtual address. + * @pdev: Physical device handle + * @config: Confguration passed by the LL driver at initialization + * @link_state: Link state + * + * HW device object. Represents Titan adapter + */ +struct __vxge_hw_device { + u32 magic; +#define VXGE_HW_DEVICE_MAGIC 0x12345678 +#define VXGE_HW_DEVICE_DEAD 0xDEADDEAD + u16 device_id; + u8 major_revision; + u8 minor_revision; + void __iomem *bar0; + void __iomem *bar1; + void __iomem *bar2; + struct pci_dev *pdev; + struct net_device *ndev; + struct vxge_hw_device_config config; + enum vxge_hw_device_link_state link_state; + + struct vxge_hw_uld_cbs uld_callbacks; + + u32 host_type; + u32 func_id; + u32 access_rights; +#define VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH 0x1 +#define VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM 0x2 +#define VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM 0x4 + struct vxge_hw_legacy_reg __iomem *legacy_reg; + struct vxge_hw_toc_reg __iomem *toc_reg; + struct vxge_hw_common_reg __iomem *common_reg; + struct vxge_hw_mrpcim_reg __iomem *mrpcim_reg; + struct vxge_hw_srpcim_reg __iomem *srpcim_reg \ + [VXGE_HW_TITAN_SRPCIM_REG_SPACES]; + struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg \ + [VXGE_HW_TITAN_VPMGMT_REG_SPACES]; + struct vxge_hw_vpath_reg __iomem *vpath_reg \ + [VXGE_HW_TITAN_VPATH_REG_SPACES]; + u8 __iomem *kdfc; + u8 __iomem *usdc; + struct __vxge_hw_virtualpath virtual_paths \ + [VXGE_HW_MAX_VIRTUAL_PATHS]; + u64 vpath_assignments; + u64 vpaths_deployed; + u32 first_vp_id; + u64 tim_int_mask0[4]; + u32 tim_int_mask1[4]; + + struct __vxge_hw_blockpool block_pool; + struct vxge_hw_device_stats stats; + u32 debug_module_mask; + u32 debug_level; + u32 level_err; + u32 level_trace; +}; + +#define VXGE_HW_INFO_LEN 64 +/** + * struct vxge_hw_device_hw_info - Device information + * @host_type: Host Type + * @func_id: Function Id + * @vpath_mask: vpath bit mask + * @fw_version: Firmware version + * @fw_date: Firmware Date + * @flash_version: Firmware version + * @flash_date: Firmware Date + * @mac_addrs: Mac addresses for each vpath + * @mac_addr_masks: Mac address masks for each vpath + * + * Returns the vpath mask that has the bits set for each vpath allocated + * for the driver and the first mac address for each vpath + */ +struct vxge_hw_device_hw_info { + u32 host_type; +#define VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION 0 +#define VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION 1 +#define VXGE_HW_NO_MR_SR_VH0_FUNCTION0 2 +#define VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION 3 +#define VXGE_HW_MR_SR_VH0_INVALID_CONFIG 4 +#define VXGE_HW_SR_VH_FUNCTION0 5 +#define VXGE_HW_SR_VH_VIRTUAL_FUNCTION 6 +#define VXGE_HW_VH_NORMAL_FUNCTION 7 + u64 function_mode; +#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION 0 +#define VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION 1 +#define VXGE_HW_FUNCTION_MODE_SRIOV 2 +#define VXGE_HW_FUNCTION_MODE_MRIOV 3 + u32 func_id; + u64 vpath_mask; + struct vxge_hw_device_version fw_version; + struct vxge_hw_device_date fw_date; + struct vxge_hw_device_version flash_version; + struct vxge_hw_device_date flash_date; + u8 serial_number[VXGE_HW_INFO_LEN]; + u8 part_number[VXGE_HW_INFO_LEN]; + u8 product_desc[VXGE_HW_INFO_LEN]; + u8 (mac_addrs)[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN]; + u8 (mac_addr_masks)[VXGE_HW_MAX_VIRTUAL_PATHS][ETH_ALEN]; +}; + +/** + * struct vxge_hw_device_attr - Device memory spaces. + * @bar0: BAR0 virtual address. + * @bar1: BAR1 virtual address. + * @bar2: BAR2 virtual address. + * @pdev: PCI device object. + * + * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device + * mapped memories. Also, includes a pointer to OS-specific PCI device object. + */ +struct vxge_hw_device_attr { + void __iomem *bar0; + void __iomem *bar1; + void __iomem *bar2; + struct pci_dev *pdev; + struct vxge_hw_uld_cbs uld_callbacks; +}; + +#define VXGE_HW_DEVICE_LINK_STATE_SET(hldev, ls) (hldev->link_state = ls) + +#define VXGE_HW_DEVICE_TIM_INT_MASK_SET(m0, m1, i) { \ + if (i < 16) { \ + m0[0] |= vxge_vBIT(0x8, (i*4), 4); \ + m0[1] |= vxge_vBIT(0x4, (i*4), 4); \ + } \ + else { \ + m1[0] = 0x80000000; \ + m1[1] = 0x40000000; \ + } \ +} + +#define VXGE_HW_DEVICE_TIM_INT_MASK_RESET(m0, m1, i) { \ + if (i < 16) { \ + m0[0] &= ~vxge_vBIT(0x8, (i*4), 4); \ + m0[1] &= ~vxge_vBIT(0x4, (i*4), 4); \ + } \ + else { \ + m1[0] = 0; \ + m1[1] = 0; \ + } \ +} + +#define VXGE_HW_DEVICE_STATS_PIO_READ(loc, offset) { \ + status = vxge_hw_mrpcim_stats_access(hldev, \ + VXGE_HW_STATS_OP_READ, \ + loc, \ + offset, \ + &val64); \ + \ + if (status != VXGE_HW_OK) \ + return status; \ +} + +#define VXGE_HW_VPATH_STATS_PIO_READ(offset) { \ + status = __vxge_hw_vpath_stats_access(vpath, \ + VXGE_HW_STATS_OP_READ, \ + offset, \ + &val64); \ + if (status != VXGE_HW_OK) \ + return status; \ +} + +/* + * struct __vxge_hw_ring - Ring channel. + * @channel: Channel "base" of this ring, the common part of all HW + * channels. + * @mempool: Memory pool, the pool from which descriptors get allocated. + * (See vxge_hw_mm.h). + * @config: Ring configuration, part of device configuration + * (see struct vxge_hw_device_config{}). + * @ring_length: Length of the ring + * @buffer_mode: 1, 3, or 5. The value specifies a receive buffer mode, + * as per Titan User Guide. + * @rxd_size: RxD sizes for 1-, 3- or 5- buffer modes. As per Titan spec, + * 1-buffer mode descriptor is 32 byte long, etc. + * @rxd_priv_size: Per RxD size reserved (by HW) for driver to keep + * per-descriptor data (e.g., DMA handle for Solaris) + * @per_rxd_space: Per rxd space requested by driver + * @rxds_per_block: Number of descriptors per hardware-defined RxD + * block. Depends on the (1-, 3-, 5-) buffer mode. + * @rxdblock_priv_size: Reserved at the end of each RxD block. HW internal + * usage. Not to confuse with @rxd_priv_size. + * @cmpl_cnt: Completion counter. Is reset to zero upon entering the ISR. + * @callback: Channel completion callback. HW invokes the callback when there + * are new completions on that channel. In many implementations + * the @callback executes in the hw interrupt context. + * @rxd_init: Channel's descriptor-initialize callback. + * See vxge_hw_ring_rxd_init_f{}. + * If not NULL, HW invokes the callback when opening + * the ring. + * @rxd_term: Channel's descriptor-terminate callback. If not NULL, + * HW invokes the callback when closing the corresponding channel. + * See also vxge_hw_channel_rxd_term_f{}. + * @stats: Statistics for ring + * Ring channel. + * + * Note: The structure is cache line aligned to better utilize + * CPU cache performance. + */ +struct __vxge_hw_ring { + struct __vxge_hw_channel channel; + struct vxge_hw_mempool *mempool; + struct vxge_hw_vpath_reg __iomem *vp_reg; + struct vxge_hw_common_reg __iomem *common_reg; + u32 ring_length; + u32 buffer_mode; + u32 rxd_size; + u32 rxd_priv_size; + u32 per_rxd_space; + u32 rxds_per_block; + u32 rxdblock_priv_size; + u32 cmpl_cnt; + u32 vp_id; + u32 doorbell_cnt; + u32 total_db_cnt; + u64 rxds_limit; + + enum vxge_hw_status (*callback)( + struct __vxge_hw_ring *ringh, + void *rxdh, + u8 t_code, + void *userdata); + + enum vxge_hw_status (*rxd_init)( + void *rxdh, + void *userdata); + + void (*rxd_term)( + void *rxdh, + enum vxge_hw_rxd_state state, + void *userdata); + + struct vxge_hw_vpath_stats_sw_ring_info *stats ____cacheline_aligned; + struct vxge_hw_ring_config *config; +} ____cacheline_aligned; + +/** + * enum enum vxge_hw_txdl_state - Descriptor (TXDL) state. + * @VXGE_HW_TXDL_STATE_NONE: Invalid state. + * @VXGE_HW_TXDL_STATE_AVAIL: Descriptor is available for reservation. + * @VXGE_HW_TXDL_STATE_POSTED: Descriptor is posted for processing by the + * device. + * @VXGE_HW_TXDL_STATE_FREED: Descriptor is free and can be reused for + * filling-in and posting later. + * + * Titan/HW descriptor states. + * + */ +enum vxge_hw_txdl_state { + VXGE_HW_TXDL_STATE_NONE = 0, + VXGE_HW_TXDL_STATE_AVAIL = 1, + VXGE_HW_TXDL_STATE_POSTED = 2, + VXGE_HW_TXDL_STATE_FREED = 3 +}; +/* + * struct __vxge_hw_fifo - Fifo. + * @channel: Channel "base" of this fifo, the common part of all HW + * channels. + * @mempool: Memory pool, from which descriptors get allocated. + * @config: Fifo configuration, part of device configuration + * (see struct vxge_hw_device_config{}). + * @interrupt_type: Interrupt type to be used + * @no_snoop_bits: See struct vxge_hw_fifo_config{}. + * @txdl_per_memblock: Number of TxDLs (TxD lists) per memblock. + * on TxDL please refer to Titan UG. + * @txdl_size: Configured TxDL size (i.e., number of TxDs in a list), plus + * per-TxDL HW private space (struct __vxge_hw_fifo_txdl_priv). + * @priv_size: Per-Tx descriptor space reserved for driver + * usage. + * @per_txdl_space: Per txdl private space for the driver + * @callback: Fifo completion callback. HW invokes the callback when there + * are new completions on that fifo. In many implementations + * the @callback executes in the hw interrupt context. + * @txdl_term: Fifo's descriptor-terminate callback. If not NULL, + * HW invokes the callback when closing the corresponding fifo. + * See also vxge_hw_fifo_txdl_term_f{}. + * @stats: Statistics of this fifo + * + * Fifo channel. + * Note: The structure is cache line aligned. + */ +struct __vxge_hw_fifo { + struct __vxge_hw_channel channel; + struct vxge_hw_mempool *mempool; + struct vxge_hw_fifo_config *config; + struct vxge_hw_vpath_reg __iomem *vp_reg; + struct __vxge_hw_non_offload_db_wrapper __iomem *nofl_db; + u64 interrupt_type; + u32 no_snoop_bits; + u32 txdl_per_memblock; + u32 txdl_size; + u32 priv_size; + u32 per_txdl_space; + u32 vp_id; + u32 tx_intr_num; + + enum vxge_hw_status (*callback)( + struct __vxge_hw_fifo *fifo_handle, + void *txdlh, + enum vxge_hw_fifo_tcode t_code, + void *userdata, + void **skb_ptr); + + void (*txdl_term)( + void *txdlh, + enum vxge_hw_txdl_state state, + void *userdata); + + struct vxge_hw_vpath_stats_sw_fifo_info *stats ____cacheline_aligned; +} ____cacheline_aligned; + +/* + * struct __vxge_hw_fifo_txdl_priv - Transmit descriptor HW-private data. + * @dma_addr: DMA (mapped) address of _this_ descriptor. + * @dma_handle: DMA handle used to map the descriptor onto device. + * @dma_offset: Descriptor's offset in the memory block. HW allocates + * descriptors in memory blocks (see struct vxge_hw_fifo_config{}) + * Each memblock is a contiguous block of DMA-able memory. + * @frags: Total number of fragments (that is, contiguous data buffers) + * carried by this TxDL. + * @align_vaddr_start: Aligned virtual address start + * @align_vaddr: Virtual address of the per-TxDL area in memory used for + * alignement. Used to place one or more mis-aligned fragments + * @align_dma_addr: DMA address translated from the @align_vaddr. + * @align_dma_handle: DMA handle that corresponds to @align_dma_addr. + * @align_dma_acch: DMA access handle corresponds to @align_dma_addr. + * @align_dma_offset: The current offset into the @align_vaddr area. + * Grows while filling the descriptor, gets reset. + * @align_used_frags: Number of fragments used. + * @alloc_frags: Total number of fragments allocated. + * @unused: TODO + * @next_txdl_priv: (TODO). + * @first_txdp: (TODO). + * @linked_txdl_priv: Pointer to any linked TxDL for creating contiguous + * TxDL list. + * @txdlh: Corresponding txdlh to this TxDL. + * @memblock: Pointer to the TxDL memory block or memory page. + * on the next send operation. + * @dma_object: DMA address and handle of the memory block that contains + * the descriptor. This member is used only in the "checked" + * version of the HW (to enforce certain assertions); + * otherwise it gets compiled out. + * @allocated: True if the descriptor is reserved, 0 otherwise. Internal usage. + * + * Per-transmit decsriptor HW-private data. HW uses the space to keep DMA + * information associated with the descriptor. Note that driver can ask HW + * to allocate additional per-descriptor space for its own (driver-specific) + * purposes. + * + * See also: struct vxge_hw_ring_rxd_priv{}. + */ +struct __vxge_hw_fifo_txdl_priv { + dma_addr_t dma_addr; + struct pci_dev *dma_handle; + ptrdiff_t dma_offset; + u32 frags; + u8 *align_vaddr_start; + u8 *align_vaddr; + dma_addr_t align_dma_addr; + struct pci_dev *align_dma_handle; + struct pci_dev *align_dma_acch; + ptrdiff_t align_dma_offset; + u32 align_used_frags; + u32 alloc_frags; + u32 unused; + struct __vxge_hw_fifo_txdl_priv *next_txdl_priv; + struct vxge_hw_fifo_txd *first_txdp; + void *memblock; +}; + +/* + * struct __vxge_hw_non_offload_db_wrapper - Non-offload Doorbell Wrapper + * @control_0: Bits 0 to 7 - Doorbell type. + * Bits 8 to 31 - Reserved. + * Bits 32 to 39 - The highest TxD in this TxDL. + * Bits 40 to 47 - Reserved. + * Bits 48 to 55 - Reserved. + * Bits 56 to 63 - No snoop flags. + * @txdl_ptr: The starting location of the TxDL in host memory. + * + * Created by the host and written to the adapter via PIO to a Kernel Doorbell + * FIFO. All non-offload doorbell wrapper fields must be written by the host as + * part of a doorbell write. Consumed by the adapter but is not written by the + * adapter. + */ +struct __vxge_hw_non_offload_db_wrapper { + u64 control_0; +#define VXGE_HW_NODBW_GET_TYPE(ctrl0) vxge_bVALn(ctrl0, 0, 8) +#define VXGE_HW_NODBW_TYPE(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_NODBW_TYPE_NODBW 0 + +#define VXGE_HW_NODBW_GET_LAST_TXD_NUMBER(ctrl0) vxge_bVALn(ctrl0, 32, 8) +#define VXGE_HW_NODBW_LAST_TXD_NUMBER(val) vxge_vBIT(val, 32, 8) + +#define VXGE_HW_NODBW_GET_NO_SNOOP(ctrl0) vxge_bVALn(ctrl0, 56, 8) +#define VXGE_HW_NODBW_LIST_NO_SNOOP(val) vxge_vBIT(val, 56, 8) +#define VXGE_HW_NODBW_LIST_NO_SNOOP_TXD_READ_TXD0_WRITE 0x2 +#define VXGE_HW_NODBW_LIST_NO_SNOOP_TX_FRAME_DATA_READ 0x1 + + u64 txdl_ptr; +}; + +/* + * TX Descriptor + */ + +/** + * struct vxge_hw_fifo_txd - Transmit Descriptor + * @control_0: Bits 0 to 6 - Reserved. + * Bit 7 - List Ownership. This field should be initialized + * to '1' by the driver before the transmit list pointer is + * written to the adapter. This field will be set to '0' by the + * adapter once it has completed transmitting the frame or frames in + * the list. Note - This field is only valid in TxD0. Additionally, + * for multi-list sequences, the driver should not release any + * buffers until the ownership of the last list in the multi-list + * sequence has been returned to the host. + * Bits 8 to 11 - Reserved + * Bits 12 to 15 - Transfer_Code. This field is only valid in + * TxD0. It is used to describe the status of the transmit data + * buffer transfer. This field is always overwritten by the + * adapter, so this field may be initialized to any value. + * Bits 16 to 17 - Host steering. This field allows the host to + * override the selection of the physical transmit port. + * Attention: + * Normal sounds as if learned from the switch rather than from + * the aggregation algorythms. + * 00: Normal. Use Destination/MAC Address + * lookup to determine the transmit port. + * 01: Send on physical Port1. + * 10: Send on physical Port0. + * 11: Send on both ports. + * Bits 18 to 21 - Reserved + * Bits 22 to 23 - Gather_Code. This field is set by the host and + * is used to describe how individual buffers comprise a frame. + * 10: First descriptor of a frame. + * 00: Middle of a multi-descriptor frame. + * 01: Last descriptor of a frame. + * 11: First and last descriptor of a frame (the entire frame + * resides in a single buffer). + * For multi-descriptor frames, the only valid gather code sequence + * is {10, [00], 01}. In other words, the descriptors must be placed + * in the list in the correct order. + * Bits 24 to 27 - Reserved + * Bits 28 to 29 - LSO_Frm_Encap. LSO Frame Encapsulation + * definition. Only valid in TxD0. This field allows the host to + * indicate the Ethernet encapsulation of an outbound LSO packet. + * 00 - classic mode (best guess) + * 01 - LLC + * 10 - SNAP + * 11 - DIX + * If "classic mode" is selected, the adapter will attempt to + * decode the frame's Ethernet encapsulation by examining the L/T + * field as follows: + * <= 0x05DC LLC/SNAP encoding; must examine DSAP/SSAP to determine + * if packet is IPv4 or IPv6. + * 0x8870 Jumbo-SNAP encoding. + * 0x0800 IPv4 DIX encoding + * 0x86DD IPv6 DIX encoding + * others illegal encapsulation + * Bits 30 - LSO_ Flag. Large Send Offload (LSO) flag. + * Set to 1 to perform segmentation offload for TCP/UDP. + * This field is valid only in TxD0. + * Bits 31 to 33 - Reserved. + * Bits 34 to 47 - LSO_MSS. TCP/UDP LSO Maximum Segment Size + * This field is meaningful only when LSO_Control is non-zero. + * When LSO_Control is set to TCP_LSO, the single (possibly large) + * TCP segment described by this TxDL will be sent as a series of + * TCP segments each of which contains no more than LSO_MSS + * payload bytes. + * When LSO_Control is set to UDP_LSO, the single (possibly large) + * UDP datagram described by this TxDL will be sent as a series of + * UDP datagrams each of which contains no more than LSO_MSS + * payload bytes. + * All outgoing frames from this TxDL will have LSO_MSS bytes of UDP + * or TCP payload, with the exception of the last, which will have + * <= LSO_MSS bytes of payload. + * Bits 48 to 63 - Buffer_Size. Number of valid bytes in the + * buffer to be read by the adapter. This field is written by the + * host. A value of 0 is illegal. + * Bits 32 to 63 - This value is written by the adapter upon + * completion of a UDP or TCP LSO operation and indicates the number + * of UDP or TCP payload bytes that were transmitted. 0x0000 will be + * returned for any non-LSO operation. + * @control_1: Bits 0 to 4 - Reserved. + * Bit 5 - Tx_CKO_IPv4 Set to a '1' to enable IPv4 header checksum + * offload. This field is only valid in the first TxD of a frame. + * Bit 6 - Tx_CKO_TCP Set to a '1' to enable TCP checksum offload. + * This field is only valid in the first TxD of a frame (the TxD's + * gather code must be 10 or 11). The driver should only set this + * bit if it can guarantee that TCP is present. + * Bit 7 - Tx_CKO_UDP Set to a '1' to enable UDP checksum offload. + * This field is only valid in the first TxD of a frame (the TxD's + * gather code must be 10 or 11). The driver should only set this + * bit if it can guarantee that UDP is present. + * Bits 8 to 14 - Reserved. + * Bit 15 - Tx_VLAN_Enable VLAN tag insertion flag. Set to a '1' to + * instruct the adapter to insert the VLAN tag specified by the + * Tx_VLAN_Tag field. This field is only valid in the first TxD of + * a frame. + * Bits 16 to 31 - Tx_VLAN_Tag. Variable portion of the VLAN tag + * to be inserted into the frame by the adapter (the first two bytes + * of a VLAN tag are always 0x8100). This field is only valid if the + * Tx_VLAN_Enable field is set to '1'. + * Bits 32 to 33 - Reserved. + * Bits 34 to 39 - Tx_Int_Number. Indicates which Tx interrupt + * number the frame associated with. This field is written by the + * host. It is only valid in the first TxD of a frame. + * Bits 40 to 42 - Reserved. + * Bit 43 - Set to 1 to exclude the frame from bandwidth metering + * functions. This field is valid only in the first TxD + * of a frame. + * Bits 44 to 45 - Reserved. + * Bit 46 - Tx_Int_Per_List Set to a '1' to instruct the adapter to + * generate an interrupt as soon as all of the frames in the list + * have been transmitted. In order to have per-frame interrupts, + * the driver should place a maximum of one frame per list. This + * field is only valid in the first TxD of a frame. + * Bit 47 - Tx_Int_Utilization Set to a '1' to instruct the adapter + * to count the frame toward the utilization interrupt specified in + * the Tx_Int_Number field. This field is only valid in the first + * TxD of a frame. + * Bits 48 to 63 - Reserved. + * @buffer_pointer: Buffer start address. + * @host_control: Host_Control.Opaque 64bit data stored by driver inside the + * Titan descriptor prior to posting the latter on the fifo + * via vxge_hw_fifo_txdl_post().The %host_control is returned as is + * to the driver with each completed descriptor. + * + * Transmit descriptor (TxD).Fifo descriptor contains configured number + * (list) of TxDs. * For more details please refer to Titan User Guide, + * Section 5.4.2 "Transmit Descriptor (TxD) Format". + */ +struct vxge_hw_fifo_txd { + u64 control_0; +#define VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER vxge_mBIT(7) + +#define VXGE_HW_FIFO_TXD_T_CODE_GET(ctrl0) vxge_bVALn(ctrl0, 12, 4) +#define VXGE_HW_FIFO_TXD_T_CODE(val) vxge_vBIT(val, 12, 4) +#define VXGE_HW_FIFO_TXD_T_CODE_UNUSED VXGE_HW_FIFO_T_CODE_UNUSED + + +#define VXGE_HW_FIFO_TXD_GATHER_CODE(val) vxge_vBIT(val, 22, 2) +#define VXGE_HW_FIFO_TXD_GATHER_CODE_FIRST VXGE_HW_FIFO_GATHER_CODE_FIRST +#define VXGE_HW_FIFO_TXD_GATHER_CODE_LAST VXGE_HW_FIFO_GATHER_CODE_LAST + + +#define VXGE_HW_FIFO_TXD_LSO_EN vxge_mBIT(30) + +#define VXGE_HW_FIFO_TXD_LSO_MSS(val) vxge_vBIT(val, 34, 14) + +#define VXGE_HW_FIFO_TXD_BUFFER_SIZE(val) vxge_vBIT(val, 48, 16) + + u64 control_1; +#define VXGE_HW_FIFO_TXD_TX_CKO_IPV4_EN vxge_mBIT(5) +#define VXGE_HW_FIFO_TXD_TX_CKO_TCP_EN vxge_mBIT(6) +#define VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN vxge_mBIT(7) +#define VXGE_HW_FIFO_TXD_VLAN_ENABLE vxge_mBIT(15) + +#define VXGE_HW_FIFO_TXD_VLAN_TAG(val) vxge_vBIT(val, 16, 16) + +#define VXGE_HW_FIFO_TXD_INT_NUMBER(val) vxge_vBIT(val, 34, 6) + +#define VXGE_HW_FIFO_TXD_INT_TYPE_PER_LIST vxge_mBIT(46) +#define VXGE_HW_FIFO_TXD_INT_TYPE_UTILZ vxge_mBIT(47) + + u64 buffer_pointer; + + u64 host_control; +}; + +/** + * struct vxge_hw_ring_rxd_1 - One buffer mode RxD for ring + * @host_control: This field is exclusively for host use and is "readonly" + * from the adapter's perspective. + * @control_0:Bits 0 to 6 - RTH_Bucket get + * Bit 7 - Own Descriptor ownership bit. This bit is set to 1 + * by the host, and is set to 0 by the adapter. + * 0 - Host owns RxD and buffer. + * 1 - The adapter owns RxD and buffer. + * Bit 8 - Fast_Path_Eligible When set, indicates that the + * received frame meets all of the criteria for fast path processing. + * The required criteria are as follows: + * !SYN & + * (Transfer_Code == "Transfer OK") & + * (!Is_IP_Fragment) & + * ((Is_IPv4 & computed_L3_checksum == 0xFFFF) | + * (Is_IPv6)) & + * ((Is_TCP & computed_L4_checksum == 0xFFFF) | + * (Is_UDP & (computed_L4_checksum == 0xFFFF | + * computed _L4_checksum == 0x0000))) + * (same meaning for all RxD buffer modes) + * Bit 9 - L3 Checksum Correct + * Bit 10 - L4 Checksum Correct + * Bit 11 - Reserved + * Bit 12 to 15 - This field is written by the adapter. It is + * used to report the status of the frame transfer to the host. + * 0x0 - Transfer OK + * 0x4 - RDA Failure During Transfer + * 0x5 - Unparseable Packet, such as unknown IPv6 header. + * 0x6 - Frame integrity error (FCS or ECC). + * 0x7 - Buffer Size Error. The provided buffer(s) were not + * appropriately sized and data loss occurred. + * 0x8 - Internal ECC Error. RxD corrupted. + * 0x9 - IPv4 Checksum error + * 0xA - TCP/UDP Checksum error + * 0xF - Unknown Error or Multiple Error. Indicates an + * unknown problem or that more than one of transfer codes is set. + * Bit 16 - SYN The adapter sets this field to indicate that + * the incoming frame contained a TCP segment with its SYN bit + * set and its ACK bit NOT set. (same meaning for all RxD buffer + * modes) + * Bit 17 - Is ICMP + * Bit 18 - RTH_SPDM_HIT Set to 1 if there was a match in the + * Socket Pair Direct Match Table and the frame was steered based + * on SPDM. + * Bit 19 - RTH_IT_HIT Set to 1 if there was a match in the + * Indirection Table and the frame was steered based on hash + * indirection. + * Bit 20 to 23 - RTH_HASH_TYPE Indicates the function (hash + * type) that was used to calculate the hash. + * Bit 19 - IS_VLAN Set to '1' if the frame was/is VLAN + * tagged. + * Bit 25 to 26 - ETHER_ENCAP Reflects the Ethernet encapsulation + * of the received frame. + * 0x0 - Ethernet DIX + * 0x1 - LLC + * 0x2 - SNAP (includes Jumbo-SNAP) + * 0x3 - IPX + * Bit 27 - IS_IPV4 Set to '1' if the frame contains an IPv4 packet. + * Bit 28 - IS_IPV6 Set to '1' if the frame contains an IPv6 packet. + * Bit 29 - IS_IP_FRAG Set to '1' if the frame contains a fragmented + * IP packet. + * Bit 30 - IS_TCP Set to '1' if the frame contains a TCP segment. + * Bit 31 - IS_UDP Set to '1' if the frame contains a UDP message. + * Bit 32 to 47 - L3_Checksum[0:15] The IPv4 checksum value that + * arrived with the frame. If the resulting computed IPv4 header + * checksum for the frame did not produce the expected 0xFFFF value, + * then the transfer code would be set to 0x9. + * Bit 48 to 63 - L4_Checksum[0:15] The TCP/UDP checksum value that + * arrived with the frame. If the resulting computed TCP/UDP checksum + * for the frame did not produce the expected 0xFFFF value, then the + * transfer code would be set to 0xA. + * @control_1:Bits 0 to 1 - Reserved + * Bits 2 to 15 - Buffer0_Size.This field is set by the host and + * eventually overwritten by the adapter. The host writes the + * available buffer size in bytes when it passes the descriptor to + * the adapter. When a frame is delivered the host, the adapter + * populates this field with the number of bytes written into the + * buffer. The largest supported buffer is 16, 383 bytes. + * Bit 16 to 47 - RTH Hash Value 32-bit RTH hash value. Only valid if + * RTH_HASH_TYPE (Control_0, bits 20:23) is nonzero. + * Bit 48 to 63 - VLAN_Tag[0:15] The contents of the variable portion + * of the VLAN tag, if one was detected by the adapter. This field is + * populated even if VLAN-tag stripping is enabled. + * @buffer0_ptr: Pointer to buffer. This field is populated by the driver. + * + * One buffer mode RxD for ring structure + */ +struct vxge_hw_ring_rxd_1 { + u64 host_control; + u64 control_0; +#define VXGE_HW_RING_RXD_RTH_BUCKET_GET(ctrl0) vxge_bVALn(ctrl0, 0, 7) + +#define VXGE_HW_RING_RXD_LIST_OWN_ADAPTER vxge_mBIT(7) + +#define VXGE_HW_RING_RXD_FAST_PATH_ELIGIBLE_GET(ctrl0) vxge_bVALn(ctrl0, 8, 1) + +#define VXGE_HW_RING_RXD_L3_CKSUM_CORRECT_GET(ctrl0) vxge_bVALn(ctrl0, 9, 1) + +#define VXGE_HW_RING_RXD_L4_CKSUM_CORRECT_GET(ctrl0) vxge_bVALn(ctrl0, 10, 1) + +#define VXGE_HW_RING_RXD_T_CODE_GET(ctrl0) vxge_bVALn(ctrl0, 12, 4) +#define VXGE_HW_RING_RXD_T_CODE(val) vxge_vBIT(val, 12, 4) + +#define VXGE_HW_RING_RXD_T_CODE_UNUSED VXGE_HW_RING_T_CODE_UNUSED + +#define VXGE_HW_RING_RXD_SYN_GET(ctrl0) vxge_bVALn(ctrl0, 16, 1) + +#define VXGE_HW_RING_RXD_IS_ICMP_GET(ctrl0) vxge_bVALn(ctrl0, 17, 1) + +#define VXGE_HW_RING_RXD_RTH_SPDM_HIT_GET(ctrl0) vxge_bVALn(ctrl0, 18, 1) + +#define VXGE_HW_RING_RXD_RTH_IT_HIT_GET(ctrl0) vxge_bVALn(ctrl0, 19, 1) + +#define VXGE_HW_RING_RXD_RTH_HASH_TYPE_GET(ctrl0) vxge_bVALn(ctrl0, 20, 4) + +#define VXGE_HW_RING_RXD_IS_VLAN_GET(ctrl0) vxge_bVALn(ctrl0, 24, 1) + +#define VXGE_HW_RING_RXD_ETHER_ENCAP_GET(ctrl0) vxge_bVALn(ctrl0, 25, 2) + +#define VXGE_HW_RING_RXD_FRAME_PROTO_GET(ctrl0) vxge_bVALn(ctrl0, 27, 5) + +#define VXGE_HW_RING_RXD_L3_CKSUM_GET(ctrl0) vxge_bVALn(ctrl0, 32, 16) + +#define VXGE_HW_RING_RXD_L4_CKSUM_GET(ctrl0) vxge_bVALn(ctrl0, 48, 16) + + u64 control_1; + +#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE_GET(ctrl1) vxge_bVALn(ctrl1, 2, 14) +#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE(val) vxge_vBIT(val, 2, 14) +#define VXGE_HW_RING_RXD_1_BUFFER0_SIZE_MASK vxge_vBIT(0x3FFF, 2, 14) + +#define VXGE_HW_RING_RXD_1_RTH_HASH_VAL_GET(ctrl1) vxge_bVALn(ctrl1, 16, 32) + +#define VXGE_HW_RING_RXD_VLAN_TAG_GET(ctrl1) vxge_bVALn(ctrl1, 48, 16) + + u64 buffer0_ptr; +}; + +enum vxge_hw_rth_algoritms { + RTH_ALG_JENKINS = 0, + RTH_ALG_MS_RSS = 1, + RTH_ALG_CRC32C = 2 +}; + +/** + * struct vxge_hw_rth_hash_types - RTH hash types. + * @hash_type_tcpipv4_en: Enables RTH field type HashTypeTcpIPv4 + * @hash_type_ipv4_en: Enables RTH field type HashTypeIPv4 + * @hash_type_tcpipv6_en: Enables RTH field type HashTypeTcpIPv6 + * @hash_type_ipv6_en: Enables RTH field type HashTypeIPv6 + * @hash_type_tcpipv6ex_en: Enables RTH field type HashTypeTcpIPv6Ex + * @hash_type_ipv6ex_en: Enables RTH field type HashTypeIPv6Ex + * + * Used to pass RTH hash types to rts_rts_set. + * + * See also: vxge_hw_vpath_rts_rth_set(), vxge_hw_vpath_rts_rth_get(). + */ +struct vxge_hw_rth_hash_types { + u8 hash_type_tcpipv4_en; + u8 hash_type_ipv4_en; + u8 hash_type_tcpipv6_en; + u8 hash_type_ipv6_en; + u8 hash_type_tcpipv6ex_en; + u8 hash_type_ipv6ex_en; +}; + +u32 +vxge_hw_device_debug_mask_get(struct __vxge_hw_device *devh); + +void vxge_hw_device_debug_set( + struct __vxge_hw_device *devh, + enum vxge_debug_level level, + u32 mask); + +u32 +vxge_hw_device_error_level_get(struct __vxge_hw_device *devh); + +u32 +vxge_hw_device_trace_level_get(struct __vxge_hw_device *devh); + +u32 +vxge_hw_device_debug_mask_get(struct __vxge_hw_device *devh); + +/** + * vxge_hw_ring_rxd_size_get - Get the size of ring descriptor. + * @buf_mode: Buffer mode (1, 3 or 5) + * + * This function returns the size of RxD for given buffer mode + */ +static inline u32 vxge_hw_ring_rxd_size_get(u32 buf_mode) +{ + return sizeof(struct vxge_hw_ring_rxd_1); +} + +/** + * vxge_hw_ring_rxds_per_block_get - Get the number of rxds per block. + * @buf_mode: Buffer mode (1 buffer mode only) + * + * This function returns the number of RxD for RxD block for given buffer mode + */ +static inline u32 vxge_hw_ring_rxds_per_block_get(u32 buf_mode) +{ + return (u32)((VXGE_HW_BLOCK_SIZE-16) / + sizeof(struct vxge_hw_ring_rxd_1)); +} + +/** + * vxge_hw_ring_rxd_1b_set - Prepare 1-buffer-mode descriptor. + * @rxdh: Descriptor handle. + * @dma_pointer: DMA address of a single receive buffer this descriptor + * should carry. Note that by the time vxge_hw_ring_rxd_1b_set is called, + * the receive buffer should be already mapped to the device + * @size: Size of the receive @dma_pointer buffer. + * + * Prepare 1-buffer-mode Rx descriptor for posting + * (via vxge_hw_ring_rxd_post()). + * + * This inline helper-function does not return any parameters and always + * succeeds. + * + */ +static inline +void vxge_hw_ring_rxd_1b_set( + void *rxdh, + dma_addr_t dma_pointer, + u32 size) +{ + struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh; + rxdp->buffer0_ptr = dma_pointer; + rxdp->control_1 &= ~VXGE_HW_RING_RXD_1_BUFFER0_SIZE_MASK; + rxdp->control_1 |= VXGE_HW_RING_RXD_1_BUFFER0_SIZE(size); +} + +/** + * vxge_hw_ring_rxd_1b_get - Get data from the completed 1-buf + * descriptor. + * @vpath_handle: Virtual Path handle. + * @rxdh: Descriptor handle. + * @dma_pointer: DMA address of a single receive buffer this descriptor + * carries. Returned by HW. + * @pkt_length: Length (in bytes) of the data in the buffer pointed by + * + * Retrieve protocol data from the completed 1-buffer-mode Rx descriptor. + * This inline helper-function uses completed descriptor to populate receive + * buffer pointer and other "out" parameters. The function always succeeds. + * + */ +static inline +void vxge_hw_ring_rxd_1b_get( + struct __vxge_hw_ring *ring_handle, + void *rxdh, + u32 *pkt_length) +{ + struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh; + + *pkt_length = + (u32)VXGE_HW_RING_RXD_1_BUFFER0_SIZE_GET(rxdp->control_1); +} + +/** + * vxge_hw_ring_rxd_1b_info_get - Get extended information associated with + * a completed receive descriptor for 1b mode. + * @vpath_handle: Virtual Path handle. + * @rxdh: Descriptor handle. + * @rxd_info: Descriptor information + * + * Retrieve extended information associated with a completed receive descriptor. + * + */ +static inline +void vxge_hw_ring_rxd_1b_info_get( + struct __vxge_hw_ring *ring_handle, + void *rxdh, + struct vxge_hw_ring_rxd_info *rxd_info) +{ + + struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh; + rxd_info->syn_flag = + (u32)VXGE_HW_RING_RXD_SYN_GET(rxdp->control_0); + rxd_info->is_icmp = + (u32)VXGE_HW_RING_RXD_IS_ICMP_GET(rxdp->control_0); + rxd_info->fast_path_eligible = + (u32)VXGE_HW_RING_RXD_FAST_PATH_ELIGIBLE_GET(rxdp->control_0); + rxd_info->l3_cksum_valid = + (u32)VXGE_HW_RING_RXD_L3_CKSUM_CORRECT_GET(rxdp->control_0); + rxd_info->l3_cksum = + (u32)VXGE_HW_RING_RXD_L3_CKSUM_GET(rxdp->control_0); + rxd_info->l4_cksum_valid = + (u32)VXGE_HW_RING_RXD_L4_CKSUM_CORRECT_GET(rxdp->control_0); + rxd_info->l4_cksum = + (u32)VXGE_HW_RING_RXD_L4_CKSUM_GET(rxdp->control_0);; + rxd_info->frame = + (u32)VXGE_HW_RING_RXD_ETHER_ENCAP_GET(rxdp->control_0); + rxd_info->proto = + (u32)VXGE_HW_RING_RXD_FRAME_PROTO_GET(rxdp->control_0); + rxd_info->is_vlan = + (u32)VXGE_HW_RING_RXD_IS_VLAN_GET(rxdp->control_0); + rxd_info->vlan = + (u32)VXGE_HW_RING_RXD_VLAN_TAG_GET(rxdp->control_1); + rxd_info->rth_bucket = + (u32)VXGE_HW_RING_RXD_RTH_BUCKET_GET(rxdp->control_0); + rxd_info->rth_it_hit = + (u32)VXGE_HW_RING_RXD_RTH_IT_HIT_GET(rxdp->control_0); + rxd_info->rth_spdm_hit = + (u32)VXGE_HW_RING_RXD_RTH_SPDM_HIT_GET(rxdp->control_0); + rxd_info->rth_hash_type = + (u32)VXGE_HW_RING_RXD_RTH_HASH_TYPE_GET(rxdp->control_0); + rxd_info->rth_value = + (u32)VXGE_HW_RING_RXD_1_RTH_HASH_VAL_GET(rxdp->control_1); +} + +/** + * vxge_hw_ring_rxd_private_get - Get driver private per-descriptor data + * of 1b mode 3b mode ring. + * @rxdh: Descriptor handle. + * + * Returns: private driver info associated with the descriptor. + * driver requests per-descriptor space via vxge_hw_ring_attr. + * + */ +static inline void *vxge_hw_ring_rxd_private_get(void *rxdh) +{ + struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh; + return (void *)(size_t)rxdp->host_control; +} + +/** + * vxge_hw_fifo_txdl_cksum_set_bits - Offload checksum. + * @txdlh: Descriptor handle. + * @cksum_bits: Specifies which checksums are to be offloaded: IPv4, + * and/or TCP and/or UDP. + * + * Ask Titan to calculate IPv4 & transport checksums for _this_ transmit + * descriptor. + * This API is part of the preparation of the transmit descriptor for posting + * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include + * vxge_hw_fifo_txdl_mss_set(), vxge_hw_fifo_txdl_buffer_set_aligned(), + * and vxge_hw_fifo_txdl_buffer_set(). + * All these APIs fill in the fields of the fifo descriptor, + * in accordance with the Titan specification. + * + */ +static inline void vxge_hw_fifo_txdl_cksum_set_bits(void *txdlh, u64 cksum_bits) +{ + struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh; + txdp->control_1 |= cksum_bits; +} + +/** + * vxge_hw_fifo_txdl_mss_set - Set MSS. + * @txdlh: Descriptor handle. + * @mss: MSS size for _this_ TCP connection. Passed by TCP stack down to the + * driver, which in turn inserts the MSS into the @txdlh. + * + * This API is part of the preparation of the transmit descriptor for posting + * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include + * vxge_hw_fifo_txdl_buffer_set(), vxge_hw_fifo_txdl_buffer_set_aligned(), + * and vxge_hw_fifo_txdl_cksum_set_bits(). + * All these APIs fill in the fields of the fifo descriptor, + * in accordance with the Titan specification. + * + */ +static inline void vxge_hw_fifo_txdl_mss_set(void *txdlh, int mss) +{ + struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh; + + txdp->control_0 |= VXGE_HW_FIFO_TXD_LSO_EN; + txdp->control_0 |= VXGE_HW_FIFO_TXD_LSO_MSS(mss); +} + +/** + * vxge_hw_fifo_txdl_vlan_set - Set VLAN tag. + * @txdlh: Descriptor handle. + * @vlan_tag: 16bit VLAN tag. + * + * Insert VLAN tag into specified transmit descriptor. + * The actual insertion of the tag into outgoing frame is done by the hardware. + */ +static inline void vxge_hw_fifo_txdl_vlan_set(void *txdlh, u16 vlan_tag) +{ + struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh; + + txdp->control_1 |= VXGE_HW_FIFO_TXD_VLAN_ENABLE; + txdp->control_1 |= VXGE_HW_FIFO_TXD_VLAN_TAG(vlan_tag); +} + +/** + * vxge_hw_fifo_txdl_private_get - Retrieve per-descriptor private data. + * @txdlh: Descriptor handle. + * + * Retrieve per-descriptor private data. + * Note that driver requests per-descriptor space via + * struct vxge_hw_fifo_attr passed to + * vxge_hw_vpath_open(). + * + * Returns: private driver data associated with the descriptor. + */ +static inline void *vxge_hw_fifo_txdl_private_get(void *txdlh) +{ + struct vxge_hw_fifo_txd *txdp = (struct vxge_hw_fifo_txd *)txdlh; + + return (void *)(size_t)txdp->host_control; +} + +/** + * struct vxge_hw_ring_attr - Ring open "template". + * @callback: Ring completion callback. HW invokes the callback when there + * are new completions on that ring. In many implementations + * the @callback executes in the hw interrupt context. + * @rxd_init: Ring's descriptor-initialize callback. + * See vxge_hw_ring_rxd_init_f{}. + * If not NULL, HW invokes the callback when opening + * the ring. + * @rxd_term: Ring's descriptor-terminate callback. If not NULL, + * HW invokes the callback when closing the corresponding ring. + * See also vxge_hw_ring_rxd_term_f{}. + * @userdata: User-defined "context" of _that_ ring. Passed back to the + * user as one of the @callback, @rxd_init, and @rxd_term arguments. + * @per_rxd_space: If specified (i.e., greater than zero): extra space + * reserved by HW per each receive descriptor. + * Can be used to store + * and retrieve on completion, information specific + * to the driver. + * + * Ring open "template". User fills the structure with ring + * attributes and passes it to vxge_hw_vpath_open(). + */ +struct vxge_hw_ring_attr { + enum vxge_hw_status (*callback)( + struct __vxge_hw_ring *ringh, + void *rxdh, + u8 t_code, + void *userdata); + + enum vxge_hw_status (*rxd_init)( + void *rxdh, + void *userdata); + + void (*rxd_term)( + void *rxdh, + enum vxge_hw_rxd_state state, + void *userdata); + + void *userdata; + u32 per_rxd_space; +}; + +/** + * function vxge_hw_fifo_callback_f - FIFO callback. + * @vpath_handle: Virtual path whose Fifo "containing" 1 or more completed + * descriptors. + * @txdlh: First completed descriptor. + * @txdl_priv: Pointer to per txdl space allocated + * @t_code: Transfer code, as per Titan User Guide. + * Returned by HW. + * @host_control: Opaque 64bit data stored by driver inside the Titan + * descriptor prior to posting the latter on the fifo + * via vxge_hw_fifo_txdl_post(). The @host_control is returned + * as is to the driver with each completed descriptor. + * @userdata: Opaque per-fifo data specified at fifo open + * time, via vxge_hw_vpath_open(). + * + * Fifo completion callback (type declaration). A single per-fifo + * callback is specified at fifo open time, via + * vxge_hw_vpath_open(). Typically gets called as part of the processing + * of the Interrupt Service Routine. + * + * Fifo callback gets called by HW if, and only if, there is at least + * one new completion on a given fifo. Upon processing the first @txdlh driver + * is _supposed_ to continue consuming completions using: + * - vxge_hw_fifo_txdl_next_completed() + * + * Note that failure to process new completions in a timely fashion + * leads to VXGE_HW_INF_OUT_OF_DESCRIPTORS condition. + * + * Non-zero @t_code means failure to process transmit descriptor. + * + * In the "transmit" case the failure could happen, for instance, when the + * link is down, in which case Titan completes the descriptor because it + * is not able to send the data out. + * + * For details please refer to Titan User Guide. + * + * See also: vxge_hw_fifo_txdl_next_completed(), vxge_hw_fifo_txdl_term_f{}. + */ +/** + * function vxge_hw_fifo_txdl_term_f - Terminate descriptor callback. + * @txdlh: First completed descriptor. + * @txdl_priv: Pointer to per txdl space allocated + * @state: One of the enum vxge_hw_txdl_state{} enumerated states. + * @userdata: Per-fifo user data (a.k.a. context) specified at + * fifo open time, via vxge_hw_vpath_open(). + * + * Terminate descriptor callback. Unless NULL is specified in the + * struct vxge_hw_fifo_attr{} structure passed to vxge_hw_vpath_open()), + * HW invokes the callback as part of closing fifo, prior to + * de-allocating the ring and associated data structures + * (including descriptors). + * driver should utilize the callback to (for instance) unmap + * and free DMA data buffers associated with the posted (state = + * VXGE_HW_TXDL_STATE_POSTED) descriptors, + * as well as other relevant cleanup functions. + * + * See also: struct vxge_hw_fifo_attr{} + */ +/** + * struct vxge_hw_fifo_attr - Fifo open "template". + * @callback: Fifo completion callback. HW invokes the callback when there + * are new completions on that fifo. In many implementations + * the @callback executes in the hw interrupt context. + * @txdl_term: Fifo's descriptor-terminate callback. If not NULL, + * HW invokes the callback when closing the corresponding fifo. + * See also vxge_hw_fifo_txdl_term_f{}. + * @userdata: User-defined "context" of _that_ fifo. Passed back to the + * user as one of the @callback, and @txdl_term arguments. + * @per_txdl_space: If specified (i.e., greater than zero): extra space + * reserved by HW per each transmit descriptor. Can be used to + * store, and retrieve on completion, information specific + * to the driver. + * + * Fifo open "template". User fills the structure with fifo + * attributes and passes it to vxge_hw_vpath_open(). + */ +struct vxge_hw_fifo_attr { + + enum vxge_hw_status (*callback)( + struct __vxge_hw_fifo *fifo_handle, + void *txdlh, + enum vxge_hw_fifo_tcode t_code, + void *userdata, + void **skb_ptr); + + void (*txdl_term)( + void *txdlh, + enum vxge_hw_txdl_state state, + void *userdata); + + void *userdata; + u32 per_txdl_space; +}; + +/** + * struct vxge_hw_vpath_attr - Attributes of virtual path + * @vp_id: Identifier of Virtual Path + * @ring_attr: Attributes of ring for non-offload receive + * @fifo_attr: Attributes of fifo for non-offload transmit + * + * Attributes of virtual path. This structure is passed as parameter + * to the vxge_hw_vpath_open() routine to set the attributes of ring and fifo. + */ +struct vxge_hw_vpath_attr { + u32 vp_id; + struct vxge_hw_ring_attr ring_attr; + struct vxge_hw_fifo_attr fifo_attr; +}; + +enum vxge_hw_status +__vxge_hw_blockpool_create(struct __vxge_hw_device *hldev, + struct __vxge_hw_blockpool *blockpool, + u32 pool_size, + u32 pool_max); + +void +__vxge_hw_blockpool_destroy(struct __vxge_hw_blockpool *blockpool); + +struct __vxge_hw_blockpool_entry * +__vxge_hw_blockpool_block_allocate(struct __vxge_hw_device *hldev, + u32 size); + +void +__vxge_hw_blockpool_block_free(struct __vxge_hw_device *hldev, + struct __vxge_hw_blockpool_entry *entry); + +void * +__vxge_hw_blockpool_malloc(struct __vxge_hw_device *hldev, + u32 size, + struct vxge_hw_mempool_dma *dma_object); + +void +__vxge_hw_blockpool_free(struct __vxge_hw_device *hldev, + void *memblock, + u32 size, + struct vxge_hw_mempool_dma *dma_object); + +enum vxge_hw_status +__vxge_hw_device_fifo_config_check(struct vxge_hw_fifo_config *fifo_config); + +enum vxge_hw_status +__vxge_hw_device_config_check(struct vxge_hw_device_config *new_config); + +enum vxge_hw_status +vxge_hw_mgmt_device_config(struct __vxge_hw_device *devh, + struct vxge_hw_device_config *dev_config, int size); + +enum vxge_hw_status __devinit vxge_hw_device_hw_info_get( + void __iomem *bar0, + struct vxge_hw_device_hw_info *hw_info); + +enum vxge_hw_status +__vxge_hw_vpath_fw_ver_get( + u32 vp_id, + struct vxge_hw_vpath_reg __iomem *vpath_reg, + struct vxge_hw_device_hw_info *hw_info); + +enum vxge_hw_status +__vxge_hw_vpath_card_info_get( + u32 vp_id, + struct vxge_hw_vpath_reg __iomem *vpath_reg, + struct vxge_hw_device_hw_info *hw_info); + +enum vxge_hw_status __devinit vxge_hw_device_config_default_get( + struct vxge_hw_device_config *device_config); + +/** + * vxge_hw_device_link_state_get - Get link state. + * @devh: HW device handle. + * + * Get link state. + * Returns: link state. + */ +static inline +enum vxge_hw_device_link_state vxge_hw_device_link_state_get( + struct __vxge_hw_device *devh) +{ + return devh->link_state; +} + +void vxge_hw_device_terminate(struct __vxge_hw_device *devh); + +const u8 * +vxge_hw_device_serial_number_get(struct __vxge_hw_device *devh); + +u16 vxge_hw_device_link_width_get(struct __vxge_hw_device *devh); + +const u8 * +vxge_hw_device_product_name_get(struct __vxge_hw_device *devh); + +enum vxge_hw_status __devinit vxge_hw_device_initialize( + struct __vxge_hw_device **devh, + struct vxge_hw_device_attr *attr, + struct vxge_hw_device_config *device_config); + +enum vxge_hw_status vxge_hw_device_getpause_data( + struct __vxge_hw_device *devh, + u32 port, + u32 *tx, + u32 *rx); + +enum vxge_hw_status vxge_hw_device_setpause_data( + struct __vxge_hw_device *devh, + u32 port, + u32 tx, + u32 rx); + +static inline void *vxge_os_dma_malloc(struct pci_dev *pdev, + unsigned long size, + struct pci_dev **p_dmah, + struct pci_dev **p_dma_acch) +{ + gfp_t flags; + void *vaddr; + unsigned long misaligned = 0; + *p_dma_acch = *p_dmah = NULL; + + if (in_interrupt()) + flags = GFP_ATOMIC | GFP_DMA; + else + flags = GFP_KERNEL | GFP_DMA; + + size += VXGE_CACHE_LINE_SIZE; + + vaddr = kmalloc((size), flags); + if (vaddr == NULL) + return vaddr; + misaligned = (unsigned long)VXGE_ALIGN(*((u64 *)&vaddr), + VXGE_CACHE_LINE_SIZE); + *(unsigned long *)p_dma_acch = misaligned; + vaddr = (void *)((u8 *)vaddr + misaligned); + return vaddr; +} + +extern void vxge_hw_blockpool_block_add( + struct __vxge_hw_device *devh, + void *block_addr, + u32 length, + struct pci_dev *dma_h, + struct pci_dev *acc_handle); + +static inline void vxge_os_dma_malloc_async(struct pci_dev *pdev, void *devh, + unsigned long size) +{ + gfp_t flags; + void *vaddr; + + if (in_interrupt()) + flags = GFP_ATOMIC | GFP_DMA; + else + flags = GFP_KERNEL | GFP_DMA; + + vaddr = kmalloc((size), flags); + + vxge_hw_blockpool_block_add(devh, vaddr, size, pdev, pdev); +} + +static inline void vxge_os_dma_free(struct pci_dev *pdev, const void *vaddr, + struct pci_dev **p_dma_acch) +{ + unsigned long misaligned = *(unsigned long *)p_dma_acch; + u8 *tmp = (u8 *)vaddr; + tmp -= misaligned; + kfree((void *)tmp); +} + +/* + * __vxge_hw_mempool_item_priv - will return pointer on per item private space + */ +static inline void* +__vxge_hw_mempool_item_priv( + struct vxge_hw_mempool *mempool, + u32 memblock_idx, + void *item, + u32 *memblock_item_idx) +{ + ptrdiff_t offset; + void *memblock = mempool->memblocks_arr[memblock_idx]; + + + offset = (u32)((u8 *)item - (u8 *)memblock); + vxge_assert(offset >= 0 && (u32)offset < mempool->memblock_size); + + (*memblock_item_idx) = (u32) offset / mempool->item_size; + vxge_assert((*memblock_item_idx) < mempool->items_per_memblock); + + return (u8 *)mempool->memblocks_priv_arr[memblock_idx] + + (*memblock_item_idx) * mempool->items_priv_size; +} + +enum vxge_hw_status +__vxge_hw_mempool_grow( + struct vxge_hw_mempool *mempool, + u32 num_allocate, + u32 *num_allocated); + +struct vxge_hw_mempool* +__vxge_hw_mempool_create( + struct __vxge_hw_device *devh, + u32 memblock_size, + u32 item_size, + u32 private_size, + u32 items_initial, + u32 items_max, + struct vxge_hw_mempool_cbs *mp_callback, + void *userdata); + +struct __vxge_hw_channel* +__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph, + enum __vxge_hw_channel_type type, u32 length, + u32 per_dtr_space, void *userdata); + +void +__vxge_hw_channel_free( + struct __vxge_hw_channel *channel); + +enum vxge_hw_status +__vxge_hw_channel_initialize( + struct __vxge_hw_channel *channel); + +enum vxge_hw_status +__vxge_hw_channel_reset( + struct __vxge_hw_channel *channel); + +/* + * __vxge_hw_fifo_txdl_priv - Return the max fragments allocated + * for the fifo. + * @fifo: Fifo + * @txdp: Poniter to a TxD + */ +static inline struct __vxge_hw_fifo_txdl_priv * +__vxge_hw_fifo_txdl_priv( + struct __vxge_hw_fifo *fifo, + struct vxge_hw_fifo_txd *txdp) +{ + return (struct __vxge_hw_fifo_txdl_priv *) + (((char *)((ulong)txdp->host_control)) + + fifo->per_txdl_space); +} + +enum vxge_hw_status vxge_hw_vpath_open( + struct __vxge_hw_device *devh, + struct vxge_hw_vpath_attr *attr, + struct __vxge_hw_vpath_handle **vpath_handle); + +enum vxge_hw_status +__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog); + +enum vxge_hw_status vxge_hw_vpath_close( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status +vxge_hw_vpath_reset( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status +vxge_hw_vpath_recover_from_reset( + struct __vxge_hw_vpath_handle *vpath_handle); + +void +vxge_hw_vpath_enable(struct __vxge_hw_vpath_handle *vp); + +enum vxge_hw_status +vxge_hw_vpath_check_leak(struct __vxge_hw_ring *ringh); + +enum vxge_hw_status vxge_hw_vpath_mtu_set( + struct __vxge_hw_vpath_handle *vpath_handle, + u32 new_mtu); + +enum vxge_hw_status vxge_hw_vpath_stats_enable( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status +__vxge_hw_vpath_stats_access( + struct __vxge_hw_virtualpath *vpath, + u32 operation, + u32 offset, + u64 *stat); + +enum vxge_hw_status +__vxge_hw_vpath_xmac_tx_stats_get( + struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_xmac_vpath_tx_stats *vpath_tx_stats); + +enum vxge_hw_status +__vxge_hw_vpath_xmac_rx_stats_get( + struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_xmac_vpath_rx_stats *vpath_rx_stats); + +enum vxge_hw_status +__vxge_hw_vpath_stats_get( + struct __vxge_hw_virtualpath *vpath, + struct vxge_hw_vpath_stats_hw_info *hw_stats); + +void +vxge_hw_vpath_rx_doorbell_init(struct __vxge_hw_vpath_handle *vp); + +enum vxge_hw_status +__vxge_hw_device_vpath_config_check(struct vxge_hw_vp_config *vp_config); + +void +__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev); + +enum vxge_hw_status +__vxge_hw_legacy_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg); + +enum vxge_hw_status +__vxge_hw_vpath_swapper_set(struct vxge_hw_vpath_reg __iomem *vpath_reg); + +enum vxge_hw_status +__vxge_hw_kdfc_swapper_set(struct vxge_hw_legacy_reg __iomem *legacy_reg, + struct vxge_hw_vpath_reg __iomem *vpath_reg); + +enum vxge_hw_status +__vxge_hw_device_register_poll( + void __iomem *reg, + u64 mask, u32 max_millis); + +#ifndef readq +static inline u64 readq(void __iomem *addr) +{ + u64 ret = 0; + ret = readl(addr + 4); + ret <<= 32; + ret |= readl(addr); + + return ret; +} +#endif + +#ifndef writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel((u32) (val), addr); + writel((u32) (val >> 32), (addr + 4)); +} +#endif + +static inline void __vxge_hw_pio_mem_write32_upper(u32 val, void __iomem *addr) +{ + writel(val, addr + 4); +} + +static inline void __vxge_hw_pio_mem_write32_lower(u32 val, void __iomem *addr) +{ + writel(val, addr); +} + +static inline enum vxge_hw_status +__vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr, + u64 mask, u32 max_millis) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + __vxge_hw_pio_mem_write32_lower((u32)vxge_bVALn(val64, 32, 32), addr); + wmb(); + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), addr); + wmb(); + + status = __vxge_hw_device_register_poll(addr, mask, max_millis); + return status; +} + +struct vxge_hw_toc_reg __iomem * +__vxge_hw_device_toc_get(void __iomem *bar0); + +enum vxge_hw_status +__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev); + +void +__vxge_hw_device_id_get(struct __vxge_hw_device *hldev); + +void +__vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev); + +enum vxge_hw_status +vxge_hw_device_flick_link_led(struct __vxge_hw_device *devh, u64 on_off); + +enum vxge_hw_status +__vxge_hw_device_initialize(struct __vxge_hw_device *hldev); + +enum vxge_hw_status +__vxge_hw_vpath_pci_read( + struct __vxge_hw_virtualpath *vpath, + u32 phy_func_0, + u32 offset, + u32 *val); + +enum vxge_hw_status +__vxge_hw_vpath_addr_get( + u32 vp_id, + struct vxge_hw_vpath_reg __iomem *vpath_reg, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN]); + +u32 +__vxge_hw_vpath_func_id_get( + u32 vp_id, struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg); + +enum vxge_hw_status +__vxge_hw_vpath_reset_check(struct __vxge_hw_virtualpath *vpath); + +/** + * vxge_debug + * @level: level of debug verbosity. + * @mask: mask for the debug + * @buf: Circular buffer for tracing + * @fmt: printf like format string + * + * Provides logging facilities. Can be customized on per-module + * basis or/and with debug levels. Input parameters, except + * module and level, are the same as posix printf. This function + * may be compiled out if DEBUG macro was never defined. + * See also: enum vxge_debug_level{}. + */ + +#define vxge_trace_aux(level, mask, fmt, ...) \ +{\ + vxge_os_vaprintf(level, mask, fmt, __VA_ARGS__);\ +} + +#define vxge_debug(module, level, mask, fmt, ...) { \ +if ((level >= VXGE_TRACE && ((module & VXGE_DEBUG_TRACE_MASK) == module)) || \ + (level >= VXGE_ERR && ((module & VXGE_DEBUG_ERR_MASK) == module))) {\ + if ((mask & VXGE_DEBUG_MASK) == mask)\ + vxge_trace_aux(level, mask, fmt, __VA_ARGS__); \ +} \ +} + +#if (VXGE_COMPONENT_LL & VXGE_DEBUG_MODULE_MASK) +#define vxge_debug_ll(level, mask, fmt, ...) \ +{\ + vxge_debug(VXGE_COMPONENT_LL, level, mask, fmt, __VA_ARGS__);\ +} + +#else +#define vxge_debug_ll(level, mask, fmt, ...) +#endif + +enum vxge_hw_status vxge_hw_vpath_rts_rth_itable_set( + struct __vxge_hw_vpath_handle **vpath_handles, + u32 vpath_count, + u8 *mtable, + u8 *itable, + u32 itable_size); + +enum vxge_hw_status vxge_hw_vpath_rts_rth_set( + struct __vxge_hw_vpath_handle *vpath_handle, + enum vxge_hw_rth_algoritms algorithm, + struct vxge_hw_rth_hash_types *hash_type, + u16 bucket_size); + +#endif diff --git a/trunk/drivers/net/vxge/vxge-ethtool.c b/trunk/drivers/net/vxge/vxge-ethtool.c new file mode 100644 index 000000000000..c6736b972635 --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-ethtool.c @@ -0,0 +1,1148 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-ethtool.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#include +#include +#include + +#include "vxge-ethtool.h" + +/** + * vxge_ethtool_sset - Sets different link parameters. + * @dev: device pointer. + * @info: pointer to the structure with parameters given by ethtool to set + * link information. + * + * The function sets different link parameters provided by the user onto + * the NIC. + * Return value: + * 0 on success. + */ + +static int vxge_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) +{ + /* We currently only support 10Gb/FULL */ + if ((info->autoneg == AUTONEG_ENABLE) || + (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) + return -EINVAL; + + return 0; +} + +/** + * vxge_ethtool_gset - Return link specific information. + * @dev: device pointer. + * @info: pointer to the structure with parameters given by ethtool + * to return link information. + * + * Returns link specific information like speed, duplex etc.. to ethtool. + * Return value : + * return 0 on success. + */ +static int vxge_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) +{ + info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + info->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + info->port = PORT_FIBRE; + + info->transceiver = XCVR_EXTERNAL; + + if (netif_carrier_ok(dev)) { + info->speed = SPEED_10000; + info->duplex = DUPLEX_FULL; + } else { + info->speed = -1; + info->duplex = -1; + } + + info->autoneg = AUTONEG_DISABLE; + return 0; +} + +/** + * vxge_ethtool_gdrvinfo - Returns driver specific information. + * @dev: device pointer. + * @info: pointer to the structure with parameters given by ethtool to + * return driver information. + * + * Returns driver specefic information like name, version etc.. to ethtool. + */ +static void vxge_ethtool_gdrvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct vxgedev *vdev; + vdev = (struct vxgedev *)netdev_priv(dev); + strlcpy(info->driver, VXGE_DRIVER_NAME, sizeof(VXGE_DRIVER_NAME)); + strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION)); + strlcpy(info->fw_version, vdev->fw_version, VXGE_HW_FW_STRLEN); + strlcpy(info->bus_info, pci_name(vdev->pdev), sizeof(info->bus_info)); + info->regdump_len = sizeof(struct vxge_hw_vpath_reg) + * vdev->no_of_vpath; + + info->n_stats = STAT_LEN; +} + +/** + * vxge_ethtool_gregs - dumps the entire space of Titan into the buffer. + * @dev: device pointer. + * @regs: pointer to the structure with parameters given by ethtool for + * dumping the registers. + * @reg_space: The input argumnet into which all the registers are dumped. + * + * Dumps the vpath register space of Titan NIC into the user given + * buffer area. + */ +static void vxge_ethtool_gregs(struct net_device *dev, + struct ethtool_regs *regs, void *space) +{ + int index, offset; + enum vxge_hw_status status; + u64 reg; + u8 *reg_space = (u8 *) space; + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) + pci_get_drvdata(vdev->pdev); + + regs->len = sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath; + regs->version = vdev->pdev->subsystem_device; + for (index = 0; index < vdev->no_of_vpath; index++) { + for (offset = 0; offset < sizeof(struct vxge_hw_vpath_reg); + offset += 8) { + status = vxge_hw_mgmt_reg_read(hldev, + vxge_hw_mgmt_reg_type_vpath, + vdev->vpaths[index].device_id, + offset, ®); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s:%d Getting reg dump Failed", + __func__, __LINE__); + return; + } + + memcpy((reg_space + offset), ®, 8); + } + } +} + +/** + * vxge_ethtool_idnic - To physically identify the nic on the system. + * @dev : device pointer. + * @id : pointer to the structure with identification parameters given by + * ethtool. + * + * Used to physically identify the NIC on the system. + * The Link LED will blink for a time specified by the user. + * Return value: + * 0 on success + */ +static int vxge_ethtool_idnic(struct net_device *dev, u32 data) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) + pci_get_drvdata(vdev->pdev); + + vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON); + msleep_interruptible(data ? (data * HZ) : VXGE_MAX_FLICKER_TIME); + vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF); + + return 0; +} + +/** + * vxge_ethtool_getpause_data - Pause frame frame generation and reception. + * @dev : device pointer. + * @ep : pointer to the structure with pause parameters given by ethtool. + * Description: + * Returns the Pause frame generation and reception capability of the NIC. + * Return value: + * void + */ +static void vxge_ethtool_getpause_data(struct net_device *dev, + struct ethtool_pauseparam *ep) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) + pci_get_drvdata(vdev->pdev); + + vxge_hw_device_getpause_data(hldev, 0, &ep->tx_pause, &ep->rx_pause); +} + +/** + * vxge_ethtool_setpause_data - set/reset pause frame generation. + * @dev : device pointer. + * @ep : pointer to the structure with pause parameters given by ethtool. + * Description: + * It can be used to set or reset Pause frame generation or reception + * support of the NIC. + * Return value: + * int, returns 0 on Success + */ +static int vxge_ethtool_setpause_data(struct net_device *dev, + struct ethtool_pauseparam *ep) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) + pci_get_drvdata(vdev->pdev); + + vxge_hw_device_setpause_data(hldev, 0, ep->tx_pause, ep->rx_pause); + + vdev->config.tx_pause_enable = ep->tx_pause; + vdev->config.rx_pause_enable = ep->rx_pause; + + return 0; +} + +static void vxge_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *estats, u64 *tmp_stats) +{ + int j, k; + enum vxge_hw_status status; + enum vxge_hw_status swstatus; + struct vxge_vpath *vpath = NULL; + + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + struct __vxge_hw_device *hldev = vdev->devh; + struct vxge_hw_xmac_stats *xmac_stats; + struct vxge_hw_device_stats_sw_info *sw_stats; + struct vxge_hw_device_stats_hw_info *hw_stats; + + u64 *ptr = tmp_stats; + + memset(tmp_stats, 0, + vxge_ethtool_get_sset_count(dev, ETH_SS_STATS) * sizeof(u64)); + + xmac_stats = kzalloc(sizeof(struct vxge_hw_xmac_stats), GFP_KERNEL); + if (xmac_stats == NULL) { + vxge_debug_init(VXGE_ERR, + "%s : %d Memory Allocation failed for xmac_stats", + __func__, __LINE__); + return; + } + + sw_stats = kzalloc(sizeof(struct vxge_hw_device_stats_sw_info), + GFP_KERNEL); + if (sw_stats == NULL) { + kfree(xmac_stats); + vxge_debug_init(VXGE_ERR, + "%s : %d Memory Allocation failed for sw_stats", + __func__, __LINE__); + return; + } + + hw_stats = kzalloc(sizeof(struct vxge_hw_device_stats_hw_info), + GFP_KERNEL); + if (hw_stats == NULL) { + kfree(xmac_stats); + kfree(sw_stats); + vxge_debug_init(VXGE_ERR, + "%s : %d Memory Allocation failed for hw_stats", + __func__, __LINE__); + return; + } + + *ptr++ = 0; + status = vxge_hw_device_xmac_stats_get(hldev, xmac_stats); + if (status != VXGE_HW_OK) { + if (status != VXGE_HW_ERR_PRIVILAGED_OPEARATION) { + vxge_debug_init(VXGE_ERR, + "%s : %d Failure in getting xmac stats", + __func__, __LINE__); + } + } + swstatus = vxge_hw_driver_stats_get(hldev, sw_stats); + if (swstatus != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s : %d Failure in getting sw stats", + __func__, __LINE__); + } + + status = vxge_hw_device_stats_get(hldev, hw_stats); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s : %d hw_stats_get error", __func__, __LINE__); + } + + for (k = 0; k < vdev->no_of_vpath; k++) { + struct vxge_hw_vpath_stats_hw_info *vpath_info; + + vpath = &vdev->vpaths[k]; + j = vpath->device_id; + vpath_info = hw_stats->vpath_info[j]; + if (!vpath_info) { + memset(ptr, 0, (VXGE_HW_VPATH_TX_STATS_LEN + + VXGE_HW_VPATH_RX_STATS_LEN) * sizeof(u64)); + ptr += (VXGE_HW_VPATH_TX_STATS_LEN + + VXGE_HW_VPATH_RX_STATS_LEN); + continue; + } + + *ptr++ = vpath_info->tx_stats.tx_ttl_eth_frms; + *ptr++ = vpath_info->tx_stats.tx_ttl_eth_octets; + *ptr++ = vpath_info->tx_stats.tx_data_octets; + *ptr++ = vpath_info->tx_stats.tx_mcast_frms; + *ptr++ = vpath_info->tx_stats.tx_bcast_frms; + *ptr++ = vpath_info->tx_stats.tx_ucast_frms; + *ptr++ = vpath_info->tx_stats.tx_tagged_frms; + *ptr++ = vpath_info->tx_stats.tx_vld_ip; + *ptr++ = vpath_info->tx_stats.tx_vld_ip_octets; + *ptr++ = vpath_info->tx_stats.tx_icmp; + *ptr++ = vpath_info->tx_stats.tx_tcp; + *ptr++ = vpath_info->tx_stats.tx_rst_tcp; + *ptr++ = vpath_info->tx_stats.tx_udp; + *ptr++ = vpath_info->tx_stats.tx_unknown_protocol; + *ptr++ = vpath_info->tx_stats.tx_lost_ip; + *ptr++ = vpath_info->tx_stats.tx_parse_error; + *ptr++ = vpath_info->tx_stats.tx_tcp_offload; + *ptr++ = vpath_info->tx_stats.tx_retx_tcp_offload; + *ptr++ = vpath_info->tx_stats.tx_lost_ip_offload; + *ptr++ = vpath_info->rx_stats.rx_ttl_eth_frms; + *ptr++ = vpath_info->rx_stats.rx_vld_frms; + *ptr++ = vpath_info->rx_stats.rx_offload_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_eth_octets; + *ptr++ = vpath_info->rx_stats.rx_data_octets; + *ptr++ = vpath_info->rx_stats.rx_offload_octets; + *ptr++ = vpath_info->rx_stats.rx_vld_mcast_frms; + *ptr++ = vpath_info->rx_stats.rx_vld_bcast_frms; + *ptr++ = vpath_info->rx_stats.rx_accepted_ucast_frms; + *ptr++ = vpath_info->rx_stats.rx_accepted_nucast_frms; + *ptr++ = vpath_info->rx_stats.rx_tagged_frms; + *ptr++ = vpath_info->rx_stats.rx_long_frms; + *ptr++ = vpath_info->rx_stats.rx_usized_frms; + *ptr++ = vpath_info->rx_stats.rx_osized_frms; + *ptr++ = vpath_info->rx_stats.rx_frag_frms; + *ptr++ = vpath_info->rx_stats.rx_jabber_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_64_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_65_127_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_128_255_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_256_511_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_512_1023_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_1024_1518_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_1519_4095_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_4096_8191_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_8192_max_frms; + *ptr++ = vpath_info->rx_stats.rx_ttl_gt_max_frms; + *ptr++ = vpath_info->rx_stats.rx_ip; + *ptr++ = vpath_info->rx_stats.rx_accepted_ip; + *ptr++ = vpath_info->rx_stats.rx_ip_octets; + *ptr++ = vpath_info->rx_stats.rx_err_ip; + *ptr++ = vpath_info->rx_stats.rx_icmp; + *ptr++ = vpath_info->rx_stats.rx_tcp; + *ptr++ = vpath_info->rx_stats.rx_udp; + *ptr++ = vpath_info->rx_stats.rx_err_tcp; + *ptr++ = vpath_info->rx_stats.rx_lost_frms; + *ptr++ = vpath_info->rx_stats.rx_lost_ip; + *ptr++ = vpath_info->rx_stats.rx_lost_ip_offload; + *ptr++ = vpath_info->rx_stats.rx_various_discard; + *ptr++ = vpath_info->rx_stats.rx_sleep_discard; + *ptr++ = vpath_info->rx_stats.rx_red_discard; + *ptr++ = vpath_info->rx_stats.rx_queue_full_discard; + *ptr++ = vpath_info->rx_stats.rx_mpa_ok_frms; + } + *ptr++ = 0; + for (k = 0; k < vdev->max_config_port; k++) { + *ptr++ = xmac_stats->aggr_stats[k].tx_frms; + *ptr++ = xmac_stats->aggr_stats[k].tx_data_octets; + *ptr++ = xmac_stats->aggr_stats[k].tx_mcast_frms; + *ptr++ = xmac_stats->aggr_stats[k].tx_bcast_frms; + *ptr++ = xmac_stats->aggr_stats[k].tx_discarded_frms; + *ptr++ = xmac_stats->aggr_stats[k].tx_errored_frms; + *ptr++ = xmac_stats->aggr_stats[k].rx_frms; + *ptr++ = xmac_stats->aggr_stats[k].rx_data_octets; + *ptr++ = xmac_stats->aggr_stats[k].rx_mcast_frms; + *ptr++ = xmac_stats->aggr_stats[k].rx_bcast_frms; + *ptr++ = xmac_stats->aggr_stats[k].rx_discarded_frms; + *ptr++ = xmac_stats->aggr_stats[k].rx_errored_frms; + *ptr++ = xmac_stats->aggr_stats[k].rx_unknown_slow_proto_frms; + } + *ptr++ = 0; + for (k = 0; k < vdev->max_config_port; k++) { + *ptr++ = xmac_stats->port_stats[k].tx_ttl_frms; + *ptr++ = xmac_stats->port_stats[k].tx_ttl_octets; + *ptr++ = xmac_stats->port_stats[k].tx_data_octets; + *ptr++ = xmac_stats->port_stats[k].tx_mcast_frms; + *ptr++ = xmac_stats->port_stats[k].tx_bcast_frms; + *ptr++ = xmac_stats->port_stats[k].tx_ucast_frms; + *ptr++ = xmac_stats->port_stats[k].tx_tagged_frms; + *ptr++ = xmac_stats->port_stats[k].tx_vld_ip; + *ptr++ = xmac_stats->port_stats[k].tx_vld_ip_octets; + *ptr++ = xmac_stats->port_stats[k].tx_icmp; + *ptr++ = xmac_stats->port_stats[k].tx_tcp; + *ptr++ = xmac_stats->port_stats[k].tx_rst_tcp; + *ptr++ = xmac_stats->port_stats[k].tx_udp; + *ptr++ = xmac_stats->port_stats[k].tx_parse_error; + *ptr++ = xmac_stats->port_stats[k].tx_unknown_protocol; + *ptr++ = xmac_stats->port_stats[k].tx_pause_ctrl_frms; + *ptr++ = xmac_stats->port_stats[k].tx_marker_pdu_frms; + *ptr++ = xmac_stats->port_stats[k].tx_lacpdu_frms; + *ptr++ = xmac_stats->port_stats[k].tx_drop_ip; + *ptr++ = xmac_stats->port_stats[k].tx_marker_resp_pdu_frms; + *ptr++ = xmac_stats->port_stats[k].tx_xgmii_char2_match; + *ptr++ = xmac_stats->port_stats[k].tx_xgmii_char1_match; + *ptr++ = xmac_stats->port_stats[k].tx_xgmii_column2_match; + *ptr++ = xmac_stats->port_stats[k].tx_xgmii_column1_match; + *ptr++ = xmac_stats->port_stats[k].tx_any_err_frms; + *ptr++ = xmac_stats->port_stats[k].tx_drop_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_frms; + *ptr++ = xmac_stats->port_stats[k].rx_vld_frms; + *ptr++ = xmac_stats->port_stats[k].rx_offload_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_octets; + *ptr++ = xmac_stats->port_stats[k].rx_data_octets; + *ptr++ = xmac_stats->port_stats[k].rx_offload_octets; + *ptr++ = xmac_stats->port_stats[k].rx_vld_mcast_frms; + *ptr++ = xmac_stats->port_stats[k].rx_vld_bcast_frms; + *ptr++ = xmac_stats->port_stats[k].rx_accepted_ucast_frms; + *ptr++ = xmac_stats->port_stats[k].rx_accepted_nucast_frms; + *ptr++ = xmac_stats->port_stats[k].rx_tagged_frms; + *ptr++ = xmac_stats->port_stats[k].rx_long_frms; + *ptr++ = xmac_stats->port_stats[k].rx_usized_frms; + *ptr++ = xmac_stats->port_stats[k].rx_osized_frms; + *ptr++ = xmac_stats->port_stats[k].rx_frag_frms; + *ptr++ = xmac_stats->port_stats[k].rx_jabber_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_64_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_65_127_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_128_255_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_256_511_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_512_1023_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_1024_1518_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_1519_4095_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_4096_8191_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_8192_max_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ttl_gt_max_frms; + *ptr++ = xmac_stats->port_stats[k].rx_ip; + *ptr++ = xmac_stats->port_stats[k].rx_accepted_ip; + *ptr++ = xmac_stats->port_stats[k].rx_ip_octets; + *ptr++ = xmac_stats->port_stats[k].rx_err_ip; + *ptr++ = xmac_stats->port_stats[k].rx_icmp; + *ptr++ = xmac_stats->port_stats[k].rx_tcp; + *ptr++ = xmac_stats->port_stats[k].rx_udp; + *ptr++ = xmac_stats->port_stats[k].rx_err_tcp; + *ptr++ = xmac_stats->port_stats[k].rx_pause_count; + *ptr++ = xmac_stats->port_stats[k].rx_pause_ctrl_frms; + *ptr++ = xmac_stats->port_stats[k].rx_unsup_ctrl_frms; + *ptr++ = xmac_stats->port_stats[k].rx_fcs_err_frms; + *ptr++ = xmac_stats->port_stats[k].rx_in_rng_len_err_frms; + *ptr++ = xmac_stats->port_stats[k].rx_out_rng_len_err_frms; + *ptr++ = xmac_stats->port_stats[k].rx_drop_frms; + *ptr++ = xmac_stats->port_stats[k].rx_discarded_frms; + *ptr++ = xmac_stats->port_stats[k].rx_drop_ip; + *ptr++ = xmac_stats->port_stats[k].rx_drop_udp; + *ptr++ = xmac_stats->port_stats[k].rx_marker_pdu_frms; + *ptr++ = xmac_stats->port_stats[k].rx_lacpdu_frms; + *ptr++ = xmac_stats->port_stats[k].rx_unknown_pdu_frms; + *ptr++ = xmac_stats->port_stats[k].rx_marker_resp_pdu_frms; + *ptr++ = xmac_stats->port_stats[k].rx_fcs_discard; + *ptr++ = xmac_stats->port_stats[k].rx_illegal_pdu_frms; + *ptr++ = xmac_stats->port_stats[k].rx_switch_discard; + *ptr++ = xmac_stats->port_stats[k].rx_len_discard; + *ptr++ = xmac_stats->port_stats[k].rx_rpa_discard; + *ptr++ = xmac_stats->port_stats[k].rx_l2_mgmt_discard; + *ptr++ = xmac_stats->port_stats[k].rx_rts_discard; + *ptr++ = xmac_stats->port_stats[k].rx_trash_discard; + *ptr++ = xmac_stats->port_stats[k].rx_buff_full_discard; + *ptr++ = xmac_stats->port_stats[k].rx_red_discard; + *ptr++ = xmac_stats->port_stats[k].rx_xgmii_ctrl_err_cnt; + *ptr++ = xmac_stats->port_stats[k].rx_xgmii_data_err_cnt; + *ptr++ = xmac_stats->port_stats[k].rx_xgmii_char1_match; + *ptr++ = xmac_stats->port_stats[k].rx_xgmii_err_sym; + *ptr++ = xmac_stats->port_stats[k].rx_xgmii_column1_match; + *ptr++ = xmac_stats->port_stats[k].rx_xgmii_char2_match; + *ptr++ = xmac_stats->port_stats[k].rx_local_fault; + *ptr++ = xmac_stats->port_stats[k].rx_xgmii_column2_match; + *ptr++ = xmac_stats->port_stats[k].rx_jettison; + *ptr++ = xmac_stats->port_stats[k].rx_remote_fault; + } + + *ptr++ = 0; + for (k = 0; k < vdev->no_of_vpath; k++) { + struct vxge_hw_vpath_stats_sw_info *vpath_info; + + vpath = &vdev->vpaths[k]; + j = vpath->device_id; + vpath_info = (struct vxge_hw_vpath_stats_sw_info *) + &sw_stats->vpath_info[j]; + *ptr++ = vpath_info->soft_reset_cnt; + *ptr++ = vpath_info->error_stats.unknown_alarms; + *ptr++ = vpath_info->error_stats.network_sustained_fault; + *ptr++ = vpath_info->error_stats.network_sustained_ok; + *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_overwrite; + *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_poison; + *ptr++ = vpath_info->error_stats.kdfcctl_fifo0_dma_error; + *ptr++ = vpath_info->error_stats.dblgen_fifo0_overflow; + *ptr++ = vpath_info->error_stats.statsb_pif_chain_error; + *ptr++ = vpath_info->error_stats.statsb_drop_timeout; + *ptr++ = vpath_info->error_stats.target_illegal_access; + *ptr++ = vpath_info->error_stats.ini_serr_det; + *ptr++ = vpath_info->error_stats.prc_ring_bumps; + *ptr++ = vpath_info->error_stats.prc_rxdcm_sc_err; + *ptr++ = vpath_info->error_stats.prc_rxdcm_sc_abort; + *ptr++ = vpath_info->error_stats.prc_quanta_size_err; + *ptr++ = vpath_info->ring_stats.common_stats.full_cnt; + *ptr++ = vpath_info->ring_stats.common_stats.usage_cnt; + *ptr++ = vpath_info->ring_stats.common_stats.usage_max; + *ptr++ = vpath_info->ring_stats.common_stats. + reserve_free_swaps_cnt; + *ptr++ = vpath_info->ring_stats.common_stats.total_compl_cnt; + for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++) + *ptr++ = vpath_info->ring_stats.rxd_t_code_err_cnt[j]; + *ptr++ = vpath_info->fifo_stats.common_stats.full_cnt; + *ptr++ = vpath_info->fifo_stats.common_stats.usage_cnt; + *ptr++ = vpath_info->fifo_stats.common_stats.usage_max; + *ptr++ = vpath_info->fifo_stats.common_stats. + reserve_free_swaps_cnt; + *ptr++ = vpath_info->fifo_stats.common_stats.total_compl_cnt; + *ptr++ = vpath_info->fifo_stats.total_posts; + *ptr++ = vpath_info->fifo_stats.total_buffers; + for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++) + *ptr++ = vpath_info->fifo_stats.txd_t_code_err_cnt[j]; + } + + *ptr++ = 0; + for (k = 0; k < vdev->no_of_vpath; k++) { + struct vxge_hw_vpath_stats_hw_info *vpath_info; + vpath = &vdev->vpaths[k]; + j = vpath->device_id; + vpath_info = hw_stats->vpath_info[j]; + if (!vpath_info) { + memset(ptr, 0, VXGE_HW_VPATH_STATS_LEN * sizeof(u64)); + ptr += VXGE_HW_VPATH_STATS_LEN; + continue; + } + *ptr++ = vpath_info->ini_num_mwr_sent; + *ptr++ = vpath_info->ini_num_mrd_sent; + *ptr++ = vpath_info->ini_num_cpl_rcvd; + *ptr++ = vpath_info->ini_num_mwr_byte_sent; + *ptr++ = vpath_info->ini_num_cpl_byte_rcvd; + *ptr++ = vpath_info->wrcrdtarb_xoff; + *ptr++ = vpath_info->rdcrdtarb_xoff; + *ptr++ = vpath_info->vpath_genstats_count0; + *ptr++ = vpath_info->vpath_genstats_count1; + *ptr++ = vpath_info->vpath_genstats_count2; + *ptr++ = vpath_info->vpath_genstats_count3; + *ptr++ = vpath_info->vpath_genstats_count4; + *ptr++ = vpath_info->vpath_genstats_count5; + *ptr++ = vpath_info->prog_event_vnum0; + *ptr++ = vpath_info->prog_event_vnum1; + *ptr++ = vpath_info->prog_event_vnum2; + *ptr++ = vpath_info->prog_event_vnum3; + *ptr++ = vpath_info->rx_multi_cast_frame_discard; + *ptr++ = vpath_info->rx_frm_transferred; + *ptr++ = vpath_info->rxd_returned; + *ptr++ = vpath_info->rx_mpa_len_fail_frms; + *ptr++ = vpath_info->rx_mpa_mrk_fail_frms; + *ptr++ = vpath_info->rx_mpa_crc_fail_frms; + *ptr++ = vpath_info->rx_permitted_frms; + *ptr++ = vpath_info->rx_vp_reset_discarded_frms; + *ptr++ = vpath_info->rx_wol_frms; + *ptr++ = vpath_info->tx_vp_reset_discarded_frms; + } + + *ptr++ = 0; + *ptr++ = vdev->stats.vpaths_open; + *ptr++ = vdev->stats.vpath_open_fail; + *ptr++ = vdev->stats.link_up; + *ptr++ = vdev->stats.link_down; + + for (k = 0; k < vdev->no_of_vpath; k++) { + *ptr += vdev->vpaths[k].fifo.stats.tx_frms; + *(ptr + 1) += vdev->vpaths[k].fifo.stats.tx_errors; + *(ptr + 2) += vdev->vpaths[k].fifo.stats.tx_bytes; + *(ptr + 3) += vdev->vpaths[k].fifo.stats.txd_not_free; + *(ptr + 4) += vdev->vpaths[k].fifo.stats.txd_out_of_desc; + *(ptr + 5) += vdev->vpaths[k].ring.stats.rx_frms; + *(ptr + 6) += vdev->vpaths[k].ring.stats.rx_errors; + *(ptr + 7) += vdev->vpaths[k].ring.stats.rx_bytes; + *(ptr + 8) += vdev->vpaths[k].ring.stats.rx_mcast; + *(ptr + 9) += vdev->vpaths[k].fifo.stats.pci_map_fail + + vdev->vpaths[k].ring.stats.pci_map_fail; + *(ptr + 10) += vdev->vpaths[k].ring.stats.skb_alloc_fail; + } + + ptr += 12; + + kfree(xmac_stats); + kfree(sw_stats); + kfree(hw_stats); +} + +static void vxge_ethtool_get_strings(struct net_device *dev, + u32 stringset, u8 *data) +{ + int stat_size = 0; + int i, j; + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + switch (stringset) { + case ETH_SS_STATS: + vxge_add_string("VPATH STATISTICS%s\t\t\t", + &stat_size, data, ""); + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_add_string("tx_ttl_eth_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_ttl_eth_octects_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_data_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_mcast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_bcast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_ucast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_tagged_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_vld_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_vld_ip_octects_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_icmp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_tcp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_rst_tcp_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_udp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_unknown_proto_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_lost_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_parse_error_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_tcp_offload_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_retx_tcp_offload_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_lost_ip_offload_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_eth_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_vld_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_offload_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_eth_octects_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_data_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_offload_octects_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_vld_mcast_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_vld_bcast_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_accepted_ucast_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_accepted_nucast_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_tagged_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_long_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_usized_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_osized_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_frag_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_jabber_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_64_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_65_127_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_128_255_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_256_511_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_512_1023_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_1024_1518_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_1519_4095_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_4096_8191_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_8192_max_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_gt_max_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ip%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_accepted_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ip_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_err_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_icmp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_tcp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_udp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_err_tcp_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_lost_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_lost_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_lost_ip_offload_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_various_discard_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_sleep_discard_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_red_discard_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_queue_full_discard_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_mpa_ok_frms_%d\t\t\t", + &stat_size, data, i); + } + + vxge_add_string("\nAGGR STATISTICS%s\t\t\t\t", + &stat_size, data, ""); + for (i = 0; i < vdev->max_config_port; i++) { + vxge_add_string("tx_frms_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_data_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_mcast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_bcast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_discarded_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_errored_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_frms_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_data_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_mcast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_bcast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_discarded_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_errored_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_unknown_slow_proto_frms_%d\t", + &stat_size, data, i); + } + + vxge_add_string("\nPORT STATISTICS%s\t\t\t\t", + &stat_size, data, ""); + for (i = 0; i < vdev->max_config_port; i++) { + vxge_add_string("tx_ttl_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_ttl_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_data_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_mcast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_bcast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_ucast_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_tagged_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_vld_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_vld_ip_octects_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_icmp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_tcp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_rst_tcp_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_udp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_parse_error_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_unknown_protocol_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_pause_ctrl_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_marker_pdu_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_lacpdu_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_drop_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_marker_resp_pdu_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_xgmii_char2_match_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_xgmii_char1_match_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_xgmii_column2_match_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_xgmii_column1_match_%d\t\t", + &stat_size, data, i); + vxge_add_string("tx_any_err_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_drop_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_vld_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_offload_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_data_octects_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_offload_octects_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_vld_mcast_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_vld_bcast_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_accepted_ucast_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_accepted_nucast_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_tagged_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_long_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_usized_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_osized_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_frag_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_jabber_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_64_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_65_127_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_128_255_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_256_511_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_512_1023_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_1024_1518_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_1519_4095_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_4096_8191_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_8192_max_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ttl_gt_max_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_ip_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_accepted_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_ip_octets_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_err_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_icmp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_tcp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_udp_%d\t\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_err_tcp_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_pause_count_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_pause_ctrl_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_unsup_ctrl_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_fcs_err_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_in_rng_len_err_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_out_rng_len_err_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_drop_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_discard_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_drop_ip_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_drop_udp_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_marker_pdu_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_lacpdu_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_unknown_pdu_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_marker_resp_pdu_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_fcs_discard_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_illegal_pdu_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_switch_discard_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_len_discard_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_rpa_discard_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_l2_mgmt_discard_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_rts_discard_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_trash_discard_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_buff_full_discard_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_red_discard_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_xgmii_ctrl_err_cnt_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_xgmii_data_err_cnt_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_xgmii_char1_match_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_xgmii_err_sym_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_xgmii_column1_match_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_xgmii_char2_match_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_local_fault_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_xgmii_column2_match_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_jettison_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_remote_fault_%d\t\t\t", + &stat_size, data, i); + } + + vxge_add_string("\n SOFTWARE STATISTICS%s\t\t\t", + &stat_size, data, ""); + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_add_string("soft_reset_cnt_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("unknown_alarms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("network_sustained_fault_%d\t\t", + &stat_size, data, i); + vxge_add_string("network_sustained_ok_%d\t\t", + &stat_size, data, i); + vxge_add_string("kdfcctl_fifo0_overwrite_%d\t\t", + &stat_size, data, i); + vxge_add_string("kdfcctl_fifo0_poison_%d\t\t", + &stat_size, data, i); + vxge_add_string("kdfcctl_fifo0_dma_error_%d\t\t", + &stat_size, data, i); + vxge_add_string("dblgen_fifo0_overflow_%d\t\t", + &stat_size, data, i); + vxge_add_string("statsb_pif_chain_error_%d\t\t", + &stat_size, data, i); + vxge_add_string("statsb_drop_timeout_%d\t\t", + &stat_size, data, i); + vxge_add_string("target_illegal_access_%d\t\t", + &stat_size, data, i); + vxge_add_string("ini_serr_det_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("prc_ring_bumps_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("prc_rxdcm_sc_err_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("prc_rxdcm_sc_abort_%d\t\t", + &stat_size, data, i); + vxge_add_string("prc_quanta_size_err_%d\t\t", + &stat_size, data, i); + vxge_add_string("ring_full_cnt_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("ring_usage_cnt_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("ring_usage_max_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("ring_reserve_free_swaps_cnt_%d\t", + &stat_size, data, i); + vxge_add_string("ring_total_compl_cnt_%d\t\t", + &stat_size, data, i); + for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++) + vxge_add_string("rxd_t_code_err_cnt%d_%d\t\t", + &stat_size, data, j, i); + vxge_add_string("fifo_full_cnt_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("fifo_usage_cnt_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("fifo_usage_max_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("fifo_reserve_free_swaps_cnt_%d\t", + &stat_size, data, i); + vxge_add_string("fifo_total_compl_cnt_%d\t\t", + &stat_size, data, i); + vxge_add_string("fifo_total_posts_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("fifo_total_buffers_%d\t\t", + &stat_size, data, i); + for (j = 0; j < VXGE_HW_DTR_MAX_T_CODE; j++) + vxge_add_string("txd_t_code_err_cnt%d_%d\t\t", + &stat_size, data, j, i); + } + + vxge_add_string("\n HARDWARE STATISTICS%s\t\t\t", + &stat_size, data, ""); + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_add_string("ini_num_mwr_sent_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("ini_num_mrd_sent_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("ini_num_cpl_rcvd_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("ini_num_mwr_byte_sent_%d\t\t", + &stat_size, data, i); + vxge_add_string("ini_num_cpl_byte_rcvd_%d\t\t", + &stat_size, data, i); + vxge_add_string("wrcrdtarb_xoff_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rdcrdtarb_xoff_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("vpath_genstats_count0_%d\t\t", + &stat_size, data, i); + vxge_add_string("vpath_genstats_count1_%d\t\t", + &stat_size, data, i); + vxge_add_string("vpath_genstats_count2_%d\t\t", + &stat_size, data, i); + vxge_add_string("vpath_genstats_count3_%d\t\t", + &stat_size, data, i); + vxge_add_string("vpath_genstats_count4_%d\t\t", + &stat_size, data, i); + vxge_add_string("vpath_genstats_count5_%d\t\t", + &stat_size, data, i); + vxge_add_string("prog_event_vnum0_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("prog_event_vnum1_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("prog_event_vnum2_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("prog_event_vnum3_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_multi_cast_frame_discard_%d\t", + &stat_size, data, i); + vxge_add_string("rx_frm_transferred_%d\t\t", + &stat_size, data, i); + vxge_add_string("rxd_returned_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("rx_mpa_len_fail_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_mpa_mrk_fail_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_mpa_crc_fail_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_permitted_frms_%d\t\t", + &stat_size, data, i); + vxge_add_string("rx_vp_reset_discarded_frms_%d\t", + &stat_size, data, i); + vxge_add_string("rx_wol_frms_%d\t\t\t", + &stat_size, data, i); + vxge_add_string("tx_vp_reset_discarded_frms_%d\t", + &stat_size, data, i); + } + + memcpy(data + stat_size, ðtool_driver_stats_keys, + sizeof(ethtool_driver_stats_keys)); + } +} + +static int vxge_ethtool_get_regs_len(struct net_device *dev) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + + return sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath; +} + +static u32 vxge_get_rx_csum(struct net_device *dev) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + + return vdev->rx_csum; +} + +static int vxge_set_rx_csum(struct net_device *dev, u32 data) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + + if (data) + vdev->rx_csum = 1; + else + vdev->rx_csum = 0; + + return 0; +} + +static int vxge_ethtool_op_set_tso(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= (NETIF_F_TSO | NETIF_F_TSO6); + else + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return 0; +} + +static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset) +{ + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + + switch (sset) { + case ETH_SS_STATS: + return VXGE_TITLE_LEN + + (vdev->no_of_vpath * VXGE_HW_VPATH_STATS_LEN) + + (vdev->max_config_port * VXGE_HW_AGGR_STATS_LEN) + + (vdev->max_config_port * VXGE_HW_PORT_STATS_LEN) + + (vdev->no_of_vpath * VXGE_HW_VPATH_TX_STATS_LEN) + + (vdev->no_of_vpath * VXGE_HW_VPATH_RX_STATS_LEN) + + (vdev->no_of_vpath * VXGE_SW_STATS_LEN) + + DRIVER_STAT_LEN; + default: + return -EOPNOTSUPP; + } +} + +static const struct ethtool_ops vxge_ethtool_ops = { + .get_settings = vxge_ethtool_gset, + .set_settings = vxge_ethtool_sset, + .get_drvinfo = vxge_ethtool_gdrvinfo, + .get_regs_len = vxge_ethtool_get_regs_len, + .get_regs = vxge_ethtool_gregs, + .get_link = ethtool_op_get_link, + .get_pauseparam = vxge_ethtool_getpause_data, + .set_pauseparam = vxge_ethtool_setpause_data, + .get_rx_csum = vxge_get_rx_csum, + .set_rx_csum = vxge_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_hw_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = vxge_ethtool_op_set_tso, + .get_strings = vxge_ethtool_get_strings, + .phys_id = vxge_ethtool_idnic, + .get_sset_count = vxge_ethtool_get_sset_count, + .get_ethtool_stats = vxge_get_ethtool_stats, +}; + +void initialize_ethtool_ops(struct net_device *ndev) +{ + SET_ETHTOOL_OPS(ndev, &vxge_ethtool_ops); +} diff --git a/trunk/drivers/net/vxge/vxge-ethtool.h b/trunk/drivers/net/vxge/vxge-ethtool.h new file mode 100644 index 000000000000..1c3df0a34acc --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-ethtool.h @@ -0,0 +1,67 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-ethtool.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#ifndef _VXGE_ETHTOOL_H +#define _VXGE_ETHTOOL_H + +#include "vxge-main.h" + +/* Ethtool related variables and Macros. */ +static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset); + +static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { + {"\n DRIVER STATISTICS"}, + {"vpaths_opened"}, + {"vpath_open_fail_cnt"}, + {"link_up_cnt"}, + {"link_down_cnt"}, + {"tx_frms"}, + {"tx_errors"}, + {"tx_bytes"}, + {"txd_not_free"}, + {"txd_out_of_desc"}, + {"rx_frms"}, + {"rx_errors"}, + {"rx_bytes"}, + {"rx_mcast"}, + {"pci_map_fail_cnt"}, + {"skb_alloc_fail_cnt"} +}; + +#define VXGE_TITLE_LEN 5 +#define VXGE_HW_VPATH_STATS_LEN 27 +#define VXGE_HW_AGGR_STATS_LEN 13 +#define VXGE_HW_PORT_STATS_LEN 94 +#define VXGE_HW_VPATH_TX_STATS_LEN 19 +#define VXGE_HW_VPATH_RX_STATS_LEN 42 +#define VXGE_SW_STATS_LEN 60 +#define VXGE_HW_STATS_LEN (VXGE_HW_VPATH_STATS_LEN +\ + VXGE_HW_AGGR_STATS_LEN +\ + VXGE_HW_PORT_STATS_LEN +\ + VXGE_HW_VPATH_TX_STATS_LEN +\ + VXGE_HW_VPATH_RX_STATS_LEN) + +#define DRIVER_STAT_LEN (sizeof(ethtool_driver_stats_keys)/ETH_GSTRING_LEN) +#define STAT_LEN (VXGE_HW_STATS_LEN + DRIVER_STAT_LEN + VXGE_SW_STATS_LEN) + +/* Maximum flicker time of adapter LED */ +#define VXGE_MAX_FLICKER_TIME (60 * HZ) /* 60 seconds */ +#define VXGE_FLICKER_ON 1 +#define VXGE_FLICKER_OFF 0 + +#define vxge_add_string(fmt, size, buf, ...) {\ + snprintf(buf + *size, ETH_GSTRING_LEN, fmt, __VA_ARGS__); \ + *size += ETH_GSTRING_LEN; \ +} + +#endif /*_VXGE_ETHTOOL_H*/ diff --git a/trunk/drivers/net/vxge/vxge-main.c b/trunk/drivers/net/vxge/vxge-main.c new file mode 100644 index 000000000000..61ef16118157 --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-main.c @@ -0,0 +1,4502 @@ +/****************************************************************************** +* This software may be used and distributed according to the terms of +* the GNU General Public License (GPL), incorporated herein by reference. +* Drivers based on or derived from this code fall under the GPL and must +* retain the authorship, copyright and license notice. This file is not +* a complete program and may only be used when the entire operating +* system is licensed under the GPL. +* See the file COPYING in this distribution for more information. +* +* vxge-main.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O +* Virtualized Server Adapter. +* Copyright(c) 2002-2009 Neterion Inc. +* +* The module loadable parameters that are supported by the driver and a brief +* explanation of all the variables: +* vlan_tag_strip: +* Strip VLAN Tag enable/disable. Instructs the device to remove +* the VLAN tag from all received tagged frames that are not +* replicated at the internal L2 switch. +* 0 - Do not strip the VLAN tag. +* 1 - Strip the VLAN tag. +* +* addr_learn_en: +* Enable learning the mac address of the guest OS interface in +* a virtualization environment. +* 0 - DISABLE +* 1 - ENABLE +* +* max_config_port: +* Maximum number of port to be supported. +* MIN -1 and MAX - 2 +* +* max_config_vpath: +* This configures the maximum no of VPATH configures for each +* device function. +* MIN - 1 and MAX - 17 +* +* max_config_dev: +* This configures maximum no of Device function to be enabled. +* MIN - 1 and MAX - 17 +* +******************************************************************************/ + +#include +#include +#include +#include +#include +#include "vxge-main.h" +#include "vxge-reg.h" + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Neterion's X3100 Series 10GbE PCIe I/O" + "Virtualized Server Adapter"); + +static struct pci_device_id vxge_id_table[] __devinitdata = { + {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_WIN, PCI_ANY_ID, + PCI_ANY_ID}, + {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_TITAN_UNI, PCI_ANY_ID, + PCI_ANY_ID}, + {0} +}; + +MODULE_DEVICE_TABLE(pci, vxge_id_table); + +VXGE_MODULE_PARAM_INT(vlan_tag_strip, VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE); +VXGE_MODULE_PARAM_INT(addr_learn_en, VXGE_HW_MAC_ADDR_LEARN_DEFAULT); +VXGE_MODULE_PARAM_INT(max_config_port, VXGE_MAX_CONFIG_PORT); +VXGE_MODULE_PARAM_INT(max_config_vpath, VXGE_USE_DEFAULT); +VXGE_MODULE_PARAM_INT(max_mac_vpath, VXGE_MAX_MAC_ADDR_COUNT); +VXGE_MODULE_PARAM_INT(max_config_dev, VXGE_MAX_CONFIG_DEV); + +static u16 vpath_selector[VXGE_HW_MAX_VIRTUAL_PATHS] = + {0, 1, 3, 3, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, 31}; +static unsigned int bw_percentage[VXGE_HW_MAX_VIRTUAL_PATHS] = + {[0 ...(VXGE_HW_MAX_VIRTUAL_PATHS - 1)] = 0xFF}; +module_param_array(bw_percentage, uint, NULL, 0); + +static struct vxge_drv_config *driver_config; + +static inline int is_vxge_card_up(struct vxgedev *vdev) +{ + return test_bit(__VXGE_STATE_CARD_UP, &vdev->state); +} + +static inline void VXGE_COMPLETE_VPATH_TX(struct vxge_fifo *fifo) +{ + unsigned long flags = 0; + struct sk_buff *skb_ptr = NULL; + struct sk_buff **temp, *head, *skb; + + if (spin_trylock_irqsave(&fifo->tx_lock, flags)) { + vxge_hw_vpath_poll_tx(fifo->handle, (void **)&skb_ptr); + spin_unlock_irqrestore(&fifo->tx_lock, flags); + } + /* free SKBs */ + head = skb_ptr; + while (head) { + skb = head; + temp = (struct sk_buff **)&skb->cb; + head = *temp; + *temp = NULL; + dev_kfree_skb_irq(skb); + } +} + +static inline void VXGE_COMPLETE_ALL_TX(struct vxgedev *vdev) +{ + int i; + + /* Complete all transmits */ + for (i = 0; i < vdev->no_of_vpath; i++) + VXGE_COMPLETE_VPATH_TX(&vdev->vpaths[i].fifo); +} + +static inline void VXGE_COMPLETE_ALL_RX(struct vxgedev *vdev) +{ + int i; + struct vxge_ring *ring; + + /* Complete all receives*/ + for (i = 0; i < vdev->no_of_vpath; i++) { + ring = &vdev->vpaths[i].ring; + vxge_hw_vpath_poll_rx(ring->handle); + } +} + +/* + * MultiQ manipulation helper functions + */ +void vxge_stop_all_tx_queue(struct vxgedev *vdev) +{ + int i; + struct net_device *dev = vdev->ndev; + + if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) { + for (i = 0; i < vdev->no_of_vpath; i++) + vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_STOP; + } + netif_tx_stop_all_queues(dev); +} + +void vxge_stop_tx_queue(struct vxge_fifo *fifo) +{ + struct net_device *dev = fifo->ndev; + + struct netdev_queue *txq = NULL; + if (fifo->tx_steering_type == TX_MULTIQ_STEERING) + txq = netdev_get_tx_queue(dev, fifo->driver_id); + else { + txq = netdev_get_tx_queue(dev, 0); + fifo->queue_state = VPATH_QUEUE_STOP; + } + + netif_tx_stop_queue(txq); +} + +void vxge_start_all_tx_queue(struct vxgedev *vdev) +{ + int i; + struct net_device *dev = vdev->ndev; + + if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) { + for (i = 0; i < vdev->no_of_vpath; i++) + vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_START; + } + netif_tx_start_all_queues(dev); +} + +static void vxge_wake_all_tx_queue(struct vxgedev *vdev) +{ + int i; + struct net_device *dev = vdev->ndev; + + if (vdev->config.tx_steering_type != TX_MULTIQ_STEERING) { + for (i = 0; i < vdev->no_of_vpath; i++) + vdev->vpaths[i].fifo.queue_state = VPATH_QUEUE_START; + } + netif_tx_wake_all_queues(dev); +} + +void vxge_wake_tx_queue(struct vxge_fifo *fifo, struct sk_buff *skb) +{ + struct net_device *dev = fifo->ndev; + + int vpath_no = fifo->driver_id; + struct netdev_queue *txq = NULL; + if (fifo->tx_steering_type == TX_MULTIQ_STEERING) { + txq = netdev_get_tx_queue(dev, vpath_no); + if (netif_tx_queue_stopped(txq)) + netif_tx_wake_queue(txq); + } else { + txq = netdev_get_tx_queue(dev, 0); + if (fifo->queue_state == VPATH_QUEUE_STOP) + if (netif_tx_queue_stopped(txq)) { + fifo->queue_state = VPATH_QUEUE_START; + netif_tx_wake_queue(txq); + } + } +} + +/* + * vxge_callback_link_up + * + * This function is called during interrupt context to notify link up state + * change. + */ +void +vxge_callback_link_up(struct __vxge_hw_device *hldev) +{ + struct net_device *dev = hldev->ndev; + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + vdev->ndev->name, __func__, __LINE__); + printk(KERN_NOTICE "%s: Link Up\n", vdev->ndev->name); + vdev->stats.link_up++; + + netif_carrier_on(vdev->ndev); + vxge_wake_all_tx_queue(vdev); + + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__); +} + +/* + * vxge_callback_link_down + * + * This function is called during interrupt context to notify link down state + * change. + */ +void +vxge_callback_link_down(struct __vxge_hw_device *hldev) +{ + struct net_device *dev = hldev->ndev; + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d", vdev->ndev->name, __func__, __LINE__); + printk(KERN_NOTICE "%s: Link Down\n", vdev->ndev->name); + + vdev->stats.link_down++; + netif_carrier_off(vdev->ndev); + vxge_stop_all_tx_queue(vdev); + + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", vdev->ndev->name, __func__, __LINE__); +} + +/* + * vxge_rx_alloc + * + * Allocate SKB. + */ +static struct sk_buff* +vxge_rx_alloc(void *dtrh, struct vxge_ring *ring, const int skb_size) +{ + struct net_device *dev; + struct sk_buff *skb; + struct vxge_rx_priv *rx_priv; + + dev = ring->ndev; + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + ring->ndev->name, __func__, __LINE__); + + rx_priv = vxge_hw_ring_rxd_private_get(dtrh); + + /* try to allocate skb first. this one may fail */ + skb = netdev_alloc_skb(dev, skb_size + + VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); + if (skb == NULL) { + vxge_debug_mem(VXGE_ERR, + "%s: out of memory to allocate SKB", dev->name); + ring->stats.skb_alloc_fail++; + return NULL; + } + + vxge_debug_mem(VXGE_TRACE, + "%s: %s:%d Skb : 0x%p", ring->ndev->name, + __func__, __LINE__, skb); + + skb_reserve(skb, VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); + + rx_priv->skb = skb; + rx_priv->data_size = skb_size; + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); + + return skb; +} + +/* + * vxge_rx_map + */ +static int vxge_rx_map(void *dtrh, struct vxge_ring *ring) +{ + struct vxge_rx_priv *rx_priv; + dma_addr_t dma_addr; + + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + ring->ndev->name, __func__, __LINE__); + rx_priv = vxge_hw_ring_rxd_private_get(dtrh); + + dma_addr = pci_map_single(ring->pdev, rx_priv->skb->data, + rx_priv->data_size, PCI_DMA_FROMDEVICE); + + if (dma_addr == 0) { + ring->stats.pci_map_fail++; + return -EIO; + } + vxge_debug_mem(VXGE_TRACE, + "%s: %s:%d 1 buffer mode dma_addr = 0x%llx", + ring->ndev->name, __func__, __LINE__, + (unsigned long long)dma_addr); + vxge_hw_ring_rxd_1b_set(dtrh, dma_addr, rx_priv->data_size); + + rx_priv->data_dma = dma_addr; + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); + + return 0; +} + +/* + * vxge_rx_initial_replenish + * Allocation of RxD as an initial replenish procedure. + */ +static enum vxge_hw_status +vxge_rx_initial_replenish(void *dtrh, void *userdata) +{ + struct vxge_ring *ring = (struct vxge_ring *)userdata; + struct vxge_rx_priv *rx_priv; + + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + ring->ndev->name, __func__, __LINE__); + if (vxge_rx_alloc(dtrh, ring, + VXGE_LL_MAX_FRAME_SIZE(ring->ndev)) == NULL) + return VXGE_HW_FAIL; + + if (vxge_rx_map(dtrh, ring)) { + rx_priv = vxge_hw_ring_rxd_private_get(dtrh); + dev_kfree_skb(rx_priv->skb); + + return VXGE_HW_FAIL; + } + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); + + return VXGE_HW_OK; +} + +static inline void +vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan, + int pkt_length, struct vxge_hw_ring_rxd_info *ext_info) +{ + + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + ring->ndev->name, __func__, __LINE__); + skb_record_rx_queue(skb, ring->driver_id); + skb->protocol = eth_type_trans(skb, ring->ndev); + + ring->stats.rx_frms++; + ring->stats.rx_bytes += pkt_length; + + if (skb->pkt_type == PACKET_MULTICAST) + ring->stats.rx_mcast++; + + vxge_debug_rx(VXGE_TRACE, + "%s: %s:%d skb protocol = %d", + ring->ndev->name, __func__, __LINE__, skb->protocol); + + if (ring->gro_enable) { + if (ring->vlgrp && ext_info->vlan && + (ring->vlan_tag_strip == + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) + vlan_gro_receive(&ring->napi, ring->vlgrp, + ext_info->vlan, skb); + else + napi_gro_receive(&ring->napi, skb); + } else { + if (ring->vlgrp && vlan && + (ring->vlan_tag_strip == + VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE)) + vlan_hwaccel_receive_skb(skb, ring->vlgrp, vlan); + else + netif_receive_skb(skb); + } + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__); +} + +static inline void vxge_re_pre_post(void *dtr, struct vxge_ring *ring, + struct vxge_rx_priv *rx_priv) +{ + pci_dma_sync_single_for_device(ring->pdev, + rx_priv->data_dma, rx_priv->data_size, PCI_DMA_FROMDEVICE); + + vxge_hw_ring_rxd_1b_set(dtr, rx_priv->data_dma, rx_priv->data_size); + vxge_hw_ring_rxd_pre_post(ring->handle, dtr); +} + +static inline void vxge_post(int *dtr_cnt, void **first_dtr, + void *post_dtr, struct __vxge_hw_ring *ringh) +{ + int dtr_count = *dtr_cnt; + if ((*dtr_cnt % VXGE_HW_RXSYNC_FREQ_CNT) == 0) { + if (*first_dtr) + vxge_hw_ring_rxd_post_post_wmb(ringh, *first_dtr); + *first_dtr = post_dtr; + } else + vxge_hw_ring_rxd_post_post(ringh, post_dtr); + dtr_count++; + *dtr_cnt = dtr_count; +} + +/* + * vxge_rx_1b_compl + * + * If the interrupt is because of a received frame or if the receive ring + * contains fresh as yet un-processed frames, this function is called. + */ +enum vxge_hw_status +vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, + u8 t_code, void *userdata) +{ + struct vxge_ring *ring = (struct vxge_ring *)userdata; + struct net_device *dev = ring->ndev; + unsigned int dma_sizes; + void *first_dtr = NULL; + int dtr_cnt = 0; + int data_size; + dma_addr_t data_dma; + int pkt_length; + struct sk_buff *skb; + struct vxge_rx_priv *rx_priv; + struct vxge_hw_ring_rxd_info ext_info; + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + ring->ndev->name, __func__, __LINE__); + ring->pkts_processed = 0; + + vxge_hw_ring_replenish(ringh, 0); + + do { + rx_priv = vxge_hw_ring_rxd_private_get(dtr); + skb = rx_priv->skb; + data_size = rx_priv->data_size; + data_dma = rx_priv->data_dma; + + vxge_debug_rx(VXGE_TRACE, + "%s: %s:%d skb = 0x%p", + ring->ndev->name, __func__, __LINE__, skb); + + vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes); + pkt_length = dma_sizes; + + vxge_debug_rx(VXGE_TRACE, + "%s: %s:%d Packet Length = %d", + ring->ndev->name, __func__, __LINE__, pkt_length); + + vxge_hw_ring_rxd_1b_info_get(ringh, dtr, &ext_info); + + /* check skb validity */ + vxge_assert(skb); + + prefetch((char *)skb + L1_CACHE_BYTES); + if (unlikely(t_code)) { + + if (vxge_hw_ring_handle_tcode(ringh, dtr, t_code) != + VXGE_HW_OK) { + + ring->stats.rx_errors++; + vxge_debug_rx(VXGE_TRACE, + "%s: %s :%d Rx T_code is %d", + ring->ndev->name, __func__, + __LINE__, t_code); + + /* If the t_code is not supported and if the + * t_code is other than 0x5 (unparseable packet + * such as unknown UPV6 header), Drop it !!! + */ + vxge_re_pre_post(dtr, ring, rx_priv); + + vxge_post(&dtr_cnt, &first_dtr, dtr, ringh); + ring->stats.rx_dropped++; + continue; + } + } + + if (pkt_length > VXGE_LL_RX_COPY_THRESHOLD) { + + if (vxge_rx_alloc(dtr, ring, data_size) != NULL) { + + if (!vxge_rx_map(dtr, ring)) { + skb_put(skb, pkt_length); + + pci_unmap_single(ring->pdev, data_dma, + data_size, PCI_DMA_FROMDEVICE); + + vxge_hw_ring_rxd_pre_post(ringh, dtr); + vxge_post(&dtr_cnt, &first_dtr, dtr, + ringh); + } else { + dev_kfree_skb(rx_priv->skb); + rx_priv->skb = skb; + rx_priv->data_size = data_size; + vxge_re_pre_post(dtr, ring, rx_priv); + + vxge_post(&dtr_cnt, &first_dtr, dtr, + ringh); + ring->stats.rx_dropped++; + break; + } + } else { + vxge_re_pre_post(dtr, ring, rx_priv); + + vxge_post(&dtr_cnt, &first_dtr, dtr, ringh); + ring->stats.rx_dropped++; + break; + } + } else { + struct sk_buff *skb_up; + + skb_up = netdev_alloc_skb(dev, pkt_length + + VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); + if (skb_up != NULL) { + skb_reserve(skb_up, + VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN); + + pci_dma_sync_single_for_cpu(ring->pdev, + data_dma, data_size, + PCI_DMA_FROMDEVICE); + + vxge_debug_mem(VXGE_TRACE, + "%s: %s:%d skb_up = %p", + ring->ndev->name, __func__, + __LINE__, skb); + memcpy(skb_up->data, skb->data, pkt_length); + + vxge_re_pre_post(dtr, ring, rx_priv); + + vxge_post(&dtr_cnt, &first_dtr, dtr, + ringh); + /* will netif_rx small SKB instead */ + skb = skb_up; + skb_put(skb, pkt_length); + } else { + vxge_re_pre_post(dtr, ring, rx_priv); + + vxge_post(&dtr_cnt, &first_dtr, dtr, ringh); + vxge_debug_rx(VXGE_ERR, + "%s: vxge_rx_1b_compl: out of " + "memory", dev->name); + ring->stats.skb_alloc_fail++; + break; + } + } + + if ((ext_info.proto & VXGE_HW_FRAME_PROTO_TCP_OR_UDP) && + !(ext_info.proto & VXGE_HW_FRAME_PROTO_IP_FRAG) && + ring->rx_csum && /* Offload Rx side CSUM */ + ext_info.l3_cksum == VXGE_HW_L3_CKSUM_OK && + ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + + vxge_rx_complete(ring, skb, ext_info.vlan, + pkt_length, &ext_info); + + ring->budget--; + ring->pkts_processed++; + if (!ring->budget) + break; + + } while (vxge_hw_ring_rxd_next_completed(ringh, &dtr, + &t_code) == VXGE_HW_OK); + + if (first_dtr) + vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr); + + dev->last_rx = jiffies; + + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Exiting...", + __func__, __LINE__); + return VXGE_HW_OK; +} + +/* + * vxge_xmit_compl + * + * If an interrupt was raised to indicate DMA complete of the Tx packet, + * this function is called. It identifies the last TxD whose buffer was + * freed and frees all skbs whose data have already DMA'ed into the NICs + * internal memory. + */ +enum vxge_hw_status +vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, + enum vxge_hw_fifo_tcode t_code, void *userdata, + void **skb_ptr) +{ + struct vxge_fifo *fifo = (struct vxge_fifo *)userdata; + struct sk_buff *skb, *head = NULL; + struct sk_buff **temp; + int pkt_cnt = 0; + + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Entered....", __func__, __LINE__); + + do { + int frg_cnt; + skb_frag_t *frag; + int i = 0, j; + struct vxge_tx_priv *txd_priv = + vxge_hw_fifo_txdl_private_get(dtr); + + skb = txd_priv->skb; + frg_cnt = skb_shinfo(skb)->nr_frags; + frag = &skb_shinfo(skb)->frags[0]; + + vxge_debug_tx(VXGE_TRACE, + "%s: %s:%d fifo_hw = %p dtr = %p " + "tcode = 0x%x", fifo->ndev->name, __func__, + __LINE__, fifo_hw, dtr, t_code); + /* check skb validity */ + vxge_assert(skb); + vxge_debug_tx(VXGE_TRACE, + "%s: %s:%d skb = %p itxd_priv = %p frg_cnt = %d", + fifo->ndev->name, __func__, __LINE__, + skb, txd_priv, frg_cnt); + if (unlikely(t_code)) { + fifo->stats.tx_errors++; + vxge_debug_tx(VXGE_ERR, + "%s: tx: dtr %p completed due to " + "error t_code %01x", fifo->ndev->name, + dtr, t_code); + vxge_hw_fifo_handle_tcode(fifo_hw, dtr, t_code); + } + + /* for unfragmented skb */ + pci_unmap_single(fifo->pdev, txd_priv->dma_buffers[i++], + skb_headlen(skb), PCI_DMA_TODEVICE); + + for (j = 0; j < frg_cnt; j++) { + pci_unmap_page(fifo->pdev, + txd_priv->dma_buffers[i++], + frag->size, PCI_DMA_TODEVICE); + frag += 1; + } + + vxge_hw_fifo_txdl_free(fifo_hw, dtr); + + /* Updating the statistics block */ + fifo->stats.tx_frms++; + fifo->stats.tx_bytes += skb->len; + + temp = (struct sk_buff **)&skb->cb; + *temp = head; + head = skb; + + pkt_cnt++; + if (pkt_cnt > fifo->indicate_max_pkts) + break; + + } while (vxge_hw_fifo_txdl_next_completed(fifo_hw, + &dtr, &t_code) == VXGE_HW_OK); + + vxge_wake_tx_queue(fifo, skb); + + if (skb_ptr) + *skb_ptr = (void *) head; + + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", + fifo->ndev->name, __func__, __LINE__); + return VXGE_HW_OK; +} + +/* select a vpath to trasmit the packet */ +static u32 vxge_get_vpath_no(struct vxgedev *vdev, struct sk_buff *skb, + int *do_lock) +{ + u16 queue_len, counter = 0; + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *ip; + struct tcphdr *th; + + ip = ip_hdr(skb); + + if ((ip->frag_off & htons(IP_OFFSET|IP_MF)) == 0) { + th = (struct tcphdr *)(((unsigned char *)ip) + + ip->ihl*4); + + queue_len = vdev->no_of_vpath; + counter = (ntohs(th->source) + + ntohs(th->dest)) & + vdev->vpath_selector[queue_len - 1]; + if (counter >= queue_len) + counter = queue_len - 1; + + if (ip->protocol == IPPROTO_UDP) { +#ifdef NETIF_F_LLTX + *do_lock = 0; +#endif + } + } + } + return counter; +} + +static enum vxge_hw_status vxge_search_mac_addr_in_list( + struct vxge_vpath *vpath, u64 del_mac) +{ + struct list_head *entry, *next; + list_for_each_safe(entry, next, &vpath->mac_addr_list) { + if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac) + return TRUE; + } + return FALSE; +} + +static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header) +{ + struct macInfo mac_info; + u8 *mac_address = NULL; + u64 mac_addr = 0, vpath_vector = 0; + int vpath_idx = 0; + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_vpath *vpath = NULL; + struct __vxge_hw_device *hldev; + + hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + + mac_address = (u8 *)&mac_addr; + memcpy(mac_address, mac_header, ETH_ALEN); + + /* Is this mac address already in the list? */ + for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { + vpath = &vdev->vpaths[vpath_idx]; + if (vxge_search_mac_addr_in_list(vpath, mac_addr)) + return vpath_idx; + } + + memset(&mac_info, 0, sizeof(struct macInfo)); + memcpy(mac_info.macaddr, mac_header, ETH_ALEN); + + /* Any vpath has room to add mac address to its da table? */ + for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { + vpath = &vdev->vpaths[vpath_idx]; + if (vpath->mac_addr_cnt < vpath->max_mac_addr_cnt) { + /* Add this mac address to this vpath */ + mac_info.vpath_no = vpath_idx; + mac_info.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE; + status = vxge_add_mac_addr(vdev, &mac_info); + if (status != VXGE_HW_OK) + return -EPERM; + return vpath_idx; + } + } + + mac_info.state = VXGE_LL_MAC_ADDR_IN_LIST; + vpath_idx = 0; + mac_info.vpath_no = vpath_idx; + /* Is the first vpath already selected as catch-basin ? */ + vpath = &vdev->vpaths[vpath_idx]; + if (vpath->mac_addr_cnt > vpath->max_mac_addr_cnt) { + /* Add this mac address to this vpath */ + if (FALSE == vxge_mac_list_add(vpath, &mac_info)) + return -EPERM; + return vpath_idx; + } + + /* Select first vpath as catch-basin */ + vpath_vector = vxge_mBIT(vpath->device_id); + status = vxge_hw_mgmt_reg_write(vpath->vdev->devh, + vxge_hw_mgmt_reg_type_mrpcim, + 0, + (ulong)offsetof( + struct vxge_hw_mrpcim_reg, + rts_mgr_cbasin_cfg), + vpath_vector); + if (status != VXGE_HW_OK) { + vxge_debug_tx(VXGE_ERR, + "%s: Unable to set the vpath-%d in catch-basin mode", + VXGE_DRIVER_NAME, vpath->device_id); + return -EPERM; + } + + if (FALSE == vxge_mac_list_add(vpath, &mac_info)) + return -EPERM; + + return vpath_idx; +} + +/** + * vxge_xmit + * @skb : the socket buffer containing the Tx data. + * @dev : device pointer. + * + * This function is the Tx entry point of the driver. Neterion NIC supports + * certain protocol assist features on Tx side, namely CSO, S/G, LSO. + * NOTE: when device cant queue the pkt, just the trans_start variable will + * not be upadted. +*/ +static int +vxge_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct vxge_fifo *fifo = NULL; + void *dtr_priv; + void *dtr = NULL; + struct vxgedev *vdev = NULL; + enum vxge_hw_status status; + int frg_cnt, first_frg_len; + skb_frag_t *frag; + int i = 0, j = 0, avail; + u64 dma_pointer; + struct vxge_tx_priv *txdl_priv = NULL; + struct __vxge_hw_fifo *fifo_hw; + u32 max_mss = 0x0; + int offload_type; + unsigned long flags = 0; + int vpath_no = 0; + int do_spin_tx_lock = 1; + + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + dev->name, __func__, __LINE__); + + /* A buffer with no data will be dropped */ + if (unlikely(skb->len <= 0)) { + vxge_debug_tx(VXGE_ERR, + "%s: Buffer has no data..", dev->name); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + vdev = (struct vxgedev *)netdev_priv(dev); + + if (unlikely(!is_vxge_card_up(vdev))) { + vxge_debug_tx(VXGE_ERR, + "%s: vdev not initialized", dev->name); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + + if (vdev->config.addr_learn_en) { + vpath_no = vxge_learn_mac(vdev, skb->data + ETH_ALEN); + if (vpath_no == -EPERM) { + vxge_debug_tx(VXGE_ERR, + "%s: Failed to store the mac address", + dev->name); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } + } + + if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING) + vpath_no = skb_get_queue_mapping(skb); + else if (vdev->config.tx_steering_type == TX_PORT_STEERING) + vpath_no = vxge_get_vpath_no(vdev, skb, &do_spin_tx_lock); + + vxge_debug_tx(VXGE_TRACE, "%s: vpath_no= %d", dev->name, vpath_no); + + if (vpath_no >= vdev->no_of_vpath) + vpath_no = 0; + + fifo = &vdev->vpaths[vpath_no].fifo; + fifo_hw = fifo->handle; + + if (do_spin_tx_lock) + spin_lock_irqsave(&fifo->tx_lock, flags); + else { + if (unlikely(!spin_trylock_irqsave(&fifo->tx_lock, flags))) + return NETDEV_TX_LOCKED; + } + + if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING) { + if (netif_subqueue_stopped(dev, skb)) { + spin_unlock_irqrestore(&fifo->tx_lock, flags); + return NETDEV_TX_BUSY; + } + } else if (unlikely(fifo->queue_state == VPATH_QUEUE_STOP)) { + if (netif_queue_stopped(dev)) { + spin_unlock_irqrestore(&fifo->tx_lock, flags); + return NETDEV_TX_BUSY; + } + } + avail = vxge_hw_fifo_free_txdl_count_get(fifo_hw); + if (avail == 0) { + vxge_debug_tx(VXGE_ERR, + "%s: No free TXDs available", dev->name); + fifo->stats.txd_not_free++; + vxge_stop_tx_queue(fifo); + goto _exit2; + } + + status = vxge_hw_fifo_txdl_reserve(fifo_hw, &dtr, &dtr_priv); + if (unlikely(status != VXGE_HW_OK)) { + vxge_debug_tx(VXGE_ERR, + "%s: Out of descriptors .", dev->name); + fifo->stats.txd_out_of_desc++; + vxge_stop_tx_queue(fifo); + goto _exit2; + } + + vxge_debug_tx(VXGE_TRACE, + "%s: %s:%d fifo_hw = %p dtr = %p dtr_priv = %p", + dev->name, __func__, __LINE__, + fifo_hw, dtr, dtr_priv); + + if (vdev->vlgrp && vlan_tx_tag_present(skb)) { + u16 vlan_tag = vlan_tx_tag_get(skb); + vxge_hw_fifo_txdl_vlan_set(dtr, vlan_tag); + } + + first_frg_len = skb_headlen(skb); + + dma_pointer = pci_map_single(fifo->pdev, skb->data, first_frg_len, + PCI_DMA_TODEVICE); + + if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer))) { + vxge_hw_fifo_txdl_free(fifo_hw, dtr); + vxge_stop_tx_queue(fifo); + fifo->stats.pci_map_fail++; + goto _exit2; + } + + txdl_priv = vxge_hw_fifo_txdl_private_get(dtr); + txdl_priv->skb = skb; + txdl_priv->dma_buffers[j] = dma_pointer; + + frg_cnt = skb_shinfo(skb)->nr_frags; + vxge_debug_tx(VXGE_TRACE, + "%s: %s:%d skb = %p txdl_priv = %p " + "frag_cnt = %d dma_pointer = 0x%llx", dev->name, + __func__, __LINE__, skb, txdl_priv, + frg_cnt, (unsigned long long)dma_pointer); + + vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer, + first_frg_len); + + frag = &skb_shinfo(skb)->frags[0]; + for (i = 0; i < frg_cnt; i++) { + /* ignore 0 length fragment */ + if (!frag->size) + continue; + + dma_pointer = + (u64)pci_map_page(fifo->pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + + if (unlikely(pci_dma_mapping_error(fifo->pdev, dma_pointer))) + goto _exit0; + vxge_debug_tx(VXGE_TRACE, + "%s: %s:%d frag = %d dma_pointer = 0x%llx", + dev->name, __func__, __LINE__, i, + (unsigned long long)dma_pointer); + + txdl_priv->dma_buffers[j] = dma_pointer; + vxge_hw_fifo_txdl_buffer_set(fifo_hw, dtr, j++, dma_pointer, + frag->size); + frag += 1; + } + + offload_type = vxge_offload_type(skb); + + if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { + + int mss = vxge_tcp_mss(skb); + if (mss) { + max_mss = dev->mtu + ETH_HLEN - + VXGE_HW_TCPIP_HEADER_MAX_SIZE; + if (mss > max_mss) + mss = max_mss; + vxge_debug_tx(VXGE_TRACE, + "%s: %s:%d mss = %d", + dev->name, __func__, __LINE__, mss); + vxge_hw_fifo_txdl_mss_set(dtr, mss); + } else { + vxge_assert(skb->len <= + dev->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE); + vxge_assert(0); + goto _exit1; + } + } + + if (skb->ip_summed == CHECKSUM_PARTIAL) + vxge_hw_fifo_txdl_cksum_set_bits(dtr, + VXGE_HW_FIFO_TXD_TX_CKO_IPV4_EN | + VXGE_HW_FIFO_TXD_TX_CKO_TCP_EN | + VXGE_HW_FIFO_TXD_TX_CKO_UDP_EN); + + vxge_hw_fifo_txdl_post(fifo_hw, dtr); + dev->trans_start = jiffies; + spin_unlock_irqrestore(&fifo->tx_lock, flags); + + VXGE_COMPLETE_VPATH_TX(fifo); + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", + dev->name, __func__, __LINE__); + return 0; + +_exit0: + vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name); + +_exit1: + j = 0; + frag = &skb_shinfo(skb)->frags[0]; + + pci_unmap_single(fifo->pdev, txdl_priv->dma_buffers[j++], + skb_headlen(skb), PCI_DMA_TODEVICE); + + for (; j < i; j++) { + pci_unmap_page(fifo->pdev, txdl_priv->dma_buffers[j], + frag->size, PCI_DMA_TODEVICE); + frag += 1; + } + + vxge_hw_fifo_txdl_free(fifo_hw, dtr); +_exit2: + dev_kfree_skb(skb); + spin_unlock_irqrestore(&fifo->tx_lock, flags); + VXGE_COMPLETE_VPATH_TX(fifo); + + return 0; +} + +/* + * vxge_rx_term + * + * Function will be called by hw function to abort all outstanding receive + * descriptors. + */ +static void +vxge_rx_term(void *dtrh, enum vxge_hw_rxd_state state, void *userdata) +{ + struct vxge_ring *ring = (struct vxge_ring *)userdata; + struct vxge_rx_priv *rx_priv = + vxge_hw_ring_rxd_private_get(dtrh); + + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + ring->ndev->name, __func__, __LINE__); + if (state != VXGE_HW_RXD_STATE_POSTED) + return; + + pci_unmap_single(ring->pdev, rx_priv->data_dma, + rx_priv->data_size, PCI_DMA_FROMDEVICE); + + dev_kfree_skb(rx_priv->skb); + + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", + ring->ndev->name, __func__, __LINE__); +} + +/* + * vxge_tx_term + * + * Function will be called to abort all outstanding tx descriptors + */ +static void +vxge_tx_term(void *dtrh, enum vxge_hw_txdl_state state, void *userdata) +{ + struct vxge_fifo *fifo = (struct vxge_fifo *)userdata; + skb_frag_t *frag; + int i = 0, j, frg_cnt; + struct vxge_tx_priv *txd_priv = vxge_hw_fifo_txdl_private_get(dtrh); + struct sk_buff *skb = txd_priv->skb; + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); + + if (state != VXGE_HW_TXDL_STATE_POSTED) + return; + + /* check skb validity */ + vxge_assert(skb); + frg_cnt = skb_shinfo(skb)->nr_frags; + frag = &skb_shinfo(skb)->frags[0]; + + /* for unfragmented skb */ + pci_unmap_single(fifo->pdev, txd_priv->dma_buffers[i++], + skb_headlen(skb), PCI_DMA_TODEVICE); + + for (j = 0; j < frg_cnt; j++) { + pci_unmap_page(fifo->pdev, txd_priv->dma_buffers[i++], + frag->size, PCI_DMA_TODEVICE); + frag += 1; + } + + dev_kfree_skb(skb); + + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Exiting...", __func__, __LINE__); +} + +/** + * vxge_set_multicast + * @dev: pointer to the device structure + * + * Entry point for multicast address enable/disable + * This function is a driver entry point which gets called by the kernel + * whenever multicast addresses must be enabled/disabled. This also gets + * called to set/reset promiscuous mode. Depending on the deivce flag, we + * determine, if multicast address must be enabled or if promiscuous mode + * is to be disabled etc. + */ +static void vxge_set_multicast(struct net_device *dev) +{ + struct dev_mc_list *mclist; + struct vxgedev *vdev; + int i, mcast_cnt = 0; + struct __vxge_hw_device *hldev; + enum vxge_hw_status status = VXGE_HW_OK; + struct macInfo mac_info; + int vpath_idx = 0; + struct vxge_mac_addrs *mac_entry; + struct list_head *list_head; + struct list_head *entry, *next; + u8 *mac_address = NULL; + + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d", __func__, __LINE__); + + vdev = (struct vxgedev *)netdev_priv(dev); + hldev = (struct __vxge_hw_device *)vdev->devh; + + if (unlikely(!is_vxge_card_up(vdev))) + return; + + if ((dev->flags & IFF_ALLMULTI) && (!vdev->all_multi_flg)) { + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_assert(vdev->vpaths[i].is_open); + status = vxge_hw_vpath_mcast_enable( + vdev->vpaths[i].handle); + vdev->all_multi_flg = 1; + } + } else if ((dev->flags & IFF_ALLMULTI) && (vdev->all_multi_flg)) { + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_assert(vdev->vpaths[i].is_open); + status = vxge_hw_vpath_mcast_disable( + vdev->vpaths[i].handle); + vdev->all_multi_flg = 1; + } + } + + if (status != VXGE_HW_OK) + vxge_debug_init(VXGE_ERR, + "failed to %s multicast, status %d", + dev->flags & IFF_ALLMULTI ? + "enable" : "disable", status); + + if (!vdev->config.addr_learn_en) { + if (dev->flags & IFF_PROMISC) { + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_assert(vdev->vpaths[i].is_open); + status = vxge_hw_vpath_promisc_enable( + vdev->vpaths[i].handle); + } + } else { + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_assert(vdev->vpaths[i].is_open); + status = vxge_hw_vpath_promisc_disable( + vdev->vpaths[i].handle); + } + } + } + + memset(&mac_info, 0, sizeof(struct macInfo)); + /* Update individual M_CAST address list */ + if ((!vdev->all_multi_flg) && dev->mc_count) { + + mcast_cnt = vdev->vpaths[0].mcast_addr_cnt; + list_head = &vdev->vpaths[0].mac_addr_list; + if ((dev->mc_count + + (vdev->vpaths[0].mac_addr_cnt - mcast_cnt)) > + vdev->vpaths[0].max_mac_addr_cnt) + goto _set_all_mcast; + + /* Delete previous MC's */ + for (i = 0; i < mcast_cnt; i++) { + if (!list_empty(list_head)) + mac_entry = (struct vxge_mac_addrs *) + list_first_entry(list_head, + struct vxge_mac_addrs, + item); + + list_for_each_safe(entry, next, list_head) { + + mac_entry = (struct vxge_mac_addrs *) entry; + /* Copy the mac address to delete */ + mac_address = (u8 *)&mac_entry->macaddr; + memcpy(mac_info.macaddr, mac_address, ETH_ALEN); + + /* Is this a multicast address */ + if (0x01 & mac_info.macaddr[0]) { + for (vpath_idx = 0; vpath_idx < + vdev->no_of_vpath; + vpath_idx++) { + mac_info.vpath_no = vpath_idx; + status = vxge_del_mac_addr( + vdev, + &mac_info); + } + } + } + } + + /* Add new ones */ + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + + memcpy(mac_info.macaddr, mclist->dmi_addr, ETH_ALEN); + for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; + vpath_idx++) { + mac_info.vpath_no = vpath_idx; + mac_info.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE; + status = vxge_add_mac_addr(vdev, &mac_info); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s:%d Setting individual" + "multicast address failed", + __func__, __LINE__); + goto _set_all_mcast; + } + } + } + + return; +_set_all_mcast: + mcast_cnt = vdev->vpaths[0].mcast_addr_cnt; + /* Delete previous MC's */ + for (i = 0; i < mcast_cnt; i++) { + + list_for_each_safe(entry, next, list_head) { + + mac_entry = (struct vxge_mac_addrs *) entry; + /* Copy the mac address to delete */ + mac_address = (u8 *)&mac_entry->macaddr; + memcpy(mac_info.macaddr, mac_address, ETH_ALEN); + + /* Is this a multicast address */ + if (0x01 & mac_info.macaddr[0]) + break; + } + + for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; + vpath_idx++) { + mac_info.vpath_no = vpath_idx; + status = vxge_del_mac_addr(vdev, &mac_info); + } + } + + /* Enable all multicast */ + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_assert(vdev->vpaths[i].is_open); + status = vxge_hw_vpath_mcast_enable( + vdev->vpaths[i].handle); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s:%d Enabling all multicasts failed", + __func__, __LINE__); + } + vdev->all_multi_flg = 1; + } + dev->flags |= IFF_ALLMULTI; + } + + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Exiting...", __func__, __LINE__); +} + +/** + * vxge_set_mac_addr + * @dev: pointer to the device structure + * + * Update entry "0" (default MAC addr) + */ +static int vxge_set_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + struct vxgedev *vdev; + struct __vxge_hw_device *hldev; + enum vxge_hw_status status = VXGE_HW_OK; + struct macInfo mac_info_new, mac_info_old; + int vpath_idx = 0; + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); + + vdev = (struct vxgedev *)netdev_priv(dev); + hldev = vdev->devh; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + memset(&mac_info_new, 0, sizeof(struct macInfo)); + memset(&mac_info_old, 0, sizeof(struct macInfo)); + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d Exiting...", + __func__, __LINE__); + + /* Get the old address */ + memcpy(mac_info_old.macaddr, dev->dev_addr, dev->addr_len); + + /* Copy the new address */ + memcpy(mac_info_new.macaddr, addr->sa_data, dev->addr_len); + + /* First delete the old mac address from all the vpaths + as we can't specify the index while adding new mac address */ + for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { + struct vxge_vpath *vpath = &vdev->vpaths[vpath_idx]; + if (!vpath->is_open) { + /* This can happen when this interface is added/removed + to the bonding interface. Delete this station address + from the linked list */ + vxge_mac_list_del(vpath, &mac_info_old); + + /* Add this new address to the linked list + for later restoring */ + vxge_mac_list_add(vpath, &mac_info_new); + + continue; + } + /* Delete the station address */ + mac_info_old.vpath_no = vpath_idx; + status = vxge_del_mac_addr(vdev, &mac_info_old); + } + + if (unlikely(!is_vxge_card_up(vdev))) { + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + return VXGE_HW_OK; + } + + /* Set this mac address to all the vpaths */ + for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) { + mac_info_new.vpath_no = vpath_idx; + mac_info_new.state = VXGE_LL_MAC_ADDR_IN_DA_TABLE; + status = vxge_add_mac_addr(vdev, &mac_info_new); + if (status != VXGE_HW_OK) + return -EINVAL; + } + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + return status; +} + +/* + * vxge_vpath_intr_enable + * @vdev: pointer to vdev + * @vp_id: vpath for which to enable the interrupts + * + * Enables the interrupts for the vpath +*/ +void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id) +{ + struct vxge_vpath *vpath = &vdev->vpaths[vp_id]; + int msix_id, alarm_msix_id; + int tim_msix_id[4] = {[0 ...3] = 0}; + + vxge_hw_vpath_intr_enable(vpath->handle); + + if (vdev->config.intr_type == INTA) + vxge_hw_vpath_inta_unmask_tx_rx(vpath->handle); + else { + msix_id = vp_id * VXGE_HW_VPATH_MSIX_ACTIVE; + alarm_msix_id = + VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2; + + tim_msix_id[0] = msix_id; + tim_msix_id[1] = msix_id + 1; + vxge_hw_vpath_msix_set(vpath->handle, tim_msix_id, + alarm_msix_id); + + vxge_hw_vpath_msix_unmask(vpath->handle, msix_id); + vxge_hw_vpath_msix_unmask(vpath->handle, msix_id + 1); + + /* enable the alarm vector */ + vxge_hw_vpath_msix_unmask(vpath->handle, alarm_msix_id); + } +} + +/* + * vxge_vpath_intr_disable + * @vdev: pointer to vdev + * @vp_id: vpath for which to disable the interrupts + * + * Disables the interrupts for the vpath +*/ +void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id) +{ + struct vxge_vpath *vpath = &vdev->vpaths[vp_id]; + int msix_id; + + vxge_hw_vpath_intr_disable(vpath->handle); + + if (vdev->config.intr_type == INTA) + vxge_hw_vpath_inta_mask_tx_rx(vpath->handle); + else { + msix_id = vp_id * VXGE_HW_VPATH_MSIX_ACTIVE; + vxge_hw_vpath_msix_mask(vpath->handle, msix_id); + vxge_hw_vpath_msix_mask(vpath->handle, msix_id + 1); + + /* disable the alarm vector */ + msix_id = VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2; + vxge_hw_vpath_msix_mask(vpath->handle, msix_id); + } +} + +/* + * vxge_reset_vpath + * @vdev: pointer to vdev + * @vp_id: vpath to reset + * + * Resets the vpath +*/ +static int vxge_reset_vpath(struct vxgedev *vdev, int vp_id) +{ + enum vxge_hw_status status = VXGE_HW_OK; + int ret = 0; + + /* check if device is down already */ + if (unlikely(!is_vxge_card_up(vdev))) + return 0; + + /* is device reset already scheduled */ + if (test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) + return 0; + + if (vdev->vpaths[vp_id].handle) { + if (vxge_hw_vpath_reset(vdev->vpaths[vp_id].handle) + == VXGE_HW_OK) { + if (is_vxge_card_up(vdev) && + vxge_hw_vpath_recover_from_reset( + vdev->vpaths[vp_id].handle) + != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "vxge_hw_vpath_recover_from_reset" + "failed for vpath:%d", vp_id); + return status; + } + } else { + vxge_debug_init(VXGE_ERR, + "vxge_hw_vpath_reset failed for" + "vpath:%d", vp_id); + return status; + } + } else + return VXGE_HW_FAIL; + + vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]); + vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]); + + /* Enable all broadcast */ + vxge_hw_vpath_bcast_enable(vdev->vpaths[vp_id].handle); + + /* Enable the interrupts */ + vxge_vpath_intr_enable(vdev, vp_id); + + smp_wmb(); + + /* Enable the flow of traffic through the vpath */ + vxge_hw_vpath_enable(vdev->vpaths[vp_id].handle); + + smp_wmb(); + vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[vp_id].handle); + vdev->vpaths[vp_id].ring.last_status = VXGE_HW_OK; + + /* Vpath reset done */ + clear_bit(vp_id, &vdev->vp_reset); + + /* Start the vpath queue */ + vxge_wake_tx_queue(&vdev->vpaths[vp_id].fifo, NULL); + + return ret; +} + +static int do_vxge_reset(struct vxgedev *vdev, int event) +{ + enum vxge_hw_status status; + int ret = 0, vp_id, i; + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); + + if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET)) { + /* check if device is down already */ + if (unlikely(!is_vxge_card_up(vdev))) + return 0; + + /* is reset already scheduled */ + if (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) + return 0; + } + + if (event == VXGE_LL_FULL_RESET) { + /* wait for all the vpath reset to complete */ + for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { + while (test_bit(vp_id, &vdev->vp_reset)) + msleep(50); + } + + /* if execution mode is set to debug, don't reset the adapter */ + if (unlikely(vdev->exec_mode)) { + vxge_debug_init(VXGE_ERR, + "%s: execution mode is debug, returning..", + vdev->ndev->name); + clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); + vxge_stop_all_tx_queue(vdev); + return 0; + } + } + + if (event == VXGE_LL_FULL_RESET) { + vxge_hw_device_intr_disable(vdev->devh); + + switch (vdev->cric_err_event) { + case VXGE_HW_EVENT_UNKNOWN: + vxge_stop_all_tx_queue(vdev); + vxge_debug_init(VXGE_ERR, + "fatal: %s: Disabling device due to" + "unknown error", + vdev->ndev->name); + ret = -EPERM; + goto out; + case VXGE_HW_EVENT_RESET_START: + break; + case VXGE_HW_EVENT_RESET_COMPLETE: + case VXGE_HW_EVENT_LINK_DOWN: + case VXGE_HW_EVENT_LINK_UP: + case VXGE_HW_EVENT_ALARM_CLEARED: + case VXGE_HW_EVENT_ECCERR: + case VXGE_HW_EVENT_MRPCIM_ECCERR: + ret = -EPERM; + goto out; + case VXGE_HW_EVENT_FIFO_ERR: + case VXGE_HW_EVENT_VPATH_ERR: + break; + case VXGE_HW_EVENT_CRITICAL_ERR: + vxge_stop_all_tx_queue(vdev); + vxge_debug_init(VXGE_ERR, + "fatal: %s: Disabling device due to" + "serious error", + vdev->ndev->name); + /* SOP or device reset required */ + /* This event is not currently used */ + ret = -EPERM; + goto out; + case VXGE_HW_EVENT_SERR: + vxge_stop_all_tx_queue(vdev); + vxge_debug_init(VXGE_ERR, + "fatal: %s: Disabling device due to" + "serious error", + vdev->ndev->name); + ret = -EPERM; + goto out; + case VXGE_HW_EVENT_SRPCIM_SERR: + case VXGE_HW_EVENT_MRPCIM_SERR: + ret = -EPERM; + goto out; + case VXGE_HW_EVENT_SLOT_FREEZE: + vxge_stop_all_tx_queue(vdev); + vxge_debug_init(VXGE_ERR, + "fatal: %s: Disabling device due to" + "slot freeze", + vdev->ndev->name); + ret = -EPERM; + goto out; + default: + break; + + } + } + + if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_START_RESET)) + vxge_stop_all_tx_queue(vdev); + + if (event == VXGE_LL_FULL_RESET) { + status = vxge_reset_all_vpaths(vdev); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "fatal: %s: can not reset vpaths", + vdev->ndev->name); + ret = -EPERM; + goto out; + } + } + + if (event == VXGE_LL_COMPL_RESET) { + for (i = 0; i < vdev->no_of_vpath; i++) + if (vdev->vpaths[i].handle) { + if (vxge_hw_vpath_recover_from_reset( + vdev->vpaths[i].handle) + != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "vxge_hw_vpath_recover_" + "from_reset failed for vpath: " + "%d", i); + ret = -EPERM; + goto out; + } + } else { + vxge_debug_init(VXGE_ERR, + "vxge_hw_vpath_reset failed for " + "vpath:%d", i); + ret = -EPERM; + goto out; + } + } + + if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_COMPL_RESET)) { + /* Reprogram the DA table with populated mac addresses */ + for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { + vxge_restore_vpath_mac_addr(&vdev->vpaths[vp_id]); + vxge_restore_vpath_vid_table(&vdev->vpaths[vp_id]); + } + + /* enable vpath interrupts */ + for (i = 0; i < vdev->no_of_vpath; i++) + vxge_vpath_intr_enable(vdev, i); + + vxge_hw_device_intr_enable(vdev->devh); + + smp_wmb(); + + /* Indicate card up */ + set_bit(__VXGE_STATE_CARD_UP, &vdev->state); + + /* Get the traffic to flow through the vpaths */ + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_hw_vpath_enable(vdev->vpaths[i].handle); + smp_wmb(); + vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle); + } + + vxge_wake_all_tx_queue(vdev); + } + +out: + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Exiting...", __func__, __LINE__); + + /* Indicate reset done */ + if ((event == VXGE_LL_FULL_RESET) || (event == VXGE_LL_COMPL_RESET)) + clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state); + return ret; +} + +/* + * vxge_reset + * @vdev: pointer to ll device + * + * driver may reset the chip on events of serr, eccerr, etc + */ +int vxge_reset(struct vxgedev *vdev) +{ + do_vxge_reset(vdev, VXGE_LL_FULL_RESET); + return 0; +} + +/** + * vxge_poll - Receive handler when Receive Polling is used. + * @dev: pointer to the device structure. + * @budget: Number of packets budgeted to be processed in this iteration. + * + * This function comes into picture only if Receive side is being handled + * through polling (called NAPI in linux). It mostly does what the normal + * Rx interrupt handler does in terms of descriptor and packet processing + * but not in an interrupt context. Also it will process a specified number + * of packets at most in one iteration. This value is passed down by the + * kernel as the function argument 'budget'. + */ +static int vxge_poll_msix(struct napi_struct *napi, int budget) +{ + struct vxge_ring *ring = + container_of(napi, struct vxge_ring, napi); + int budget_org = budget; + ring->budget = budget; + + vxge_hw_vpath_poll_rx(ring->handle); + + if (ring->pkts_processed < budget_org) { + napi_complete(napi); + /* Re enable the Rx interrupts for the vpath */ + vxge_hw_channel_msix_unmask( + (struct __vxge_hw_channel *)ring->handle, + ring->rx_vector_no); + } + + return ring->pkts_processed; +} + +static int vxge_poll_inta(struct napi_struct *napi, int budget) +{ + struct vxgedev *vdev = container_of(napi, struct vxgedev, napi); + int pkts_processed = 0; + int i; + int budget_org = budget; + struct vxge_ring *ring; + + struct __vxge_hw_device *hldev = (struct __vxge_hw_device *) + pci_get_drvdata(vdev->pdev); + + for (i = 0; i < vdev->no_of_vpath; i++) { + ring = &vdev->vpaths[i].ring; + ring->budget = budget; + vxge_hw_vpath_poll_rx(ring->handle); + pkts_processed += ring->pkts_processed; + budget -= ring->pkts_processed; + if (budget <= 0) + break; + } + + VXGE_COMPLETE_ALL_TX(vdev); + + if (pkts_processed < budget_org) { + napi_complete(napi); + /* Re enable the Rx interrupts for the ring */ + vxge_hw_device_unmask_all(hldev); + vxge_hw_device_flush_io(hldev); + } + + return pkts_processed; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/** + * vxge_netpoll - netpoll event handler entry point + * @dev : pointer to the device structure. + * Description: + * This function will be called by upper layer to check for events on the + * interface in situations where interrupts are disabled. It is used for + * specific in-kernel networking tasks, such as remote consoles and kernel + * debugging over the network (example netdump in RedHat). + */ +static void vxge_netpoll(struct net_device *dev) +{ + struct __vxge_hw_device *hldev; + struct vxgedev *vdev; + + vdev = (struct vxgedev *)netdev_priv(dev); + hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); + + if (pci_channel_offline(vdev->pdev)) + return; + + disable_irq(dev->irq); + vxge_hw_device_clear_tx_rx(hldev); + + vxge_hw_device_clear_tx_rx(hldev); + VXGE_COMPLETE_ALL_RX(vdev); + VXGE_COMPLETE_ALL_TX(vdev); + + enable_irq(dev->irq); + + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Exiting...", __func__, __LINE__); + return; +} +#endif + +/* RTH configuration */ +static enum vxge_hw_status vxge_rth_configure(struct vxgedev *vdev) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_hw_rth_hash_types hash_types; + u8 itable[256] = {0}; /* indirection table */ + u8 mtable[256] = {0}; /* CPU to vpath mapping */ + int index; + + /* + * Filling + * - itable with bucket numbers + * - mtable with bucket-to-vpath mapping + */ + for (index = 0; index < (1 << vdev->config.rth_bkt_sz); index++) { + itable[index] = index; + mtable[index] = index % vdev->no_of_vpath; + } + + /* Fill RTH hash types */ + hash_types.hash_type_tcpipv4_en = vdev->config.rth_hash_type_tcpipv4; + hash_types.hash_type_ipv4_en = vdev->config.rth_hash_type_ipv4; + hash_types.hash_type_tcpipv6_en = vdev->config.rth_hash_type_tcpipv6; + hash_types.hash_type_ipv6_en = vdev->config.rth_hash_type_ipv6; + hash_types.hash_type_tcpipv6ex_en = + vdev->config.rth_hash_type_tcpipv6ex; + hash_types.hash_type_ipv6ex_en = vdev->config.rth_hash_type_ipv6ex; + + /* set indirection table, bucket-to-vpath mapping */ + status = vxge_hw_vpath_rts_rth_itable_set(vdev->vp_handles, + vdev->no_of_vpath, + mtable, itable, + vdev->config.rth_bkt_sz); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "RTH indirection table configuration failed " + "for vpath:%d", vdev->vpaths[0].device_id); + return status; + } + + /* + * Because the itable_set() method uses the active_table field + * for the target virtual path the RTH config should be updated + * for all VPATHs. The h/w only uses the lowest numbered VPATH + * when steering frames. + */ + for (index = 0; index < vdev->no_of_vpath; index++) { + status = vxge_hw_vpath_rts_rth_set( + vdev->vpaths[index].handle, + vdev->config.rth_algorithm, + &hash_types, + vdev->config.rth_bkt_sz); + + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "RTH configuration failed for vpath:%d", + vdev->vpaths[index].device_id); + return status; + } + } + + return status; +} + +int vxge_mac_list_add(struct vxge_vpath *vpath, struct macInfo *mac) +{ + struct vxge_mac_addrs *new_mac_entry; + u8 *mac_address = NULL; + + if (vpath->mac_addr_cnt >= VXGE_MAX_LEARN_MAC_ADDR_CNT) + return TRUE; + + new_mac_entry = kzalloc(sizeof(struct vxge_mac_addrs), GFP_ATOMIC); + if (!new_mac_entry) { + vxge_debug_mem(VXGE_ERR, + "%s: memory allocation failed", + VXGE_DRIVER_NAME); + return FALSE; + } + + list_add(&new_mac_entry->item, &vpath->mac_addr_list); + + /* Copy the new mac address to the list */ + mac_address = (u8 *)&new_mac_entry->macaddr; + memcpy(mac_address, mac->macaddr, ETH_ALEN); + + new_mac_entry->state = mac->state; + vpath->mac_addr_cnt++; + + /* Is this a multicast address */ + if (0x01 & mac->macaddr[0]) + vpath->mcast_addr_cnt++; + + return TRUE; +} + +/* Add a mac address to DA table */ +enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev, struct macInfo *mac) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_vpath *vpath; + enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode; + + if (0x01 & mac->macaddr[0]) /* multicast address */ + duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE; + else + duplicate_mode = VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE; + + vpath = &vdev->vpaths[mac->vpath_no]; + status = vxge_hw_vpath_mac_addr_add(vpath->handle, mac->macaddr, + mac->macmask, duplicate_mode); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "DA config add entry failed for vpath:%d", + vpath->device_id); + } else + if (FALSE == vxge_mac_list_add(vpath, mac)) + status = -EPERM; + + return status; +} + +int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac) +{ + struct list_head *entry, *next; + u64 del_mac = 0; + u8 *mac_address = (u8 *) (&del_mac); + + /* Copy the mac address to delete from the list */ + memcpy(mac_address, mac->macaddr, ETH_ALEN); + + list_for_each_safe(entry, next, &vpath->mac_addr_list) { + if (((struct vxge_mac_addrs *)entry)->macaddr == del_mac) { + list_del(entry); + kfree((struct vxge_mac_addrs *)entry); + vpath->mac_addr_cnt--; + + /* Is this a multicast address */ + if (0x01 & mac->macaddr[0]) + vpath->mcast_addr_cnt--; + return TRUE; + } + } + + return FALSE; +} +/* delete a mac address from DA table */ +enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev, struct macInfo *mac) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_vpath *vpath; + + vpath = &vdev->vpaths[mac->vpath_no]; + status = vxge_hw_vpath_mac_addr_delete(vpath->handle, mac->macaddr, + mac->macmask); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "DA config delete entry failed for vpath:%d", + vpath->device_id); + } else + vxge_mac_list_del(vpath, mac); + return status; +} + +/* list all mac addresses from DA table */ +enum vxge_hw_status +static vxge_search_mac_addr_in_da_table(struct vxge_vpath *vpath, + struct macInfo *mac) +{ + enum vxge_hw_status status = VXGE_HW_OK; + unsigned char macmask[ETH_ALEN]; + unsigned char macaddr[ETH_ALEN]; + + status = vxge_hw_vpath_mac_addr_get(vpath->handle, + macaddr, macmask); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "DA config list entry failed for vpath:%d", + vpath->device_id); + return status; + } + + while (memcmp(mac->macaddr, macaddr, ETH_ALEN)) { + + status = vxge_hw_vpath_mac_addr_get_next(vpath->handle, + macaddr, macmask); + if (status != VXGE_HW_OK) + break; + } + + return status; +} + +/* Store all vlan ids from the list to the vid table */ +enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct vxgedev *vdev = vpath->vdev; + u16 vid; + + if (vdev->vlgrp && vpath->is_open) { + + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(vdev->vlgrp, vid)) + continue; + /* Add these vlan to the vid table */ + status = vxge_hw_vpath_vid_add(vpath->handle, vid); + } + } + + return status; +} + +/* Store all mac addresses from the list to the DA table */ +enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath) +{ + enum vxge_hw_status status = VXGE_HW_OK; + struct macInfo mac_info; + u8 *mac_address = NULL; + struct list_head *entry, *next; + + memset(&mac_info, 0, sizeof(struct macInfo)); + + if (vpath->is_open) { + + list_for_each_safe(entry, next, &vpath->mac_addr_list) { + mac_address = + (u8 *)& + ((struct vxge_mac_addrs *)entry)->macaddr; + memcpy(mac_info.macaddr, mac_address, ETH_ALEN); + ((struct vxge_mac_addrs *)entry)->state = + VXGE_LL_MAC_ADDR_IN_DA_TABLE; + /* does this mac address already exist in da table? */ + status = vxge_search_mac_addr_in_da_table(vpath, + &mac_info); + if (status != VXGE_HW_OK) { + /* Add this mac address to the DA table */ + status = vxge_hw_vpath_mac_addr_add( + vpath->handle, mac_info.macaddr, + mac_info.macmask, + VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "DA add entry failed for vpath:%d", + vpath->device_id); + ((struct vxge_mac_addrs *)entry)->state + = VXGE_LL_MAC_ADDR_IN_LIST; + } + } + } + } + + return status; +} + +/* reset vpaths */ +enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev) +{ + int i; + enum vxge_hw_status status = VXGE_HW_OK; + + for (i = 0; i < vdev->no_of_vpath; i++) + if (vdev->vpaths[i].handle) { + if (vxge_hw_vpath_reset(vdev->vpaths[i].handle) + == VXGE_HW_OK) { + if (is_vxge_card_up(vdev) && + vxge_hw_vpath_recover_from_reset( + vdev->vpaths[i].handle) + != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "vxge_hw_vpath_recover_" + "from_reset failed for vpath: " + "%d", i); + return status; + } + } else { + vxge_debug_init(VXGE_ERR, + "vxge_hw_vpath_reset failed for " + "vpath:%d", i); + return status; + } + } + return status; +} + +/* close vpaths */ +void vxge_close_vpaths(struct vxgedev *vdev, int index) +{ + int i; + for (i = index; i < vdev->no_of_vpath; i++) { + if (vdev->vpaths[i].handle && vdev->vpaths[i].is_open) { + vxge_hw_vpath_close(vdev->vpaths[i].handle); + vdev->stats.vpaths_open--; + } + vdev->vpaths[i].is_open = 0; + vdev->vpaths[i].handle = NULL; + } +} + +/* open vpaths */ +int vxge_open_vpaths(struct vxgedev *vdev) +{ + enum vxge_hw_status status; + int i; + u32 vp_id = 0; + struct vxge_hw_vpath_attr attr; + + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_assert(vdev->vpaths[i].is_configured); + attr.vp_id = vdev->vpaths[i].device_id; + attr.fifo_attr.callback = vxge_xmit_compl; + attr.fifo_attr.txdl_term = vxge_tx_term; + attr.fifo_attr.per_txdl_space = sizeof(struct vxge_tx_priv); + attr.fifo_attr.userdata = (void *)&vdev->vpaths[i].fifo; + + attr.ring_attr.callback = vxge_rx_1b_compl; + attr.ring_attr.rxd_init = vxge_rx_initial_replenish; + attr.ring_attr.rxd_term = vxge_rx_term; + attr.ring_attr.per_rxd_space = sizeof(struct vxge_rx_priv); + attr.ring_attr.userdata = (void *)&vdev->vpaths[i].ring; + + vdev->vpaths[i].ring.ndev = vdev->ndev; + vdev->vpaths[i].ring.pdev = vdev->pdev; + status = vxge_hw_vpath_open(vdev->devh, &attr, + &(vdev->vpaths[i].handle)); + if (status == VXGE_HW_OK) { + vdev->vpaths[i].fifo.handle = + (struct __vxge_hw_fifo *)attr.fifo_attr.userdata; + vdev->vpaths[i].ring.handle = + (struct __vxge_hw_ring *)attr.ring_attr.userdata; + vdev->vpaths[i].fifo.tx_steering_type = + vdev->config.tx_steering_type; + vdev->vpaths[i].fifo.ndev = vdev->ndev; + vdev->vpaths[i].fifo.pdev = vdev->pdev; + vdev->vpaths[i].fifo.indicate_max_pkts = + vdev->config.fifo_indicate_max_pkts; + vdev->vpaths[i].ring.rx_vector_no = 0; + vdev->vpaths[i].ring.rx_csum = vdev->rx_csum; + vdev->vpaths[i].is_open = 1; + vdev->vp_handles[i] = vdev->vpaths[i].handle; + vdev->vpaths[i].ring.gro_enable = + vdev->config.gro_enable; + vdev->vpaths[i].ring.vlan_tag_strip = + vdev->vlan_tag_strip; + vdev->stats.vpaths_open++; + } else { + vdev->stats.vpath_open_fail++; + vxge_debug_init(VXGE_ERR, + "%s: vpath: %d failed to open " + "with status: %d", + vdev->ndev->name, vdev->vpaths[i].device_id, + status); + vxge_close_vpaths(vdev, 0); + return -EPERM; + } + + vp_id = + ((struct __vxge_hw_vpath_handle *)vdev->vpaths[i].handle)-> + vpath->vp_id; + vdev->vpaths_deployed |= vxge_mBIT(vp_id); + } + return VXGE_HW_OK; +} + +/* + * vxge_isr_napi + * @irq: the irq of the device. + * @dev_id: a void pointer to the hldev structure of the Titan device + * @ptregs: pointer to the registers pushed on the stack. + * + * This function is the ISR handler of the device when napi is enabled. It + * identifies the reason for the interrupt and calls the relevant service + * routines. + */ +static irqreturn_t vxge_isr_napi(int irq, void *dev_id) +{ + struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)dev_id; + struct vxgedev *vdev; + struct net_device *dev; + u64 reason; + enum vxge_hw_status status; + + vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__); + + dev = hldev->ndev; + vdev = netdev_priv(dev); + + if (pci_channel_offline(vdev->pdev)) + return IRQ_NONE; + + if (unlikely(!is_vxge_card_up(vdev))) + return IRQ_NONE; + + status = vxge_hw_device_begin_irq(hldev, vdev->exec_mode, + &reason); + if (status == VXGE_HW_OK) { + vxge_hw_device_mask_all(hldev); + + if (reason & + VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT( + vdev->vpaths_deployed >> + (64 - VXGE_HW_MAX_VIRTUAL_PATHS))) { + + vxge_hw_device_clear_tx_rx(hldev); + napi_schedule(&vdev->napi); + vxge_debug_intr(VXGE_TRACE, + "%s:%d Exiting...", __func__, __LINE__); + return IRQ_HANDLED; + } else + vxge_hw_device_unmask_all(hldev); + } else if (unlikely((status == VXGE_HW_ERR_VPATH) || + (status == VXGE_HW_ERR_CRITICAL) || + (status == VXGE_HW_ERR_FIFO))) { + vxge_hw_device_mask_all(hldev); + vxge_hw_device_flush_io(hldev); + return IRQ_HANDLED; + } else if (unlikely(status == VXGE_HW_ERR_SLOT_FREEZE)) + return IRQ_HANDLED; + + vxge_debug_intr(VXGE_TRACE, "%s:%d Exiting...", __func__, __LINE__); + return IRQ_NONE; +} + +#ifdef CONFIG_PCI_MSI + +static irqreturn_t +vxge_tx_msix_handle(int irq, void *dev_id) +{ + struct vxge_fifo *fifo = (struct vxge_fifo *)dev_id; + + VXGE_COMPLETE_VPATH_TX(fifo); + + return IRQ_HANDLED; +} + +static irqreturn_t +vxge_rx_msix_napi_handle(int irq, void *dev_id) +{ + struct vxge_ring *ring = (struct vxge_ring *)dev_id; + + /* MSIX_IDX for Rx is 1 */ + vxge_hw_channel_msix_mask((struct __vxge_hw_channel *)ring->handle, + ring->rx_vector_no); + + napi_schedule(&ring->napi); + return IRQ_HANDLED; +} + +static irqreturn_t +vxge_alarm_msix_handle(int irq, void *dev_id) +{ + int i; + enum vxge_hw_status status; + struct vxge_vpath *vpath = (struct vxge_vpath *)dev_id; + struct vxgedev *vdev = vpath->vdev; + int alarm_msix_id = + VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2; + + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_hw_vpath_msix_mask(vdev->vpaths[i].handle, + alarm_msix_id); + + status = vxge_hw_vpath_alarm_process(vdev->vpaths[i].handle, + vdev->exec_mode); + if (status == VXGE_HW_OK) { + + vxge_hw_vpath_msix_unmask(vdev->vpaths[i].handle, + alarm_msix_id); + continue; + } + vxge_debug_intr(VXGE_ERR, + "%s: vxge_hw_vpath_alarm_process failed %x ", + VXGE_DRIVER_NAME, status); + } + return IRQ_HANDLED; +} + +static int vxge_alloc_msix(struct vxgedev *vdev) +{ + int j, i, ret = 0; + int intr_cnt = 0; + int alarm_msix_id = 0, msix_intr_vect = 0; + vdev->intr_cnt = 0; + + /* Tx/Rx MSIX Vectors count */ + vdev->intr_cnt = vdev->no_of_vpath * 2; + + /* Alarm MSIX Vectors count */ + vdev->intr_cnt++; + + intr_cnt = (vdev->max_vpath_supported * 2) + 1; + vdev->entries = kzalloc(intr_cnt * sizeof(struct msix_entry), + GFP_KERNEL); + if (!vdev->entries) { + vxge_debug_init(VXGE_ERR, + "%s: memory allocation failed", + VXGE_DRIVER_NAME); + return -ENOMEM; + } + + vdev->vxge_entries = kzalloc(intr_cnt * sizeof(struct vxge_msix_entry), + GFP_KERNEL); + if (!vdev->vxge_entries) { + vxge_debug_init(VXGE_ERR, "%s: memory allocation failed", + VXGE_DRIVER_NAME); + kfree(vdev->entries); + return -ENOMEM; + } + + /* Last vector in the list is used for alarm */ + alarm_msix_id = VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2; + for (i = 0, j = 0; i < vdev->max_vpath_supported; i++) { + + msix_intr_vect = i * VXGE_HW_VPATH_MSIX_ACTIVE; + + /* Initialize the fifo vector */ + vdev->entries[j].entry = msix_intr_vect; + vdev->vxge_entries[j].entry = msix_intr_vect; + vdev->vxge_entries[j].in_use = 0; + j++; + + /* Initialize the ring vector */ + vdev->entries[j].entry = msix_intr_vect + 1; + vdev->vxge_entries[j].entry = msix_intr_vect + 1; + vdev->vxge_entries[j].in_use = 0; + j++; + } + + /* Initialize the alarm vector */ + vdev->entries[j].entry = alarm_msix_id; + vdev->vxge_entries[j].entry = alarm_msix_id; + vdev->vxge_entries[j].in_use = 0; + + ret = pci_enable_msix(vdev->pdev, vdev->entries, intr_cnt); + /* if driver request exceeeds available irq's, request with a small + * number. + */ + if (ret > 0) { + vxge_debug_init(VXGE_ERR, + "%s: MSI-X enable failed for %d vectors, available: %d", + VXGE_DRIVER_NAME, intr_cnt, ret); + vdev->max_vpath_supported = vdev->no_of_vpath; + intr_cnt = (vdev->max_vpath_supported * 2) + 1; + + /* Reset the alarm vector setting */ + vdev->entries[j].entry = 0; + vdev->vxge_entries[j].entry = 0; + + /* Initialize the alarm vector with new setting */ + vdev->entries[intr_cnt - 1].entry = alarm_msix_id; + vdev->vxge_entries[intr_cnt - 1].entry = alarm_msix_id; + vdev->vxge_entries[intr_cnt - 1].in_use = 0; + + ret = pci_enable_msix(vdev->pdev, vdev->entries, intr_cnt); + if (!ret) + vxge_debug_init(VXGE_ERR, + "%s: MSI-X enabled for %d vectors", + VXGE_DRIVER_NAME, intr_cnt); + } + + if (ret) { + vxge_debug_init(VXGE_ERR, + "%s: MSI-X enable failed for %d vectors, ret: %d", + VXGE_DRIVER_NAME, intr_cnt, ret); + kfree(vdev->entries); + kfree(vdev->vxge_entries); + vdev->entries = NULL; + vdev->vxge_entries = NULL; + return -ENODEV; + } + return 0; +} + +static int vxge_enable_msix(struct vxgedev *vdev) +{ + + int i, ret = 0; + enum vxge_hw_status status; + /* 0 - Tx, 1 - Rx */ + int tim_msix_id[4]; + int alarm_msix_id = 0, msix_intr_vect = 0;; + vdev->intr_cnt = 0; + + /* allocate msix vectors */ + ret = vxge_alloc_msix(vdev); + if (!ret) { + /* Last vector in the list is used for alarm */ + alarm_msix_id = + VXGE_HW_VPATH_MSIX_ACTIVE * vdev->no_of_vpath - 2; + for (i = 0; i < vdev->no_of_vpath; i++) { + + /* If fifo or ring are not enabled + the MSIX vector for that should be set to 0 + Hence initializeing this array to all 0s. + */ + memset(tim_msix_id, 0, sizeof(tim_msix_id)); + msix_intr_vect = i * VXGE_HW_VPATH_MSIX_ACTIVE; + tim_msix_id[0] = msix_intr_vect; + + tim_msix_id[1] = msix_intr_vect + 1; + vdev->vpaths[i].ring.rx_vector_no = tim_msix_id[1]; + + status = vxge_hw_vpath_msix_set( + vdev->vpaths[i].handle, + tim_msix_id, alarm_msix_id); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "vxge_hw_vpath_msix_set " + "failed with status : %x", status); + kfree(vdev->entries); + kfree(vdev->vxge_entries); + pci_disable_msix(vdev->pdev); + return -ENODEV; + } + } + } + + return ret; +} + +static void vxge_rem_msix_isr(struct vxgedev *vdev) +{ + int intr_cnt; + + for (intr_cnt = 0; intr_cnt < (vdev->max_vpath_supported * 2 + 1); + intr_cnt++) { + if (vdev->vxge_entries[intr_cnt].in_use) { + synchronize_irq(vdev->entries[intr_cnt].vector); + free_irq(vdev->entries[intr_cnt].vector, + vdev->vxge_entries[intr_cnt].arg); + vdev->vxge_entries[intr_cnt].in_use = 0; + } + } + + kfree(vdev->entries); + kfree(vdev->vxge_entries); + vdev->entries = NULL; + vdev->vxge_entries = NULL; + + if (vdev->config.intr_type == MSI_X) + pci_disable_msix(vdev->pdev); +} +#endif + +static void vxge_rem_isr(struct vxgedev *vdev) +{ + struct __vxge_hw_device *hldev; + hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + +#ifdef CONFIG_PCI_MSI + if (vdev->config.intr_type == MSI_X) { + vxge_rem_msix_isr(vdev); + } else +#endif + if (vdev->config.intr_type == INTA) { + synchronize_irq(vdev->pdev->irq); + free_irq(vdev->pdev->irq, hldev); + } +} + +static int vxge_add_isr(struct vxgedev *vdev) +{ + int ret = 0; + struct __vxge_hw_device *hldev = + (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); +#ifdef CONFIG_PCI_MSI + int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0; + u64 function_mode = vdev->config.device_hw_info.function_mode; + int pci_fun = PCI_FUNC(vdev->pdev->devfn); + + if (vdev->config.intr_type == MSI_X) + ret = vxge_enable_msix(vdev); + + if (ret) { + vxge_debug_init(VXGE_ERR, + "%s: Enabling MSI-X Failed", VXGE_DRIVER_NAME); + if ((function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) && + test_and_set_bit(__VXGE_STATE_CARD_UP, + &driver_config->inta_dev_open)) + return VXGE_HW_FAIL; + else { + vxge_debug_init(VXGE_ERR, + "%s: Defaulting to INTA", VXGE_DRIVER_NAME); + vdev->config.intr_type = INTA; + vxge_hw_device_set_intr_type(vdev->devh, + VXGE_HW_INTR_MODE_IRQLINE); + vxge_close_vpaths(vdev, 1); + vdev->no_of_vpath = 1; + vdev->stats.vpaths_open = 1; + } + } + + if (vdev->config.intr_type == MSI_X) { + for (intr_idx = 0; + intr_idx < (vdev->no_of_vpath * + VXGE_HW_VPATH_MSIX_ACTIVE); intr_idx++) { + + msix_idx = intr_idx % VXGE_HW_VPATH_MSIX_ACTIVE; + irq_req = 0; + + switch (msix_idx) { + case 0: + snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN, + "%s:vxge fn: %d vpath: %d Tx MSI-X: %d", + vdev->ndev->name, pci_fun, vp_idx, + vdev->entries[intr_cnt].entry); + ret = request_irq( + vdev->entries[intr_cnt].vector, + vxge_tx_msix_handle, 0, + vdev->desc[intr_cnt], + &vdev->vpaths[vp_idx].fifo); + vdev->vxge_entries[intr_cnt].arg = + &vdev->vpaths[vp_idx].fifo; + irq_req = 1; + break; + case 1: + snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN, + "%s:vxge fn: %d vpath: %d Rx MSI-X: %d", + vdev->ndev->name, pci_fun, vp_idx, + vdev->entries[intr_cnt].entry); + ret = request_irq( + vdev->entries[intr_cnt].vector, + vxge_rx_msix_napi_handle, + 0, + vdev->desc[intr_cnt], + &vdev->vpaths[vp_idx].ring); + vdev->vxge_entries[intr_cnt].arg = + &vdev->vpaths[vp_idx].ring; + irq_req = 1; + break; + } + + if (ret) { + vxge_debug_init(VXGE_ERR, + "%s: MSIX - %d Registration failed", + vdev->ndev->name, intr_cnt); + vxge_rem_msix_isr(vdev); + if ((function_mode == + VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) && + test_and_set_bit(__VXGE_STATE_CARD_UP, + &driver_config->inta_dev_open)) + return VXGE_HW_FAIL; + else { + vxge_hw_device_set_intr_type( + vdev->devh, + VXGE_HW_INTR_MODE_IRQLINE); + vdev->config.intr_type = INTA; + vxge_debug_init(VXGE_ERR, + "%s: Defaulting to INTA" + , vdev->ndev->name); + vxge_close_vpaths(vdev, 1); + vdev->no_of_vpath = 1; + vdev->stats.vpaths_open = 1; + goto INTA_MODE; + } + } + + if (irq_req) { + /* We requested for this msix interrupt */ + vdev->vxge_entries[intr_cnt].in_use = 1; + vxge_hw_vpath_msix_unmask( + vdev->vpaths[vp_idx].handle, + intr_idx); + intr_cnt++; + } + + /* Point to next vpath handler */ + if (((intr_idx + 1) % VXGE_HW_VPATH_MSIX_ACTIVE == 0) + && (vp_idx < (vdev->no_of_vpath - 1))) + vp_idx++; + } + + intr_cnt = vdev->max_vpath_supported * 2; + snprintf(vdev->desc[intr_cnt], VXGE_INTR_STRLEN, + "%s:vxge Alarm fn: %d MSI-X: %d", + vdev->ndev->name, pci_fun, + vdev->entries[intr_cnt].entry); + /* For Alarm interrupts */ + ret = request_irq(vdev->entries[intr_cnt].vector, + vxge_alarm_msix_handle, 0, + vdev->desc[intr_cnt], + &vdev->vpaths[vp_idx]); + if (ret) { + vxge_debug_init(VXGE_ERR, + "%s: MSIX - %d Registration failed", + vdev->ndev->name, intr_cnt); + vxge_rem_msix_isr(vdev); + if ((function_mode == + VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) && + test_and_set_bit(__VXGE_STATE_CARD_UP, + &driver_config->inta_dev_open)) + return VXGE_HW_FAIL; + else { + vxge_hw_device_set_intr_type(vdev->devh, + VXGE_HW_INTR_MODE_IRQLINE); + vdev->config.intr_type = INTA; + vxge_debug_init(VXGE_ERR, + "%s: Defaulting to INTA", + vdev->ndev->name); + vxge_close_vpaths(vdev, 1); + vdev->no_of_vpath = 1; + vdev->stats.vpaths_open = 1; + goto INTA_MODE; + } + } + + vxge_hw_vpath_msix_unmask(vdev->vpaths[vp_idx].handle, + intr_idx - 2); + vdev->vxge_entries[intr_cnt].in_use = 1; + vdev->vxge_entries[intr_cnt].arg = &vdev->vpaths[vp_idx]; + } +INTA_MODE: +#endif + snprintf(vdev->desc[0], VXGE_INTR_STRLEN, "%s:vxge", vdev->ndev->name); + + if (vdev->config.intr_type == INTA) { + ret = request_irq((int) vdev->pdev->irq, + vxge_isr_napi, + IRQF_SHARED, vdev->desc[0], hldev); + if (ret) { + vxge_debug_init(VXGE_ERR, + "%s %s-%d: ISR registration failed", + VXGE_DRIVER_NAME, "IRQ", vdev->pdev->irq); + return -ENODEV; + } + vxge_debug_init(VXGE_TRACE, + "new %s-%d line allocated", + "IRQ", vdev->pdev->irq); + } + + return VXGE_HW_OK; +} + +static void vxge_poll_vp_reset(unsigned long data) +{ + struct vxgedev *vdev = (struct vxgedev *)data; + int i, j = 0; + + for (i = 0; i < vdev->no_of_vpath; i++) { + if (test_bit(i, &vdev->vp_reset)) { + vxge_reset_vpath(vdev, i); + j++; + } + } + if (j && (vdev->config.intr_type != MSI_X)) { + vxge_hw_device_unmask_all(vdev->devh); + vxge_hw_device_flush_io(vdev->devh); + } + + mod_timer(&vdev->vp_reset_timer, jiffies + HZ / 2); +} + +static void vxge_poll_vp_lockup(unsigned long data) +{ + struct vxgedev *vdev = (struct vxgedev *)data; + int i; + struct vxge_ring *ring; + enum vxge_hw_status status = VXGE_HW_OK; + + for (i = 0; i < vdev->no_of_vpath; i++) { + ring = &vdev->vpaths[i].ring; + /* Did this vpath received any packets */ + if (ring->stats.prev_rx_frms == ring->stats.rx_frms) { + status = vxge_hw_vpath_check_leak(ring->handle); + + /* Did it received any packets last time */ + if ((VXGE_HW_FAIL == status) && + (VXGE_HW_FAIL == ring->last_status)) { + + /* schedule vpath reset */ + if (!test_and_set_bit(i, &vdev->vp_reset)) { + + /* disable interrupts for this vpath */ + vxge_vpath_intr_disable(vdev, i); + + /* stop the queue for this vpath */ + vxge_stop_tx_queue(&vdev->vpaths[i]. + fifo); + continue; + } + } + } + ring->stats.prev_rx_frms = ring->stats.rx_frms; + ring->last_status = status; + } + + /* Check every 1 milli second */ + mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000); +} + +/** + * vxge_open + * @dev: pointer to the device structure. + * + * This function is the open entry point of the driver. It mainly calls a + * function to allocate Rx buffers and inserts them into the buffer + * descriptors and then enables the Rx part of the NIC. + * Return value: '0' on success and an appropriate (-)ve integer as + * defined in errno.h file on failure. + */ +int +vxge_open(struct net_device *dev) +{ + enum vxge_hw_status status; + struct vxgedev *vdev; + struct __vxge_hw_device *hldev; + int ret = 0; + int i; + u64 val64, function_mode; + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d", dev->name, __func__, __LINE__); + + vdev = (struct vxgedev *)netdev_priv(dev); + hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + function_mode = vdev->config.device_hw_info.function_mode; + + /* make sure you have link off by default every time Nic is + * initialized */ + netif_carrier_off(dev); + + /* Check for another device already opn with INTA */ + if ((function_mode == VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION) && + test_bit(__VXGE_STATE_CARD_UP, &driver_config->inta_dev_open)) { + ret = -EPERM; + goto out0; + } + + /* Open VPATHs */ + status = vxge_open_vpaths(vdev); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s: fatal: Vpath open failed", vdev->ndev->name); + ret = -EPERM; + goto out0; + } + + vdev->mtu = dev->mtu; + + status = vxge_add_isr(vdev); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s: fatal: ISR add failed", dev->name); + ret = -EPERM; + goto out1; + } + + + if (vdev->config.intr_type != MSI_X) { + netif_napi_add(dev, &vdev->napi, vxge_poll_inta, + vdev->config.napi_weight); + napi_enable(&vdev->napi); + } else { + for (i = 0; i < vdev->no_of_vpath; i++) { + netif_napi_add(dev, &vdev->vpaths[i].ring.napi, + vxge_poll_msix, vdev->config.napi_weight); + napi_enable(&vdev->vpaths[i].ring.napi); + } + } + + /* configure RTH */ + if (vdev->config.rth_steering) { + status = vxge_rth_configure(vdev); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s: fatal: RTH configuration failed", + dev->name); + ret = -EPERM; + goto out2; + } + } + + for (i = 0; i < vdev->no_of_vpath; i++) { + /* set initial mtu before enabling the device */ + status = vxge_hw_vpath_mtu_set(vdev->vpaths[i].handle, + vdev->mtu); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s: fatal: can not set new MTU", dev->name); + ret = -EPERM; + goto out2; + } + } + + VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_TRACE, VXGE_COMPONENT_LL, vdev); + vxge_debug_init(vdev->level_trace, + "%s: MTU is %d", vdev->ndev->name, vdev->mtu); + VXGE_DEVICE_DEBUG_LEVEL_SET(VXGE_ERR, VXGE_COMPONENT_LL, vdev); + + /* Reprogram the DA table with populated mac addresses */ + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_restore_vpath_mac_addr(&vdev->vpaths[i]); + vxge_restore_vpath_vid_table(&vdev->vpaths[i]); + } + + /* Enable vpath to sniff all unicast/multicast traffic that not + * addressed to them. We allow promiscous mode for PF only + */ + + val64 = 0; + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) + val64 |= VXGE_HW_RXMAC_AUTHORIZE_ALL_ADDR_VP(i); + + vxge_hw_mgmt_reg_write(vdev->devh, + vxge_hw_mgmt_reg_type_mrpcim, + 0, + (ulong)offsetof(struct vxge_hw_mrpcim_reg, + rxmac_authorize_all_addr), + val64); + + vxge_hw_mgmt_reg_write(vdev->devh, + vxge_hw_mgmt_reg_type_mrpcim, + 0, + (ulong)offsetof(struct vxge_hw_mrpcim_reg, + rxmac_authorize_all_vid), + val64); + + vxge_set_multicast(dev); + + /* Enabling Bcast and mcast for all vpath */ + for (i = 0; i < vdev->no_of_vpath; i++) { + status = vxge_hw_vpath_bcast_enable(vdev->vpaths[i].handle); + if (status != VXGE_HW_OK) + vxge_debug_init(VXGE_ERR, + "%s : Can not enable bcast for vpath " + "id %d", dev->name, i); + if (vdev->config.addr_learn_en) { + status = + vxge_hw_vpath_mcast_enable(vdev->vpaths[i].handle); + if (status != VXGE_HW_OK) + vxge_debug_init(VXGE_ERR, + "%s : Can not enable mcast for vpath " + "id %d", dev->name, i); + } + } + + vxge_hw_device_setpause_data(vdev->devh, 0, + vdev->config.tx_pause_enable, + vdev->config.rx_pause_enable); + + if (vdev->vp_reset_timer.function == NULL) + vxge_os_timer(vdev->vp_reset_timer, + vxge_poll_vp_reset, vdev, (HZ/2)); + + if (vdev->vp_lockup_timer.function == NULL) + vxge_os_timer(vdev->vp_lockup_timer, + vxge_poll_vp_lockup, vdev, (HZ/2)); + + set_bit(__VXGE_STATE_CARD_UP, &vdev->state); + + smp_wmb(); + + if (vxge_hw_device_link_state_get(vdev->devh) == VXGE_HW_LINK_UP) { + netif_carrier_on(vdev->ndev); + printk(KERN_NOTICE "%s: Link Up\n", vdev->ndev->name); + vdev->stats.link_up++; + } + + vxge_hw_device_intr_enable(vdev->devh); + + smp_wmb(); + + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_hw_vpath_enable(vdev->vpaths[i].handle); + smp_wmb(); + vxge_hw_vpath_rx_doorbell_init(vdev->vpaths[i].handle); + } + + vxge_start_all_tx_queue(vdev); + goto out0; + +out2: + vxge_rem_isr(vdev); + + /* Disable napi */ + if (vdev->config.intr_type != MSI_X) + napi_disable(&vdev->napi); + else { + for (i = 0; i < vdev->no_of_vpath; i++) + napi_disable(&vdev->vpaths[i].ring.napi); + } + +out1: + vxge_close_vpaths(vdev, 0); +out0: + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", + dev->name, __func__, __LINE__); + return ret; +} + +/* Loop throught the mac address list and delete all the entries */ +void vxge_free_mac_add_list(struct vxge_vpath *vpath) +{ + + struct list_head *entry, *next; + if (list_empty(&vpath->mac_addr_list)) + return; + + list_for_each_safe(entry, next, &vpath->mac_addr_list) { + list_del(entry); + kfree((struct vxge_mac_addrs *)entry); + } +} + +static void vxge_napi_del_all(struct vxgedev *vdev) +{ + int i; + if (vdev->config.intr_type != MSI_X) + netif_napi_del(&vdev->napi); + else { + for (i = 0; i < vdev->no_of_vpath; i++) + netif_napi_del(&vdev->vpaths[i].ring.napi); + } + return; +} + +int do_vxge_close(struct net_device *dev, int do_io) +{ + enum vxge_hw_status status; + struct vxgedev *vdev; + struct __vxge_hw_device *hldev; + int i; + u64 val64, vpath_vector; + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d", + dev->name, __func__, __LINE__); + + vdev = (struct vxgedev *)netdev_priv(dev); + hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev); + + /* If vxge_handle_crit_err task is executing, + * wait till it completes. */ + while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) + msleep(50); + + clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); + if (do_io) { + /* Put the vpath back in normal mode */ + vpath_vector = vxge_mBIT(vdev->vpaths[0].device_id); + status = vxge_hw_mgmt_reg_read(vdev->devh, + vxge_hw_mgmt_reg_type_mrpcim, + 0, + (ulong)offsetof( + struct vxge_hw_mrpcim_reg, + rts_mgr_cbasin_cfg), + &val64); + + if (status == VXGE_HW_OK) { + val64 &= ~vpath_vector; + status = vxge_hw_mgmt_reg_write(vdev->devh, + vxge_hw_mgmt_reg_type_mrpcim, + 0, + (ulong)offsetof( + struct vxge_hw_mrpcim_reg, + rts_mgr_cbasin_cfg), + val64); + } + + /* Remove the function 0 from promiscous mode */ + vxge_hw_mgmt_reg_write(vdev->devh, + vxge_hw_mgmt_reg_type_mrpcim, + 0, + (ulong)offsetof(struct vxge_hw_mrpcim_reg, + rxmac_authorize_all_addr), + 0); + + vxge_hw_mgmt_reg_write(vdev->devh, + vxge_hw_mgmt_reg_type_mrpcim, + 0, + (ulong)offsetof(struct vxge_hw_mrpcim_reg, + rxmac_authorize_all_vid), + 0); + + smp_wmb(); + } + del_timer_sync(&vdev->vp_lockup_timer); + + del_timer_sync(&vdev->vp_reset_timer); + + /* Disable napi */ + if (vdev->config.intr_type != MSI_X) + napi_disable(&vdev->napi); + else { + for (i = 0; i < vdev->no_of_vpath; i++) + napi_disable(&vdev->vpaths[i].ring.napi); + } + + netif_carrier_off(vdev->ndev); + printk(KERN_NOTICE "%s: Link Down\n", vdev->ndev->name); + vxge_stop_all_tx_queue(vdev); + + /* Note that at this point xmit() is stopped by upper layer */ + if (do_io) + vxge_hw_device_intr_disable(vdev->devh); + + mdelay(1000); + + vxge_rem_isr(vdev); + + vxge_napi_del_all(vdev); + + if (do_io) + vxge_reset_all_vpaths(vdev); + + vxge_close_vpaths(vdev, 0); + + vxge_debug_entryexit(VXGE_TRACE, + "%s: %s:%d Exiting...", dev->name, __func__, __LINE__); + + clear_bit(__VXGE_STATE_CARD_UP, &driver_config->inta_dev_open); + clear_bit(__VXGE_STATE_RESET_CARD, &vdev->state); + + return 0; +} + +/** + * vxge_close + * @dev: device pointer. + * + * This is the stop entry point of the driver. It needs to undo exactly + * whatever was done by the open entry point, thus it's usually referred to + * as the close function.Among other things this function mainly stops the + * Rx side of the NIC and frees all the Rx buffers in the Rx rings. + * Return value: '0' on success and an appropriate (-)ve integer as + * defined in errno.h file on failure. + */ +int +vxge_close(struct net_device *dev) +{ + do_vxge_close(dev, 1); + return 0; +} + +/** + * vxge_change_mtu + * @dev: net device pointer. + * @new_mtu :the new MTU size for the device. + * + * A driver entry point to change MTU size for the device. Before changing + * the MTU the device must be stopped. + */ +static int vxge_change_mtu(struct net_device *dev, int new_mtu) +{ + struct vxgedev *vdev = netdev_priv(dev); + + vxge_debug_entryexit(vdev->level_trace, + "%s:%d", __func__, __LINE__); + if ((new_mtu < VXGE_HW_MIN_MTU) || (new_mtu > VXGE_HW_MAX_MTU)) { + vxge_debug_init(vdev->level_err, + "%s: mtu size is invalid", dev->name); + return -EPERM; + } + + /* check if device is down already */ + if (unlikely(!is_vxge_card_up(vdev))) { + /* just store new value, will use later on open() */ + dev->mtu = new_mtu; + vxge_debug_init(vdev->level_err, + "%s", "device is down on MTU change"); + return 0; + } + + vxge_debug_init(vdev->level_trace, + "trying to apply new MTU %d", new_mtu); + + if (vxge_close(dev)) + return -EIO; + + dev->mtu = new_mtu; + vdev->mtu = new_mtu; + + if (vxge_open(dev)) + return -EIO; + + vxge_debug_init(vdev->level_trace, + "%s: MTU changed to %d", vdev->ndev->name, new_mtu); + + vxge_debug_entryexit(vdev->level_trace, + "%s:%d Exiting...", __func__, __LINE__); + + return 0; +} + +/** + * vxge_get_stats + * @dev: pointer to the device structure + * + * Updates the device statistics structure. This function updates the device + * statistics structure in the net_device structure and returns a pointer + * to the same. + */ +static struct net_device_stats * +vxge_get_stats(struct net_device *dev) +{ + struct vxgedev *vdev; + struct net_device_stats *net_stats; + int k; + + vdev = netdev_priv(dev); + + net_stats = &vdev->stats.net_stats; + + memset(net_stats, 0, sizeof(struct net_device_stats)); + + for (k = 0; k < vdev->no_of_vpath; k++) { + net_stats->rx_packets += vdev->vpaths[k].ring.stats.rx_frms; + net_stats->rx_bytes += vdev->vpaths[k].ring.stats.rx_bytes; + net_stats->rx_errors += vdev->vpaths[k].ring.stats.rx_errors; + net_stats->multicast += vdev->vpaths[k].ring.stats.rx_mcast; + net_stats->rx_dropped += + vdev->vpaths[k].ring.stats.rx_dropped; + + net_stats->tx_packets += vdev->vpaths[k].fifo.stats.tx_frms; + net_stats->tx_bytes += vdev->vpaths[k].fifo.stats.tx_bytes; + net_stats->tx_errors += vdev->vpaths[k].fifo.stats.tx_errors; + } + + return net_stats; +} + +/** + * vxge_ioctl + * @dev: Device pointer. + * @ifr: An IOCTL specific structure, that can contain a pointer to + * a proprietary structure used to pass information to the driver. + * @cmd: This is used to distinguish between the different commands that + * can be passed to the IOCTL functions. + * + * Entry point for the Ioctl. + */ +static int vxge_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + return -EOPNOTSUPP; +} + +/** + * vxge_tx_watchdog + * @dev: pointer to net device structure + * + * Watchdog for transmit side. + * This function is triggered if the Tx Queue is stopped + * for a pre-defined amount of time when the Interface is still up. + */ +static void +vxge_tx_watchdog(struct net_device *dev) +{ + struct vxgedev *vdev; + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); + + vdev = (struct vxgedev *)netdev_priv(dev); + + vdev->cric_err_event = VXGE_HW_EVENT_RESET_START; + + vxge_reset(vdev); + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Exiting...", __func__, __LINE__); +} + +/** + * vxge_vlan_rx_register + * @dev: net device pointer. + * @grp: vlan group + * + * Vlan group registration + */ +static void +vxge_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) +{ + struct vxgedev *vdev; + struct vxge_vpath *vpath; + int vp; + u64 vid; + enum vxge_hw_status status; + int i; + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); + + vdev = (struct vxgedev *)netdev_priv(dev); + + vpath = &vdev->vpaths[0]; + if ((NULL == grp) && (vpath->is_open)) { + /* Get the first vlan */ + status = vxge_hw_vpath_vid_get(vpath->handle, &vid); + + while (status == VXGE_HW_OK) { + + /* Delete this vlan from the vid table */ + for (vp = 0; vp < vdev->no_of_vpath; vp++) { + vpath = &vdev->vpaths[vp]; + if (!vpath->is_open) + continue; + + vxge_hw_vpath_vid_delete(vpath->handle, vid); + } + + /* Get the next vlan to be deleted */ + vpath = &vdev->vpaths[0]; + status = vxge_hw_vpath_vid_get(vpath->handle, &vid); + } + } + + vdev->vlgrp = grp; + + for (i = 0; i < vdev->no_of_vpath; i++) { + if (vdev->vpaths[i].is_configured) + vdev->vpaths[i].ring.vlgrp = grp; + } + + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Exiting...", __func__, __LINE__); +} + +/** + * vxge_vlan_rx_add_vid + * @dev: net device pointer. + * @vid: vid + * + * Add the vlan id to the devices vlan id table + */ +static void +vxge_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) +{ + struct vxgedev *vdev; + struct vxge_vpath *vpath; + int vp_id; + + vdev = (struct vxgedev *)netdev_priv(dev); + + /* Add these vlan to the vid table */ + for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { + vpath = &vdev->vpaths[vp_id]; + if (!vpath->is_open) + continue; + vxge_hw_vpath_vid_add(vpath->handle, vid); + } +} + +/** + * vxge_vlan_rx_add_vid + * @dev: net device pointer. + * @vid: vid + * + * Remove the vlan id from the device's vlan id table + */ +static void +vxge_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + struct vxgedev *vdev; + struct vxge_vpath *vpath; + int vp_id; + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); + + vdev = (struct vxgedev *)netdev_priv(dev); + + vlan_group_set_device(vdev->vlgrp, vid, NULL); + + /* Delete this vlan from the vid table */ + for (vp_id = 0; vp_id < vdev->no_of_vpath; vp_id++) { + vpath = &vdev->vpaths[vp_id]; + if (!vpath->is_open) + continue; + vxge_hw_vpath_vid_delete(vpath->handle, vid); + } + vxge_debug_entryexit(VXGE_TRACE, + "%s:%d Exiting...", __func__, __LINE__); +} + +static const struct net_device_ops vxge_netdev_ops = { + .ndo_open = vxge_open, + .ndo_stop = vxge_close, + .ndo_get_stats = vxge_get_stats, + .ndo_start_xmit = vxge_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = vxge_set_multicast, + + .ndo_do_ioctl = vxge_ioctl, + + .ndo_set_mac_address = vxge_set_mac_addr, + .ndo_change_mtu = vxge_change_mtu, + .ndo_vlan_rx_register = vxge_vlan_rx_register, + .ndo_vlan_rx_kill_vid = vxge_vlan_rx_kill_vid, + .ndo_vlan_rx_add_vid = vxge_vlan_rx_add_vid, + + .ndo_tx_timeout = vxge_tx_watchdog, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = vxge_netpoll, +#endif +}; + +int __devinit vxge_device_register(struct __vxge_hw_device *hldev, + struct vxge_config *config, + int high_dma, int no_of_vpath, + struct vxgedev **vdev_out) +{ + struct net_device *ndev; + enum vxge_hw_status status = VXGE_HW_OK; + struct vxgedev *vdev; + int i, ret = 0, no_of_queue = 1; + u64 stat; + + *vdev_out = NULL; + if (config->tx_steering_type == TX_MULTIQ_STEERING) + no_of_queue = no_of_vpath; + + ndev = alloc_etherdev_mq(sizeof(struct vxgedev), + no_of_queue); + if (ndev == NULL) { + vxge_debug_init( + vxge_hw_device_trace_level_get(hldev), + "%s : device allocation failed", __func__); + ret = -ENODEV; + goto _out0; + } + + vxge_debug_entryexit( + vxge_hw_device_trace_level_get(hldev), + "%s: %s:%d Entering...", + ndev->name, __func__, __LINE__); + + vdev = netdev_priv(ndev); + memset(vdev, 0, sizeof(struct vxgedev)); + + vdev->ndev = ndev; + vdev->devh = hldev; + vdev->pdev = hldev->pdev; + memcpy(&vdev->config, config, sizeof(struct vxge_config)); + vdev->rx_csum = 1; /* Enable Rx CSUM by default. */ + + SET_NETDEV_DEV(ndev, &vdev->pdev->dev); + + ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; + /* Driver entry points */ + ndev->irq = vdev->pdev->irq; + ndev->base_addr = (unsigned long) hldev->bar0; + + ndev->netdev_ops = &vxge_netdev_ops; + + ndev->watchdog_timeo = VXGE_LL_WATCH_DOG_TIMEOUT; + + initialize_ethtool_ops(ndev); + + /* Allocate memory for vpath */ + vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) * + no_of_vpath, GFP_KERNEL); + if (!vdev->vpaths) { + vxge_debug_init(VXGE_ERR, + "%s: vpath memory allocation failed", + vdev->ndev->name); + ret = -ENODEV; + goto _out1; + } + + ndev->features |= NETIF_F_SG; + + ndev->features |= NETIF_F_HW_CSUM; + vxge_debug_init(vxge_hw_device_trace_level_get(hldev), + "%s : checksuming enabled", __func__); + + if (high_dma) { + ndev->features |= NETIF_F_HIGHDMA; + vxge_debug_init(vxge_hw_device_trace_level_get(hldev), + "%s : using High DMA", __func__); + } + + ndev->features |= NETIF_F_TSO | NETIF_F_TSO6; + + if (vdev->config.gro_enable) + ndev->features |= NETIF_F_GRO; + + if (vdev->config.tx_steering_type == TX_MULTIQ_STEERING) + ndev->real_num_tx_queues = no_of_vpath; + +#ifdef NETIF_F_LLTX + ndev->features |= NETIF_F_LLTX; +#endif + + for (i = 0; i < no_of_vpath; i++) + spin_lock_init(&vdev->vpaths[i].fifo.tx_lock); + + if (register_netdev(ndev)) { + vxge_debug_init(vxge_hw_device_trace_level_get(hldev), + "%s: %s : device registration failed!", + ndev->name, __func__); + ret = -ENODEV; + goto _out2; + } + + /* Set the factory defined MAC address initially */ + ndev->addr_len = ETH_ALEN; + + /* Make Link state as off at this point, when the Link change + * interrupt comes the state will be automatically changed to + * the right state. + */ + netif_carrier_off(ndev); + + vxge_debug_init(vxge_hw_device_trace_level_get(hldev), + "%s: Ethernet device registered", + ndev->name); + + *vdev_out = vdev; + + /* Resetting the Device stats */ + status = vxge_hw_mrpcim_stats_access( + hldev, + VXGE_HW_STATS_OP_CLEAR_ALL_STATS, + 0, + 0, + &stat); + + if (status == VXGE_HW_ERR_PRIVILAGED_OPEARATION) + vxge_debug_init( + vxge_hw_device_trace_level_get(hldev), + "%s: device stats clear returns" + "VXGE_HW_ERR_PRIVILAGED_OPEARATION", ndev->name); + + vxge_debug_entryexit(vxge_hw_device_trace_level_get(hldev), + "%s: %s:%d Exiting...", + ndev->name, __func__, __LINE__); + + return ret; +_out2: + kfree(vdev->vpaths); +_out1: + free_netdev(ndev); +_out0: + return ret; +} + +/* + * vxge_device_unregister + * + * This function will unregister and free network device + */ +void +vxge_device_unregister(struct __vxge_hw_device *hldev) +{ + struct vxgedev *vdev; + struct net_device *dev; + char buf[IFNAMSIZ]; +#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \ + (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)) + u32 level_trace; +#endif + + dev = hldev->ndev; + vdev = netdev_priv(dev); +#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \ + (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)) + level_trace = vdev->level_trace; +#endif + vxge_debug_entryexit(level_trace, + "%s: %s:%d", vdev->ndev->name, __func__, __LINE__); + + memcpy(buf, vdev->ndev->name, IFNAMSIZ); + + /* in 2.6 will call stop() if device is up */ + unregister_netdev(dev); + + flush_scheduled_work(); + + vxge_debug_init(level_trace, "%s: ethernet device unregistered", buf); + vxge_debug_entryexit(level_trace, + "%s: %s:%d Exiting...", buf, __func__, __LINE__); +} + +/* + * vxge_callback_crit_err + * + * This function is called by the alarm handler in interrupt context. + * Driver must analyze it based on the event type. + */ +static void +vxge_callback_crit_err(struct __vxge_hw_device *hldev, + enum vxge_hw_event type, u64 vp_id) +{ + struct net_device *dev = hldev->ndev; + struct vxgedev *vdev = (struct vxgedev *)netdev_priv(dev); + int vpath_idx; + + vxge_debug_entryexit(vdev->level_trace, + "%s: %s:%d", vdev->ndev->name, __func__, __LINE__); + + /* Note: This event type should be used for device wide + * indications only - Serious errors, Slot freeze and critical errors + */ + vdev->cric_err_event = type; + + for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath; vpath_idx++) + if (vdev->vpaths[vpath_idx].device_id == vp_id) + break; + + if (!test_bit(__VXGE_STATE_RESET_CARD, &vdev->state)) { + if (type == VXGE_HW_EVENT_SLOT_FREEZE) { + vxge_debug_init(VXGE_ERR, + "%s: Slot is frozen", vdev->ndev->name); + } else if (type == VXGE_HW_EVENT_SERR) { + vxge_debug_init(VXGE_ERR, + "%s: Encountered Serious Error", + vdev->ndev->name); + } else if (type == VXGE_HW_EVENT_CRITICAL_ERR) + vxge_debug_init(VXGE_ERR, + "%s: Encountered Critical Error", + vdev->ndev->name); + } + + if ((type == VXGE_HW_EVENT_SERR) || + (type == VXGE_HW_EVENT_SLOT_FREEZE)) { + if (unlikely(vdev->exec_mode)) + clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); + } else if (type == VXGE_HW_EVENT_CRITICAL_ERR) { + vxge_hw_device_mask_all(hldev); + if (unlikely(vdev->exec_mode)) + clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); + } else if ((type == VXGE_HW_EVENT_FIFO_ERR) || + (type == VXGE_HW_EVENT_VPATH_ERR)) { + + if (unlikely(vdev->exec_mode)) + clear_bit(__VXGE_STATE_CARD_UP, &vdev->state); + else { + /* check if this vpath is already set for reset */ + if (!test_and_set_bit(vpath_idx, &vdev->vp_reset)) { + + /* disable interrupts for this vpath */ + vxge_vpath_intr_disable(vdev, vpath_idx); + + /* stop the queue for this vpath */ + vxge_stop_tx_queue(&vdev->vpaths[vpath_idx]. + fifo); + } + } + } + + vxge_debug_entryexit(vdev->level_trace, + "%s: %s:%d Exiting...", + vdev->ndev->name, __func__, __LINE__); +} + +static void verify_bandwidth(void) +{ + int i, band_width, total = 0, equal_priority = 0; + + /* 1. If user enters 0 for some fifo, give equal priority to all */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + if (bw_percentage[i] == 0) { + equal_priority = 1; + break; + } + } + + if (!equal_priority) { + /* 2. If sum exceeds 100, give equal priority to all */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + if (bw_percentage[i] == 0xFF) + break; + + total += bw_percentage[i]; + if (total > VXGE_HW_VPATH_BANDWIDTH_MAX) { + equal_priority = 1; + break; + } + } + } + + if (!equal_priority) { + /* Is all the bandwidth consumed? */ + if (total < VXGE_HW_VPATH_BANDWIDTH_MAX) { + if (i < VXGE_HW_MAX_VIRTUAL_PATHS) { + /* Split rest of bw equally among next VPs*/ + band_width = + (VXGE_HW_VPATH_BANDWIDTH_MAX - total) / + (VXGE_HW_MAX_VIRTUAL_PATHS - i); + if (band_width < 2) /* min of 2% */ + equal_priority = 1; + else { + for (; i < VXGE_HW_MAX_VIRTUAL_PATHS; + i++) + bw_percentage[i] = + band_width; + } + } + } else if (i < VXGE_HW_MAX_VIRTUAL_PATHS) + equal_priority = 1; + } + + if (equal_priority) { + vxge_debug_init(VXGE_ERR, + "%s: Assigning equal bandwidth to all the vpaths", + VXGE_DRIVER_NAME); + bw_percentage[0] = VXGE_HW_VPATH_BANDWIDTH_MAX / + VXGE_HW_MAX_VIRTUAL_PATHS; + for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) + bw_percentage[i] = bw_percentage[0]; + } + + return; +} + +/* + * Vpath configuration + */ +static int __devinit vxge_config_vpaths( + struct vxge_hw_device_config *device_config, + u64 vpath_mask, struct vxge_config *config_param) +{ + int i, no_of_vpaths = 0, default_no_vpath = 0, temp; + u32 txdl_size, txdl_per_memblock; + + temp = driver_config->vpath_per_dev; + if ((driver_config->vpath_per_dev == VXGE_USE_DEFAULT) && + (max_config_dev == VXGE_MAX_CONFIG_DEV)) { + /* No more CPU. Return vpath number as zero.*/ + if (driver_config->g_no_cpus == -1) + return 0; + + if (!driver_config->g_no_cpus) + driver_config->g_no_cpus = num_online_cpus(); + + driver_config->vpath_per_dev = driver_config->g_no_cpus >> 1; + if (!driver_config->vpath_per_dev) + driver_config->vpath_per_dev = 1; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) + if (!vxge_bVALn(vpath_mask, i, 1)) + continue; + else + default_no_vpath++; + if (default_no_vpath < driver_config->vpath_per_dev) + driver_config->vpath_per_dev = default_no_vpath; + + driver_config->g_no_cpus = driver_config->g_no_cpus - + (driver_config->vpath_per_dev * 2); + if (driver_config->g_no_cpus <= 0) + driver_config->g_no_cpus = -1; + } + + if (driver_config->vpath_per_dev == 1) { + vxge_debug_ll_config(VXGE_TRACE, + "%s: Disable tx and rx steering, " + "as single vpath is configured", VXGE_DRIVER_NAME); + config_param->rth_steering = NO_STEERING; + config_param->tx_steering_type = NO_STEERING; + device_config->rth_en = 0; + } + + /* configure bandwidth */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) + device_config->vp_config[i].min_bandwidth = bw_percentage[i]; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + device_config->vp_config[i].vp_id = i; + device_config->vp_config[i].mtu = VXGE_HW_DEFAULT_MTU; + if (no_of_vpaths < driver_config->vpath_per_dev) { + if (!vxge_bVALn(vpath_mask, i, 1)) { + vxge_debug_ll_config(VXGE_TRACE, + "%s: vpath: %d is not available", + VXGE_DRIVER_NAME, i); + continue; + } else { + vxge_debug_ll_config(VXGE_TRACE, + "%s: vpath: %d available", + VXGE_DRIVER_NAME, i); + no_of_vpaths++; + } + } else { + vxge_debug_ll_config(VXGE_TRACE, + "%s: vpath: %d is not configured, " + "max_config_vpath exceeded", + VXGE_DRIVER_NAME, i); + break; + } + + /* Configure Tx fifo's */ + device_config->vp_config[i].fifo.enable = + VXGE_HW_FIFO_ENABLE; + device_config->vp_config[i].fifo.max_frags = + MAX_SKB_FRAGS; + device_config->vp_config[i].fifo.memblock_size = + VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE; + + txdl_size = MAX_SKB_FRAGS * sizeof(struct vxge_hw_fifo_txd); + txdl_per_memblock = VXGE_HW_MIN_FIFO_MEMBLOCK_SIZE / txdl_size; + + device_config->vp_config[i].fifo.fifo_blocks = + ((VXGE_DEF_FIFO_LENGTH - 1) / txdl_per_memblock) + 1; + + device_config->vp_config[i].fifo.intr = + VXGE_HW_FIFO_QUEUE_INTR_DISABLE; + + /* Configure tti properties */ + device_config->vp_config[i].tti.intr_enable = + VXGE_HW_TIM_INTR_ENABLE; + + device_config->vp_config[i].tti.btimer_val = + (VXGE_TTI_BTIMER_VAL * 1000) / 272; + + device_config->vp_config[i].tti.timer_ac_en = + VXGE_HW_TIM_TIMER_AC_ENABLE; + + /* For msi-x with napi (each vector + has a handler of its own) - + Set CI to OFF for all vpaths */ + device_config->vp_config[i].tti.timer_ci_en = + VXGE_HW_TIM_TIMER_CI_DISABLE; + + device_config->vp_config[i].tti.timer_ri_en = + VXGE_HW_TIM_TIMER_RI_DISABLE; + + device_config->vp_config[i].tti.util_sel = + VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL; + + device_config->vp_config[i].tti.ltimer_val = + (VXGE_TTI_LTIMER_VAL * 1000) / 272; + + device_config->vp_config[i].tti.rtimer_val = + (VXGE_TTI_RTIMER_VAL * 1000) / 272; + + device_config->vp_config[i].tti.urange_a = TTI_TX_URANGE_A; + device_config->vp_config[i].tti.urange_b = TTI_TX_URANGE_B; + device_config->vp_config[i].tti.urange_c = TTI_TX_URANGE_C; + device_config->vp_config[i].tti.uec_a = TTI_TX_UFC_A; + device_config->vp_config[i].tti.uec_b = TTI_TX_UFC_B; + device_config->vp_config[i].tti.uec_c = TTI_TX_UFC_C; + device_config->vp_config[i].tti.uec_d = TTI_TX_UFC_D; + + /* Configure Rx rings */ + device_config->vp_config[i].ring.enable = + VXGE_HW_RING_ENABLE; + + device_config->vp_config[i].ring.ring_blocks = + VXGE_HW_DEF_RING_BLOCKS; + device_config->vp_config[i].ring.buffer_mode = + VXGE_HW_RING_RXD_BUFFER_MODE_1; + device_config->vp_config[i].ring.rxds_limit = + VXGE_HW_DEF_RING_RXDS_LIMIT; + device_config->vp_config[i].ring.scatter_mode = + VXGE_HW_RING_SCATTER_MODE_A; + + /* Configure rti properties */ + device_config->vp_config[i].rti.intr_enable = + VXGE_HW_TIM_INTR_ENABLE; + + device_config->vp_config[i].rti.btimer_val = + (VXGE_RTI_BTIMER_VAL * 1000)/272; + + device_config->vp_config[i].rti.timer_ac_en = + VXGE_HW_TIM_TIMER_AC_ENABLE; + + device_config->vp_config[i].rti.timer_ci_en = + VXGE_HW_TIM_TIMER_CI_DISABLE; + + device_config->vp_config[i].rti.timer_ri_en = + VXGE_HW_TIM_TIMER_RI_DISABLE; + + device_config->vp_config[i].rti.util_sel = + VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL; + + device_config->vp_config[i].rti.urange_a = + RTI_RX_URANGE_A; + device_config->vp_config[i].rti.urange_b = + RTI_RX_URANGE_B; + device_config->vp_config[i].rti.urange_c = + RTI_RX_URANGE_C; + device_config->vp_config[i].rti.uec_a = RTI_RX_UFC_A; + device_config->vp_config[i].rti.uec_b = RTI_RX_UFC_B; + device_config->vp_config[i].rti.uec_c = RTI_RX_UFC_C; + device_config->vp_config[i].rti.uec_d = RTI_RX_UFC_D; + + device_config->vp_config[i].rti.rtimer_val = + (VXGE_RTI_RTIMER_VAL * 1000) / 272; + + device_config->vp_config[i].rti.ltimer_val = + (VXGE_RTI_LTIMER_VAL * 1000) / 272; + + device_config->vp_config[i].rpa_strip_vlan_tag = + vlan_tag_strip; + } + + driver_config->vpath_per_dev = temp; + return no_of_vpaths; +} + +/* initialize device configuratrions */ +static void __devinit vxge_device_config_init( + struct vxge_hw_device_config *device_config, + int *intr_type) +{ + /* Used for CQRQ/SRQ. */ + device_config->dma_blockpool_initial = + VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE; + + device_config->dma_blockpool_max = + VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE; + + if (max_mac_vpath > VXGE_MAX_MAC_ADDR_COUNT) + max_mac_vpath = VXGE_MAX_MAC_ADDR_COUNT; + +#ifndef CONFIG_PCI_MSI + vxge_debug_init(VXGE_ERR, + "%s: This Kernel does not support " + "MSI-X. Defaulting to INTA", VXGE_DRIVER_NAME); + *intr_type = INTA; +#endif + + /* Configure whether MSI-X or IRQL. */ + switch (*intr_type) { + case INTA: + device_config->intr_mode = VXGE_HW_INTR_MODE_IRQLINE; + break; + + case MSI_X: + device_config->intr_mode = VXGE_HW_INTR_MODE_MSIX; + break; + } + /* Timer period between device poll */ + device_config->device_poll_millis = VXGE_TIMER_DELAY; + + /* Configure mac based steering. */ + device_config->rts_mac_en = addr_learn_en; + + /* Configure Vpaths */ + device_config->rth_it_type = VXGE_HW_RTH_IT_TYPE_MULTI_IT; + + vxge_debug_ll_config(VXGE_TRACE, "%s : Device Config Params ", + __func__); + vxge_debug_ll_config(VXGE_TRACE, "dma_blockpool_initial : %d", + device_config->dma_blockpool_initial); + vxge_debug_ll_config(VXGE_TRACE, "dma_blockpool_max : %d", + device_config->dma_blockpool_max); + vxge_debug_ll_config(VXGE_TRACE, "intr_mode : %d", + device_config->intr_mode); + vxge_debug_ll_config(VXGE_TRACE, "device_poll_millis : %d", + device_config->device_poll_millis); + vxge_debug_ll_config(VXGE_TRACE, "rts_mac_en : %d", + device_config->rts_mac_en); + vxge_debug_ll_config(VXGE_TRACE, "rth_en : %d", + device_config->rth_en); + vxge_debug_ll_config(VXGE_TRACE, "rth_it_type : %d", + device_config->rth_it_type); +} + +static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask) +{ + int i; + + vxge_debug_init(VXGE_TRACE, + "%s: %d Vpath(s) opened", + vdev->ndev->name, vdev->no_of_vpath); + + switch (vdev->config.intr_type) { + case INTA: + vxge_debug_init(VXGE_TRACE, + "%s: Interrupt type INTA", vdev->ndev->name); + break; + + case MSI_X: + vxge_debug_init(VXGE_TRACE, + "%s: Interrupt type MSI-X", vdev->ndev->name); + break; + } + + if (vdev->config.rth_steering) { + vxge_debug_init(VXGE_TRACE, + "%s: RTH steering enabled for TCP_IPV4", + vdev->ndev->name); + } else { + vxge_debug_init(VXGE_TRACE, + "%s: RTH steering disabled", vdev->ndev->name); + } + + switch (vdev->config.tx_steering_type) { + case NO_STEERING: + vxge_debug_init(VXGE_TRACE, + "%s: Tx steering disabled", vdev->ndev->name); + break; + case TX_PRIORITY_STEERING: + vxge_debug_init(VXGE_TRACE, + "%s: Unsupported tx steering option", + vdev->ndev->name); + vxge_debug_init(VXGE_TRACE, + "%s: Tx steering disabled", vdev->ndev->name); + vdev->config.tx_steering_type = 0; + break; + case TX_VLAN_STEERING: + vxge_debug_init(VXGE_TRACE, + "%s: Unsupported tx steering option", + vdev->ndev->name); + vxge_debug_init(VXGE_TRACE, + "%s: Tx steering disabled", vdev->ndev->name); + vdev->config.tx_steering_type = 0; + break; + case TX_MULTIQ_STEERING: + vxge_debug_init(VXGE_TRACE, + "%s: Tx multiqueue steering enabled", + vdev->ndev->name); + break; + case TX_PORT_STEERING: + vxge_debug_init(VXGE_TRACE, + "%s: Tx port steering enabled", + vdev->ndev->name); + break; + default: + vxge_debug_init(VXGE_ERR, + "%s: Unsupported tx steering type", + vdev->ndev->name); + vxge_debug_init(VXGE_TRACE, + "%s: Tx steering disabled", vdev->ndev->name); + vdev->config.tx_steering_type = 0; + } + + if (vdev->config.gro_enable) { + vxge_debug_init(VXGE_ERR, + "%s: Generic receive offload enabled", + vdev->ndev->name); + } else + vxge_debug_init(VXGE_TRACE, + "%s: Generic receive offload disabled", + vdev->ndev->name); + + if (vdev->config.addr_learn_en) + vxge_debug_init(VXGE_TRACE, + "%s: MAC Address learning enabled", vdev->ndev->name); + + vxge_debug_init(VXGE_TRACE, + "%s: Rx doorbell mode enabled", vdev->ndev->name); + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + if (!vxge_bVALn(vpath_mask, i, 1)) + continue; + vxge_debug_ll_config(VXGE_TRACE, + "%s: MTU size - %d", vdev->ndev->name, + ((struct __vxge_hw_device *)(vdev->devh))-> + config.vp_config[i].mtu); + vxge_debug_init(VXGE_TRACE, + "%s: VLAN tag stripping %s", vdev->ndev->name, + ((struct __vxge_hw_device *)(vdev->devh))-> + config.vp_config[i].rpa_strip_vlan_tag + ? "Enabled" : "Disabled"); + vxge_debug_init(VXGE_TRACE, + "%s: Ring blocks : %d", vdev->ndev->name, + ((struct __vxge_hw_device *)(vdev->devh))-> + config.vp_config[i].ring.ring_blocks); + vxge_debug_init(VXGE_TRACE, + "%s: Fifo blocks : %d", vdev->ndev->name, + ((struct __vxge_hw_device *)(vdev->devh))-> + config.vp_config[i].fifo.fifo_blocks); + vxge_debug_ll_config(VXGE_TRACE, + "%s: Max frags : %d", vdev->ndev->name, + ((struct __vxge_hw_device *)(vdev->devh))-> + config.vp_config[i].fifo.max_frags); + break; + } +} + +#ifdef CONFIG_PM +/** + * vxge_pm_suspend - vxge power management suspend entry point + * + */ +static int vxge_pm_suspend(struct pci_dev *pdev, pm_message_t state) +{ + return -ENOSYS; +} +/** + * vxge_pm_resume - vxge power management resume entry point + * + */ +static int vxge_pm_resume(struct pci_dev *pdev) +{ + return -ENOSYS; +} + +#endif + +/** + * vxge_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t vxge_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct __vxge_hw_device *hldev = + (struct __vxge_hw_device *) pci_get_drvdata(pdev); + struct net_device *netdev = hldev->ndev; + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + /* Bring down the card, while avoiding PCI I/O */ + do_vxge_close(netdev, 0); + } + + pci_disable_device(pdev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * vxge_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + * At this point, the card has exprienced a hard reset, + * followed by fixups by BIOS, and has its config space + * set up identically to what it was at cold boot. + */ +static pci_ers_result_t vxge_io_slot_reset(struct pci_dev *pdev) +{ + struct __vxge_hw_device *hldev = + (struct __vxge_hw_device *) pci_get_drvdata(pdev); + struct net_device *netdev = hldev->ndev; + + struct vxgedev *vdev = netdev_priv(netdev); + + if (pci_enable_device(pdev)) { + printk(KERN_ERR "%s: " + "Cannot re-enable device after reset\n", + VXGE_DRIVER_NAME); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + vxge_reset(vdev); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * vxge_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells + * us that its OK to resume normal operation. + */ +static void vxge_io_resume(struct pci_dev *pdev) +{ + struct __vxge_hw_device *hldev = + (struct __vxge_hw_device *) pci_get_drvdata(pdev); + struct net_device *netdev = hldev->ndev; + + if (netif_running(netdev)) { + if (vxge_open(netdev)) { + printk(KERN_ERR "%s: " + "Can't bring device back up after reset\n", + VXGE_DRIVER_NAME); + return; + } + } + + netif_device_attach(netdev); +} + +/** + * vxge_probe + * @pdev : structure containing the PCI related information of the device. + * @pre: List of PCI devices supported by the driver listed in vxge_id_table. + * Description: + * This function is called when a new PCI device gets detected and initializes + * it. + * Return value: + * returns 0 on success and negative on failure. + * + */ +static int __devinit +vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) +{ + struct __vxge_hw_device *hldev; + enum vxge_hw_status status; + int ret; + int high_dma = 0; + u64 vpath_mask = 0; + struct vxgedev *vdev; + struct vxge_config ll_config; + struct vxge_hw_device_config *device_config = NULL; + struct vxge_hw_device_attr attr; + int i, j, no_of_vpath = 0, max_vpath_supported = 0; + u8 *macaddr; + struct vxge_mac_addrs *entry; + static int bus = -1, device = -1; + u8 new_device = 0; + + vxge_debug_entryexit(VXGE_TRACE, "%s:%d", __func__, __LINE__); + attr.pdev = pdev; + + if (bus != pdev->bus->number) + new_device = 1; + if (device != PCI_SLOT(pdev->devfn)) + new_device = 1; + + bus = pdev->bus->number; + device = PCI_SLOT(pdev->devfn); + + if (new_device) { + if (driver_config->config_dev_cnt && + (driver_config->config_dev_cnt != + driver_config->total_dev_cnt)) + vxge_debug_init(VXGE_ERR, + "%s: Configured %d of %d devices", + VXGE_DRIVER_NAME, + driver_config->config_dev_cnt, + driver_config->total_dev_cnt); + driver_config->config_dev_cnt = 0; + driver_config->total_dev_cnt = 0; + driver_config->g_no_cpus = 0; + driver_config->vpath_per_dev = max_config_vpath; + } + + driver_config->total_dev_cnt++; + if (++driver_config->config_dev_cnt > max_config_dev) { + ret = 0; + goto _exit0; + } + + device_config = kzalloc(sizeof(struct vxge_hw_device_config), + GFP_KERNEL); + if (!device_config) { + ret = -ENOMEM; + vxge_debug_init(VXGE_ERR, + "device_config : malloc failed %s %d", + __FILE__, __LINE__); + goto _exit0; + } + + memset(&ll_config, 0, sizeof(struct vxge_config)); + ll_config.tx_steering_type = TX_MULTIQ_STEERING; + ll_config.intr_type = MSI_X; + ll_config.napi_weight = NEW_NAPI_WEIGHT; + ll_config.rth_steering = RTH_STEERING; + + /* get the default configuration parameters */ + vxge_hw_device_config_default_get(device_config); + + /* initialize configuration parameters */ + vxge_device_config_init(device_config, &ll_config.intr_type); + + ret = pci_enable_device(pdev); + if (ret) { + vxge_debug_init(VXGE_ERR, + "%s : can not enable PCI device", __func__); + goto _exit0; + } + + if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { + vxge_debug_ll_config(VXGE_TRACE, + "%s : using 64bit DMA", __func__); + + high_dma = 1; + + if (pci_set_consistent_dma_mask(pdev, + 0xffffffffffffffffULL)) { + vxge_debug_init(VXGE_ERR, + "%s : unable to obtain 64bit DMA for " + "consistent allocations", __func__); + ret = -ENOMEM; + goto _exit1; + } + } else if (!pci_set_dma_mask(pdev, 0xffffffffUL)) { + vxge_debug_ll_config(VXGE_TRACE, + "%s : using 32bit DMA", __func__); + } else { + ret = -ENOMEM; + goto _exit1; + } + + if (pci_request_regions(pdev, VXGE_DRIVER_NAME)) { + vxge_debug_init(VXGE_ERR, + "%s : request regions failed", __func__); + ret = -ENODEV; + goto _exit1; + } + + pci_set_master(pdev); + + attr.bar0 = pci_ioremap_bar(pdev, 0); + if (!attr.bar0) { + vxge_debug_init(VXGE_ERR, + "%s : cannot remap io memory bar0", __func__); + ret = -ENODEV; + goto _exit2; + } + vxge_debug_ll_config(VXGE_TRACE, + "pci ioremap bar0: %p:0x%llx", + attr.bar0, + (unsigned long long)pci_resource_start(pdev, 0)); + + attr.bar1 = pci_ioremap_bar(pdev, 2); + if (!attr.bar1) { + vxge_debug_init(VXGE_ERR, + "%s : cannot remap io memory bar2", __func__); + ret = -ENODEV; + goto _exit3; + } + vxge_debug_ll_config(VXGE_TRACE, + "pci ioremap bar1: %p:0x%llx", + attr.bar1, + (unsigned long long)pci_resource_start(pdev, 2)); + + status = vxge_hw_device_hw_info_get(attr.bar0, + &ll_config.device_hw_info); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "%s: Reading of hardware info failed." + "Please try upgrading the firmware.", VXGE_DRIVER_NAME); + ret = -EINVAL; + goto _exit4; + } + + if (ll_config.device_hw_info.fw_version.major != + VXGE_DRIVER_VERSION_MAJOR) { + vxge_debug_init(VXGE_ERR, + "FW Ver.(maj): %d not driver's expected version: %d", + ll_config.device_hw_info.fw_version.major, + VXGE_DRIVER_VERSION_MAJOR); + ret = -EINVAL; + goto _exit4; + } + + vpath_mask = ll_config.device_hw_info.vpath_mask; + if (vpath_mask == 0) { + vxge_debug_ll_config(VXGE_TRACE, + "%s: No vpaths available in device", VXGE_DRIVER_NAME); + ret = -EINVAL; + goto _exit4; + } + + vxge_debug_ll_config(VXGE_TRACE, + "%s:%d Vpath mask = %llx", __func__, __LINE__, + (unsigned long long)vpath_mask); + + /* Check how many vpaths are available */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + if (!((vpath_mask) & vxge_mBIT(i))) + continue; + max_vpath_supported++; + } + + /* + * Configure vpaths and get driver configured number of vpaths + * which is less than or equal to the maximum vpaths per function. + */ + no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, &ll_config); + if (!no_of_vpath) { + vxge_debug_ll_config(VXGE_ERR, + "%s: No more vpaths to configure", VXGE_DRIVER_NAME); + ret = 0; + goto _exit4; + } + + /* Setting driver callbacks */ + attr.uld_callbacks.link_up = vxge_callback_link_up; + attr.uld_callbacks.link_down = vxge_callback_link_down; + attr.uld_callbacks.crit_err = vxge_callback_crit_err; + + status = vxge_hw_device_initialize(&hldev, &attr, device_config); + if (status != VXGE_HW_OK) { + vxge_debug_init(VXGE_ERR, + "Failed to initialize device (%d)", status); + ret = -EINVAL; + goto _exit4; + } + + vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); + + /* set private device info */ + pci_set_drvdata(pdev, hldev); + + ll_config.gro_enable = VXGE_GRO_ALWAYS_AGGREGATE; + ll_config.fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS; + ll_config.addr_learn_en = addr_learn_en; + ll_config.rth_algorithm = RTH_ALG_JENKINS; + ll_config.rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4; + ll_config.rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE; + ll_config.rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE; + ll_config.rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE; + ll_config.rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE; + ll_config.rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE; + ll_config.rth_bkt_sz = RTH_BUCKET_SIZE; + ll_config.tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; + ll_config.rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; + + if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath, + &vdev)) { + ret = -EINVAL; + goto _exit5; + } + + vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL); + VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev), + vxge_hw_device_trace_level_get(hldev)); + + /* set private HW device info */ + hldev->ndev = vdev->ndev; + vdev->mtu = VXGE_HW_DEFAULT_MTU; + vdev->bar0 = attr.bar0; + vdev->bar1 = attr.bar1; + vdev->max_vpath_supported = max_vpath_supported; + vdev->no_of_vpath = no_of_vpath; + + /* Virtual Path count */ + for (i = 0, j = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + if (!vxge_bVALn(vpath_mask, i, 1)) + continue; + if (j >= vdev->no_of_vpath) + break; + + vdev->vpaths[j].is_configured = 1; + vdev->vpaths[j].device_id = i; + vdev->vpaths[j].fifo.driver_id = j; + vdev->vpaths[j].ring.driver_id = j; + vdev->vpaths[j].vdev = vdev; + vdev->vpaths[j].max_mac_addr_cnt = max_mac_vpath; + memcpy((u8 *)vdev->vpaths[j].macaddr, + (u8 *)ll_config.device_hw_info.mac_addrs[i], + ETH_ALEN); + + /* Initialize the mac address list header */ + INIT_LIST_HEAD(&vdev->vpaths[j].mac_addr_list); + + vdev->vpaths[j].mac_addr_cnt = 0; + vdev->vpaths[j].mcast_addr_cnt = 0; + j++; + } + vdev->exec_mode = VXGE_EXEC_MODE_DISABLE; + vdev->max_config_port = max_config_port; + + vdev->vlan_tag_strip = vlan_tag_strip; + + /* map the hashing selector table to the configured vpaths */ + for (i = 0; i < vdev->no_of_vpath; i++) + vdev->vpath_selector[i] = vpath_selector[i]; + + macaddr = (u8 *)vdev->vpaths[0].macaddr; + + ll_config.device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0'; + ll_config.device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0'; + ll_config.device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0'; + + vxge_debug_init(VXGE_TRACE, "%s: SERIAL NUMBER: %s", + vdev->ndev->name, ll_config.device_hw_info.serial_number); + + vxge_debug_init(VXGE_TRACE, "%s: PART NUMBER: %s", + vdev->ndev->name, ll_config.device_hw_info.part_number); + + vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter", + vdev->ndev->name, ll_config.device_hw_info.product_desc); + + vxge_debug_init(VXGE_TRACE, + "%s: MAC ADDR: %02X:%02X:%02X:%02X:%02X:%02X", + vdev->ndev->name, macaddr[0], macaddr[1], macaddr[2], + macaddr[3], macaddr[4], macaddr[5]); + + vxge_debug_init(VXGE_TRACE, "%s: Link Width x%d", + vdev->ndev->name, vxge_hw_device_link_width_get(hldev)); + + vxge_debug_init(VXGE_TRACE, + "%s: Firmware version : %s Date : %s", vdev->ndev->name, + ll_config.device_hw_info.fw_version.version, + ll_config.device_hw_info.fw_date.date); + + vxge_print_parm(vdev, vpath_mask); + + /* Store the fw version for ethttool option */ + strcpy(vdev->fw_version, ll_config.device_hw_info.fw_version.version); + memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN); + memcpy(vdev->ndev->perm_addr, vdev->ndev->dev_addr, ETH_ALEN); + + /* Copy the station mac address to the list */ + for (i = 0; i < vdev->no_of_vpath; i++) { + entry = (struct vxge_mac_addrs *) + kzalloc(sizeof(struct vxge_mac_addrs), + GFP_KERNEL); + if (NULL == entry) { + vxge_debug_init(VXGE_ERR, + "%s: mac_addr_list : memory allocation failed", + vdev->ndev->name); + ret = -EPERM; + goto _exit6; + } + macaddr = (u8 *)&entry->macaddr; + memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN); + list_add(&entry->item, &vdev->vpaths[i].mac_addr_list); + vdev->vpaths[i].mac_addr_cnt = 1; + } + + vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...", + vdev->ndev->name, __func__, __LINE__); + + vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL); + VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev), + vxge_hw_device_trace_level_get(hldev)); + + return 0; + +_exit6: + for (i = 0; i < vdev->no_of_vpath; i++) + vxge_free_mac_add_list(&vdev->vpaths[i]); + + vxge_device_unregister(hldev); +_exit5: + vxge_hw_device_terminate(hldev); +_exit4: + iounmap(attr.bar1); +_exit3: + iounmap(attr.bar0); +_exit2: + pci_release_regions(pdev); +_exit1: + pci_disable_device(pdev); +_exit0: + kfree(device_config); + driver_config->config_dev_cnt--; + pci_set_drvdata(pdev, NULL); + return ret; +} + +/** + * vxge_rem_nic - Free the PCI device + * @pdev: structure containing the PCI related information of the device. + * Description: This function is called by the Pci subsystem to release a + * PCI device and free up all resource held up by the device. + */ +static void __devexit +vxge_remove(struct pci_dev *pdev) +{ + struct __vxge_hw_device *hldev; + struct vxgedev *vdev = NULL; + struct net_device *dev; + int i = 0; +#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \ + (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)) + u32 level_trace; +#endif + + hldev = (struct __vxge_hw_device *) pci_get_drvdata(pdev); + + if (hldev == NULL) + return; + dev = hldev->ndev; + vdev = netdev_priv(dev); + +#if ((VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) || \ + (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK)) + level_trace = vdev->level_trace; +#endif + vxge_debug_entryexit(level_trace, + "%s:%d", __func__, __LINE__); + + vxge_debug_init(level_trace, + "%s : removing PCI device...", __func__); + vxge_device_unregister(hldev); + + for (i = 0; i < vdev->no_of_vpath; i++) { + vxge_free_mac_add_list(&vdev->vpaths[i]); + vdev->vpaths[i].mcast_addr_cnt = 0; + vdev->vpaths[i].mac_addr_cnt = 0; + } + + kfree(vdev->vpaths); + + iounmap(vdev->bar0); + iounmap(vdev->bar1); + + /* we are safe to free it now */ + free_netdev(dev); + + vxge_debug_init(level_trace, + "%s:%d Device unregistered", __func__, __LINE__); + + vxge_hw_device_terminate(hldev); + + pci_disable_device(pdev); + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + vxge_debug_entryexit(level_trace, + "%s:%d Exiting...", __func__, __LINE__); +} + +static struct pci_error_handlers vxge_err_handler = { + .error_detected = vxge_io_error_detected, + .slot_reset = vxge_io_slot_reset, + .resume = vxge_io_resume, +}; + +static struct pci_driver vxge_driver = { + .name = VXGE_DRIVER_NAME, + .id_table = vxge_id_table, + .probe = vxge_probe, + .remove = __devexit_p(vxge_remove), +#ifdef CONFIG_PM + .suspend = vxge_pm_suspend, + .resume = vxge_pm_resume, +#endif + .err_handler = &vxge_err_handler, +}; + +static int __init +vxge_starter(void) +{ + int ret = 0; + char version[32]; + snprintf(version, 32, "%s", DRV_VERSION); + + printk(KERN_CRIT "%s: Copyright(c) 2002-2009 Neterion Inc\n", + VXGE_DRIVER_NAME); + printk(KERN_CRIT "%s: Driver version: %s\n", + VXGE_DRIVER_NAME, version); + + verify_bandwidth(); + + driver_config = kzalloc(sizeof(struct vxge_drv_config), GFP_KERNEL); + if (!driver_config) + return -ENOMEM; + + ret = pci_register_driver(&vxge_driver); + + if (driver_config->config_dev_cnt && + (driver_config->config_dev_cnt != driver_config->total_dev_cnt)) + vxge_debug_init(VXGE_ERR, + "%s: Configured %d of %d devices", + VXGE_DRIVER_NAME, driver_config->config_dev_cnt, + driver_config->total_dev_cnt); + + if (ret) + kfree(driver_config); + + return ret; +} + +static void __exit +vxge_closer(void) +{ + pci_unregister_driver(&vxge_driver); + kfree(driver_config); +} +module_init(vxge_starter); +module_exit(vxge_closer); diff --git a/trunk/drivers/net/vxge/vxge-main.h b/trunk/drivers/net/vxge/vxge-main.h new file mode 100644 index 000000000000..9704b2bd4320 --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-main.h @@ -0,0 +1,557 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-main.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#ifndef VXGE_MAIN_H +#define VXGE_MAIN_H + +#include "vxge-traffic.h" +#include "vxge-config.h" +#include "vxge-version.h" +#include + +#define VXGE_DRIVER_NAME "vxge" +#define VXGE_DRIVER_VENDOR "Neterion, Inc" +#define VXGE_DRIVER_VERSION_MAJOR 0 + +#define DRV_VERSION VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\ + VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\ + VXGE_VERSION_FOR + +#define PCI_DEVICE_ID_TITAN_WIN 0x5733 +#define PCI_DEVICE_ID_TITAN_UNI 0x5833 +#define VXGE_USE_DEFAULT 0xffffffff +#define VXGE_HW_VPATH_MSIX_ACTIVE 4 +#define VXGE_HW_RXSYNC_FREQ_CNT 4 +#define VXGE_LL_WATCH_DOG_TIMEOUT (15 * HZ) +#define VXGE_LL_RX_COPY_THRESHOLD 256 +#define VXGE_DEF_FIFO_LENGTH 84 + +#define NO_STEERING 0 +#define PORT_STEERING 0x1 +#define RTH_STEERING 0x2 +#define RX_TOS_STEERING 0x3 +#define RX_VLAN_STEERING 0x4 +#define RTH_BUCKET_SIZE 4 + +#define TX_PRIORITY_STEERING 1 +#define TX_VLAN_STEERING 2 +#define TX_PORT_STEERING 3 +#define TX_MULTIQ_STEERING 4 + +#define VXGE_HW_MAC_ADDR_LEARN_DEFAULT VXGE_HW_RTS_MAC_DISABLE + +#define VXGE_TTI_BTIMER_VAL 250000 + +#define VXGE_TTI_LTIMER_VAL 1000 +#define VXGE_TTI_RTIMER_VAL 0 +#define VXGE_RTI_BTIMER_VAL 250 +#define VXGE_RTI_LTIMER_VAL 100 +#define VXGE_RTI_RTIMER_VAL 0 +#define VXGE_FIFO_INDICATE_MAX_PKTS VXGE_DEF_FIFO_LENGTH +#define VXGE_ISR_POLLING_CNT 8 +#define VXGE_MAX_CONFIG_DEV 0xFF +#define VXGE_EXEC_MODE_DISABLE 0 +#define VXGE_EXEC_MODE_ENABLE 1 +#define VXGE_MAX_CONFIG_PORT 1 +#define VXGE_ALL_VID_DISABLE 0 +#define VXGE_ALL_VID_ENABLE 1 +#define VXGE_PAUSE_CTRL_DISABLE 0 +#define VXGE_PAUSE_CTRL_ENABLE 1 + +#define TTI_TX_URANGE_A 5 +#define TTI_TX_URANGE_B 15 +#define TTI_TX_URANGE_C 40 +#define TTI_TX_UFC_A 5 +#define TTI_TX_UFC_B 40 +#define TTI_TX_UFC_C 60 +#define TTI_TX_UFC_D 100 + +#define RTI_RX_URANGE_A 5 +#define RTI_RX_URANGE_B 15 +#define RTI_RX_URANGE_C 40 +#define RTI_RX_UFC_A 1 +#define RTI_RX_UFC_B 5 +#define RTI_RX_UFC_C 10 +#define RTI_RX_UFC_D 15 + +/* Milli secs timer period */ +#define VXGE_TIMER_DELAY 10000 + +#define VXGE_LL_MAX_FRAME_SIZE(dev) ((dev)->mtu + VXGE_HW_MAC_HEADER_MAX_SIZE) + +enum vxge_reset_event { + /* reset events */ + VXGE_LL_VPATH_RESET = 0, + VXGE_LL_DEVICE_RESET = 1, + VXGE_LL_FULL_RESET = 2, + VXGE_LL_START_RESET = 3, + VXGE_LL_COMPL_RESET = 4 +}; +/* These flags represent the devices temporary state */ +enum vxge_device_state_t { +__VXGE_STATE_RESET_CARD = 0, +__VXGE_STATE_CARD_UP +}; + +enum vxge_mac_addr_state { + /* mac address states */ + VXGE_LL_MAC_ADDR_IN_LIST = 0, + VXGE_LL_MAC_ADDR_IN_DA_TABLE = 1 +}; + +struct vxge_drv_config { + int config_dev_cnt; + int total_dev_cnt; + unsigned long inta_dev_open; + int g_no_cpus; + unsigned int vpath_per_dev; +}; + +struct macInfo { + unsigned char macaddr[ETH_ALEN]; + unsigned char macmask[ETH_ALEN]; + unsigned int vpath_no; + enum vxge_mac_addr_state state; +}; + +struct vxge_config { + int tx_pause_enable; + int rx_pause_enable; + +#define NEW_NAPI_WEIGHT 64 + int napi_weight; +#define VXGE_GRO_DONOT_AGGREGATE 0 +#define VXGE_GRO_ALWAYS_AGGREGATE 1 + int gro_enable; + int intr_type; +#define INTA 0 +#define MSI 1 +#define MSI_X 2 + + int addr_learn_en; + + int rth_steering; + int rth_algorithm; + int rth_hash_type_tcpipv4; + int rth_hash_type_ipv4; + int rth_hash_type_tcpipv6; + int rth_hash_type_ipv6; + int rth_hash_type_tcpipv6ex; + int rth_hash_type_ipv6ex; + int rth_bkt_sz; + int rth_jhash_golden_ratio; + int tx_steering_type; + int fifo_indicate_max_pkts; + struct vxge_hw_device_hw_info device_hw_info; +}; + +struct vxge_msix_entry { + /* Mimicing the msix_entry struct of Kernel. */ + u16 vector; + u16 entry; + u16 in_use; + void *arg; +}; + +/* Software Statistics */ + +struct vxge_sw_stats { + /* Network Stats (interface stats) */ + struct net_device_stats net_stats; + + /* Tx */ + u64 tx_frms; + u64 tx_errors; + u64 tx_bytes; + u64 txd_not_free; + u64 txd_out_of_desc; + + /* Virtual Path */ + u64 vpaths_open; + u64 vpath_open_fail; + + /* Rx */ + u64 rx_frms; + u64 rx_errors; + u64 rx_bytes; + u64 rx_mcast; + + /* Misc. */ + u64 link_up; + u64 link_down; + u64 pci_map_fail; + u64 skb_alloc_fail; +}; + +struct vxge_mac_addrs { + struct list_head item; + u64 macaddr; + u64 macmask; + enum vxge_mac_addr_state state; +}; + +struct vxgedev; + +struct vxge_fifo_stats { + u64 tx_frms; + u64 tx_errors; + u64 tx_bytes; + u64 txd_not_free; + u64 txd_out_of_desc; + u64 pci_map_fail; +}; + +struct vxge_fifo { + struct net_device *ndev; + struct pci_dev *pdev; + struct __vxge_hw_fifo *handle; + + /* The vpath id maintained in the driver - + * 0 to 'maximum_vpaths_in_function - 1' + */ + int driver_id; + int tx_steering_type; + int indicate_max_pkts; + spinlock_t tx_lock; + /* flag used to maintain queue state when MULTIQ is not enabled */ +#define VPATH_QUEUE_START 0 +#define VPATH_QUEUE_STOP 1 + int queue_state; + + /* Tx stats */ + struct vxge_fifo_stats stats; +} ____cacheline_aligned; + +struct vxge_ring_stats { + u64 prev_rx_frms; + u64 rx_frms; + u64 rx_errors; + u64 rx_dropped; + u64 rx_bytes; + u64 rx_mcast; + u64 pci_map_fail; + u64 skb_alloc_fail; +}; + +struct vxge_ring { + struct net_device *ndev; + struct pci_dev *pdev; + struct __vxge_hw_ring *handle; + /* The vpath id maintained in the driver - + * 0 to 'maximum_vpaths_in_function - 1' + */ + int driver_id; + + /* copy of the flag indicating whether rx_csum is to be used */ + u32 rx_csum; + + int pkts_processed; + int budget; + int gro_enable; + + struct napi_struct napi; + +#define VXGE_MAX_MAC_ADDR_COUNT 30 + + int vlan_tag_strip; + struct vlan_group *vlgrp; + int rx_vector_no; + enum vxge_hw_status last_status; + + /* Rx stats */ + struct vxge_ring_stats stats; +} ____cacheline_aligned; + +struct vxge_vpath { + + struct vxge_fifo fifo; + struct vxge_ring ring; + + struct __vxge_hw_vpath_handle *handle; + + /* Actual vpath id for this vpath in the device - 0 to 16 */ + int device_id; + int max_mac_addr_cnt; + int is_configured; + int is_open; + struct vxgedev *vdev; + u8 (macaddr)[ETH_ALEN]; + u8 (macmask)[ETH_ALEN]; + +#define VXGE_MAX_LEARN_MAC_ADDR_CNT 2048 + /* mac addresses currently programmed into NIC */ + u16 mac_addr_cnt; + u16 mcast_addr_cnt; + struct list_head mac_addr_list; + + u32 level_err; + u32 level_trace; +}; +#define VXGE_COPY_DEBUG_INFO_TO_LL(vdev, err, trace) { \ + for (i = 0; i < vdev->no_of_vpath; i++) { \ + vdev->vpaths[i].level_err = err; \ + vdev->vpaths[i].level_trace = trace; \ + } \ + vdev->level_err = err; \ + vdev->level_trace = trace; \ +} + +struct vxgedev { + struct net_device *ndev; + struct pci_dev *pdev; + struct __vxge_hw_device *devh; + struct vlan_group *vlgrp; + int vlan_tag_strip; + struct vxge_config config; + unsigned long state; + + /* Indicates which vpath to reset */ + unsigned long vp_reset; + + /* Timer used for polling vpath resets */ + struct timer_list vp_reset_timer; + + /* Timer used for polling vpath lockup */ + struct timer_list vp_lockup_timer; + + /* + * Flags to track whether device is in All Multicast + * or in promiscuous mode. + */ + u16 all_multi_flg; + + /* A flag indicating whether rx_csum is to be used or not. */ + u32 rx_csum; + + struct vxge_msix_entry *vxge_entries; + struct msix_entry *entries; + /* + * 4 for each vpath * 17; + * total is 68 + */ +#define VXGE_MAX_REQUESTED_MSIX 68 +#define VXGE_INTR_STRLEN 80 + char desc[VXGE_MAX_REQUESTED_MSIX][VXGE_INTR_STRLEN]; + + enum vxge_hw_event cric_err_event; + + int max_vpath_supported; + int no_of_vpath; + + struct napi_struct napi; + /* A debug option, when enabled and if error condition occurs, + * the driver will do following steps: + * - mask all interrupts + * - Not clear the source of the alarm + * - gracefully stop all I/O + * A diagnostic dump of register and stats at this point + * reveals very useful information. + */ + int exec_mode; + int max_config_port; + struct vxge_vpath *vpaths; + + struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS]; + void __iomem *bar0; + void __iomem *bar1; + struct vxge_sw_stats stats; + int mtu; + /* Below variables are used for vpath selection to transmit a packet */ + u8 vpath_selector[VXGE_HW_MAX_VIRTUAL_PATHS]; + u64 vpaths_deployed; + + u32 intr_cnt; + u32 level_err; + u32 level_trace; + char fw_version[VXGE_HW_FW_STRLEN]; +}; + +struct vxge_rx_priv { + struct sk_buff *skb; + dma_addr_t data_dma; + dma_addr_t data_size; +}; + +struct vxge_tx_priv { + struct sk_buff *skb; + dma_addr_t dma_buffers[MAX_SKB_FRAGS+1]; +}; + +#define VXGE_MODULE_PARAM_INT(p, val) \ + static int p = val; \ + module_param(p, int, 0) + +#define vxge_os_bug(fmt...) { printk(fmt); BUG(); } + +#define vxge_os_timer(timer, handle, arg, exp) do { \ + init_timer(&timer); \ + timer.function = handle; \ + timer.data = (unsigned long) arg; \ + mod_timer(&timer, (jiffies + exp)); \ + } while (0); + +int __devinit vxge_device_register(struct __vxge_hw_device *devh, + struct vxge_config *config, + int high_dma, int no_of_vpath, + struct vxgedev **vdev); + +void vxge_device_unregister(struct __vxge_hw_device *devh); + +void vxge_vpath_intr_enable(struct vxgedev *vdev, int vp_id); + +void vxge_vpath_intr_disable(struct vxgedev *vdev, int vp_id); + +void vxge_callback_link_up(struct __vxge_hw_device *devh); + +void vxge_callback_link_down(struct __vxge_hw_device *devh); + +enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev, + struct macInfo *mac); + +int vxge_mac_list_del(struct vxge_vpath *vpath, struct macInfo *mac); + +int vxge_reset(struct vxgedev *vdev); + +enum vxge_hw_status +vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr, + u8 t_code, void *userdata); + +enum vxge_hw_status +vxge_xmit_compl(struct __vxge_hw_fifo *fifo_hw, void *dtr, + enum vxge_hw_fifo_tcode t_code, void *userdata, void **skb_ptr); + +int vxge_close(struct net_device *dev); + +int vxge_open(struct net_device *dev); + +void vxge_close_vpaths(struct vxgedev *vdev, int index); + +int vxge_open_vpaths(struct vxgedev *vdev); + +enum vxge_hw_status vxge_reset_all_vpaths(struct vxgedev *vdev); + +void vxge_stop_all_tx_queue(struct vxgedev *vdev); + +void vxge_stop_tx_queue(struct vxge_fifo *fifo); + +void vxge_start_all_tx_queue(struct vxgedev *vdev); + +void vxge_wake_tx_queue(struct vxge_fifo *fifo, struct sk_buff *skb); + +enum vxge_hw_status vxge_add_mac_addr(struct vxgedev *vdev, + struct macInfo *mac); + +enum vxge_hw_status vxge_del_mac_addr(struct vxgedev *vdev, + struct macInfo *mac); + +int vxge_mac_list_add(struct vxge_vpath *vpath, + struct macInfo *mac); + +void vxge_free_mac_add_list(struct vxge_vpath *vpath); + +enum vxge_hw_status vxge_restore_vpath_mac_addr(struct vxge_vpath *vpath); + +enum vxge_hw_status vxge_restore_vpath_vid_table(struct vxge_vpath *vpath); + +int do_vxge_close(struct net_device *dev, int do_io); +extern void initialize_ethtool_ops(struct net_device *ndev); +/** + * #define VXGE_DEBUG_INIT: debug for initialization functions + * #define VXGE_DEBUG_TX : debug transmit related functions + * #define VXGE_DEBUG_RX : debug recevice related functions + * #define VXGE_DEBUG_MEM : debug memory module + * #define VXGE_DEBUG_LOCK: debug locks + * #define VXGE_DEBUG_SEM : debug semaphore + * #define VXGE_DEBUG_ENTRYEXIT: debug functions by adding entry exit statements +*/ +#define VXGE_DEBUG_INIT 0x00000001 +#define VXGE_DEBUG_TX 0x00000002 +#define VXGE_DEBUG_RX 0x00000004 +#define VXGE_DEBUG_MEM 0x00000008 +#define VXGE_DEBUG_LOCK 0x00000010 +#define VXGE_DEBUG_SEM 0x00000020 +#define VXGE_DEBUG_ENTRYEXIT 0x00000040 +#define VXGE_DEBUG_INTR 0x00000080 +#define VXGE_DEBUG_LL_CONFIG 0x00000100 + +/* Debug tracing for VXGE driver */ +#ifndef VXGE_DEBUG_MASK +#define VXGE_DEBUG_MASK 0x0 +#endif + +#if (VXGE_DEBUG_LL_CONFIG & VXGE_DEBUG_MASK) +#define vxge_debug_ll_config(level, fmt, ...) \ + vxge_debug_ll(level, VXGE_DEBUG_LL_CONFIG, fmt, __VA_ARGS__) +#else +#define vxge_debug_ll_config(level, fmt, ...) +#endif + +#if (VXGE_DEBUG_INIT & VXGE_DEBUG_MASK) +#define vxge_debug_init(level, fmt, ...) \ + vxge_debug_ll(level, VXGE_DEBUG_INIT, fmt, __VA_ARGS__) +#else +#define vxge_debug_init(level, fmt, ...) +#endif + +#if (VXGE_DEBUG_TX & VXGE_DEBUG_MASK) +#define vxge_debug_tx(level, fmt, ...) \ + vxge_debug_ll(level, VXGE_DEBUG_TX, fmt, __VA_ARGS__) +#else +#define vxge_debug_tx(level, fmt, ...) +#endif + +#if (VXGE_DEBUG_RX & VXGE_DEBUG_MASK) +#define vxge_debug_rx(level, fmt, ...) \ + vxge_debug_ll(level, VXGE_DEBUG_RX, fmt, __VA_ARGS__) +#else +#define vxge_debug_rx(level, fmt, ...) +#endif + +#if (VXGE_DEBUG_MEM & VXGE_DEBUG_MASK) +#define vxge_debug_mem(level, fmt, ...) \ + vxge_debug_ll(level, VXGE_DEBUG_MEM, fmt, __VA_ARGS__) +#else +#define vxge_debug_mem(level, fmt, ...) +#endif + +#if (VXGE_DEBUG_ENTRYEXIT & VXGE_DEBUG_MASK) +#define vxge_debug_entryexit(level, fmt, ...) \ + vxge_debug_ll(level, VXGE_DEBUG_ENTRYEXIT, fmt, __VA_ARGS__) +#else +#define vxge_debug_entryexit(level, fmt, ...) +#endif + +#if (VXGE_DEBUG_INTR & VXGE_DEBUG_MASK) +#define vxge_debug_intr(level, fmt, ...) \ + vxge_debug_ll(level, VXGE_DEBUG_INTR, fmt, __VA_ARGS__) +#else +#define vxge_debug_intr(level, fmt, ...) +#endif + +#define VXGE_DEVICE_DEBUG_LEVEL_SET(level, mask, vdev) {\ + vxge_hw_device_debug_set((struct __vxge_hw_device *)vdev->devh, \ + level, mask);\ + VXGE_COPY_DEBUG_INFO_TO_LL(vdev, \ + vxge_hw_device_error_level_get((struct __vxge_hw_device *) \ + vdev->devh), \ + vxge_hw_device_trace_level_get((struct __vxge_hw_device *) \ + vdev->devh));\ +} + +#ifdef NETIF_F_GSO +#define vxge_tcp_mss(skb) (skb_shinfo(skb)->gso_size) +#define vxge_udp_mss(skb) (skb_shinfo(skb)->gso_size) +#define vxge_offload_type(skb) (skb_shinfo(skb)->gso_type) +#endif + +#endif diff --git a/trunk/drivers/net/vxge/vxge-reg.h b/trunk/drivers/net/vxge/vxge-reg.h new file mode 100644 index 000000000000..10f4da32929f --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-reg.h @@ -0,0 +1,4608 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-reg.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O Virtualized + * Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#ifndef VXGE_REG_H +#define VXGE_REG_H + +/* + * vxge_mBIT(loc) - set bit at offset + */ +#define vxge_mBIT(loc) (0x8000000000000000ULL >> (loc)) + +/* + * vxge_vBIT(val, loc, sz) - set bits at offset + */ +#define vxge_vBIT(val, loc, sz) (((u64)(val)) << (64-(loc)-(sz))) +#define vxge_vBIT32(val, loc, sz) (((u32)(val)) << (32-(loc)-(sz))) + +/* + * vxge_bVALn(bits, loc, n) - Get the value of n bits at location + */ +#define vxge_bVALn(bits, loc, n) \ + ((((u64)bits) >> (64-(loc+n))) & ((0x1ULL << n) - 1)) + +#define VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(bits) \ + vxge_bVALn(bits, 0, 16) +#define VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(bits) \ + vxge_bVALn(bits, 48, 8) +#define VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(bits) \ + vxge_bVALn(bits, 56, 8) + +#define VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_GET_VPATH_TO_FUNC_MAP_CFG1(bits) \ + vxge_bVALn(bits, 3, 5) +#define VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(bits) \ + vxge_bVALn(bits, 5, 3) +#define VXGE_HW_PF_SW_RESET_COMMAND 0xA5 + +#define VXGE_HW_TITAN_PCICFGMGMT_REG_SPACES 17 +#define VXGE_HW_TITAN_SRPCIM_REG_SPACES 17 +#define VXGE_HW_TITAN_VPMGMT_REG_SPACES 17 +#define VXGE_HW_TITAN_VPATH_REG_SPACES 17 + +#define VXGE_HW_ASIC_MODE_RESERVED 0 +#define VXGE_HW_ASIC_MODE_NO_IOV 1 +#define VXGE_HW_ASIC_MODE_SR_IOV 2 +#define VXGE_HW_ASIC_MODE_MR_IOV 3 + +#define VXGE_HW_TXMAC_GEN_CFG1_TMAC_PERMA_STOP_EN vxge_mBIT(3) +#define VXGE_HW_TXMAC_GEN_CFG1_BLOCK_BCAST_TO_WIRE vxge_mBIT(19) +#define VXGE_HW_TXMAC_GEN_CFG1_BLOCK_BCAST_TO_SWITCH vxge_mBIT(23) +#define VXGE_HW_TXMAC_GEN_CFG1_HOST_APPEND_FCS vxge_mBIT(31) + +#define VXGE_HW_VPATH_IS_FIRST_GET_VPATH_IS_FIRST(bits) vxge_bVALn(bits, 3, 1) + +#define VXGE_HW_TIM_VPATH_ASSIGNMENT_GET_BMAP_ROOT(bits) \ + vxge_bVALn(bits, 0, 32) + +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_GET_MAX_PYLD_LEN(bits) \ + vxge_bVALn(bits, 50, 14) + +#define VXGE_HW_XMAC_VSPORT_CHOICES_VP_GET_VSPORT_VECTOR(bits) \ + vxge_bVALn(bits, 0, 17) + +#define VXGE_HW_XMAC_VPATH_TO_VSPORT_VPMGMT_CLONE_GET_VSPORT_NUMBER(bits) \ + vxge_bVALn(bits, 3, 5) + +#define VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_GET_KDFC_MAX_SIZE(bits) \ + vxge_bVALn(bits, 17, 15) + +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_LEGACY_MODE 0 +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_NON_OFFLOAD_ONLY 1 +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE_MULTI_OP_MODE 2 + +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE_MESSAGES_ONLY 0 +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE_MULTI_OP_MODE 1 + +#define VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val) \ + (val&~VXGE_HW_TOC_KDFC_INITIAL_BIR(7)) +#define VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val) \ + vxge_bVALn(val, 61, 3) +#define VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET(val) \ + (val&~VXGE_HW_TOC_USDC_INITIAL_BIR(7)) +#define VXGE_HW_TOC_GET_USDC_INITIAL_BIR(val) \ + vxge_bVALn(val, 61, 3) + +#define VXGE_HW_TOC_KDFC_VPATH_STRIDE_GET_TOC_KDFC_VPATH_STRIDE(bits) bits +#define VXGE_HW_TOC_KDFC_FIFO_STRIDE_GET_TOC_KDFC_FIFO_STRIDE(bits) bits + +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR0(bits) \ + vxge_bVALn(bits, 1, 15) +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR1(bits) \ + vxge_bVALn(bits, 17, 15) +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_GET_KDFC_RCTR2(bits) \ + vxge_bVALn(bits, 33, 15) + +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_VAPTH_NUM(val) vxge_vBIT(val, 42, 5) +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_FIFO_NUM(val) vxge_vBIT(val, 47, 2) +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_FIFO_OFFSET(val) \ + vxge_vBIT(val, 49, 15) + +#define VXGE_HW_PRC_CFG4_RING_MODE_ONE_BUFFER 0 +#define VXGE_HW_PRC_CFG4_RING_MODE_THREE_BUFFER 1 +#define VXGE_HW_PRC_CFG4_RING_MODE_FIVE_BUFFER 2 + +#define VXGE_HW_PRC_CFG7_SCATTER_MODE_A 0 +#define VXGE_HW_PRC_CFG7_SCATTER_MODE_B 2 +#define VXGE_HW_PRC_CFG7_SCATTER_MODE_C 1 + +#define VXGE_HW_RTS_MGR_STEER_CTRL_WE_READ 0 +#define VXGE_HW_RTS_MGR_STEER_CTRL_WE_WRITE 1 + +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_DA 0 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_VID 1 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_ETYPE 2 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_PN 3 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RANGE_PN 4 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG 5 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT 6 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG 7 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK 8 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY 9 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_QOS 10 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_DS 11 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT 12 +#define VXGE_HW_RTS_MGR_STEER_CTRL_DATA_STRUCT_SEL_FW_VERSION 13 + +#define VXGE_HW_RTS_MGR_STEER_DATA0_GET_DA_MAC_ADDR(bits) \ + vxge_bVALn(bits, 0, 48) +#define VXGE_HW_RTS_MGR_STEER_DATA0_DA_MAC_ADDR(val) vxge_vBIT(val, 0, 48) + +#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_MASK(bits) \ + vxge_bVALn(bits, 0, 48) +#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_MASK(val) vxge_vBIT(val, 0, 48) +#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_ADD_PRIVILEGED_MODE \ + vxge_mBIT(54) +#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_ADD_VPATH(bits) \ + vxge_bVALn(bits, 55, 5) +#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_ADD_VPATH(val) \ + vxge_vBIT(val, 55, 5) +#define VXGE_HW_RTS_MGR_STEER_DATA1_GET_DA_MAC_ADDR_ADD_MODE(bits) \ + vxge_bVALn(bits, 62, 2) +#define VXGE_HW_RTS_MGR_STEER_DATA1_DA_MAC_ADDR_MODE(val) vxge_vBIT(val, 62, 2) + +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY 0 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY 1 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY 2 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY 3 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_ENTRY 0 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_WRITE_ENTRY 1 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_READ_MEMO_ENTRY 3 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LED_CONTROL 4 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ALL_CLEAR 172 + +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA 0 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID 1 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_ETYPE 2 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_PN 3 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_GEN_CFG 5 +#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_SOLO_IT 6 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_JHASH_CFG 7 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MASK 8 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_RTH_KEY 9 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_QOS 10 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DS 11 +#define VXGE_HW_RTS_ACS_STEER_CTRL_DATA_STRUCT_SEL_RTH_MULTI_IT 12 +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_FW_MEMO 13 + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(bits) \ + vxge_bVALn(bits, 0, 48) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(val) vxge_vBIT(val, 0, 48) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(bits) vxge_bVALn(bits, 0, 12) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(val) vxge_vBIT(val, 0, 12) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_ETYPE(bits) vxge_bVALn(bits, 0, 11) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_ETYPE(val) vxge_vBIT(val, 0, 16) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_SRC_DEST_SEL(bits) \ + vxge_bVALn(bits, 3, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_SRC_DEST_SEL vxge_mBIT(3) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_TCP_UDP_SEL(bits) \ + vxge_bVALn(bits, 7, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_TCP_UDP_SEL vxge_mBIT(7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_PN_PORT_NUM(bits) \ + vxge_bVALn(bits, 8, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_PN_PORT_NUM(val) vxge_vBIT(val, 8, 16) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_EN(bits) \ + vxge_bVALn(bits, 3, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_EN vxge_mBIT(3) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_BUCKET_SIZE(bits) \ + vxge_bVALn(bits, 4, 4) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_BUCKET_SIZE(val) \ + vxge_vBIT(val, 4, 4) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ALG_SEL(bits) \ + vxge_bVALn(bits, 10, 2) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL(val) \ + vxge_vBIT(val, 10, 2) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_JENKINS 0 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_MS_RSS 1 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ALG_SEL_CRC32C 2 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV4_EN(bits) \ + vxge_bVALn(bits, 15, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV4_EN vxge_mBIT(15) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV4_EN(bits) \ + vxge_bVALn(bits, 19, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV4_EN vxge_mBIT(19) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV6_EN(bits) \ + vxge_bVALn(bits, 23, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EN vxge_mBIT(23) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV6_EN(bits) \ + vxge_bVALn(bits, 27, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EN vxge_mBIT(27) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_TCP_IPV6_EX_EN(bits) \ + vxge_bVALn(bits, 31, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_TCP_IPV6_EX_EN vxge_mBIT(31) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_RTH_IPV6_EX_EN(bits) \ + vxge_bVALn(bits, 35, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_RTH_IPV6_EX_EN vxge_mBIT(35) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_ACTIVE_TABLE(bits) \ + vxge_bVALn(bits, 39, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_ACTIVE_TABLE vxge_mBIT(39) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_GEN_REPL_ENTRY_EN(bits) \ + vxge_bVALn(bits, 43, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_GEN_REPL_ENTRY_EN vxge_mBIT(43) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_SOLO_IT_ENTRY_EN(bits) \ + vxge_bVALn(bits, 3, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_ENTRY_EN vxge_mBIT(3) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_SOLO_IT_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 9, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_SOLO_IT_BUCKET_DATA(val) \ + vxge_vBIT(val, 9, 7) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_BUCKET_NUM(bits) \ + vxge_bVALn(bits, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_NUM(val) \ + vxge_vBIT(val, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_ENTRY_EN(bits) \ + vxge_bVALn(bits, 8, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_ENTRY_EN vxge_mBIT(8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM0_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 9, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM0_BUCKET_DATA(val) \ + vxge_vBIT(val, 9, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_BUCKET_NUM(bits) \ + vxge_bVALn(bits, 16, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_NUM(val) \ + vxge_vBIT(val, 16, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_ENTRY_EN(bits) \ + vxge_bVALn(bits, 24, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_ENTRY_EN vxge_mBIT(24) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_ITEM1_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 25, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_ITEM1_BUCKET_DATA(val) \ + vxge_vBIT(val, 25, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_BUCKET_NUM(bits) \ + vxge_bVALn(bits, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_NUM(val) \ + vxge_vBIT(val, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_ENTRY_EN(bits) \ + vxge_bVALn(bits, 8, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_ENTRY_EN vxge_mBIT(8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM0_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 9, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM0_BUCKET_DATA(val) \ + vxge_vBIT(val, 9, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_BUCKET_NUM(bits) \ + vxge_bVALn(bits, 16, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_NUM(val) \ + vxge_vBIT(val, 16, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_ENTRY_EN(bits) \ + vxge_bVALn(bits, 24, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_ENTRY_EN vxge_mBIT(24) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM1_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 25, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM1_BUCKET_DATA(val) \ + vxge_vBIT(val, 25, 7) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_JHASH_CFG_GOLDEN_RATIO(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_JHASH_CFG_GOLDEN_RATIO(val) \ + vxge_vBIT(val, 0, 32) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_JHASH_CFG_INIT_VALUE(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_JHASH_CFG_INIT_VALUE(val) \ + vxge_vBIT(val, 32, 32) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV6_SA_MASK(bits) \ + vxge_bVALn(bits, 0, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV6_SA_MASK(val) \ + vxge_vBIT(val, 0, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV6_DA_MASK(bits) \ + vxge_bVALn(bits, 16, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV6_DA_MASK(val) \ + vxge_vBIT(val, 16, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV4_SA_MASK(bits) \ + vxge_bVALn(bits, 32, 4) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV4_SA_MASK(val) \ + vxge_vBIT(val, 32, 4) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_IPV4_DA_MASK(bits) \ + vxge_bVALn(bits, 36, 4) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_IPV4_DA_MASK(val) \ + vxge_vBIT(val, 36, 4) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_L4SP_MASK(bits) \ + vxge_bVALn(bits, 40, 2) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_L4SP_MASK(val) \ + vxge_vBIT(val, 40, 2) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_MASK_L4DP_MASK(bits) \ + vxge_bVALn(bits, 42, 2) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_MASK_L4DP_MASK(val) \ + vxge_vBIT(val, 42, 2) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_RTH_KEY_KEY(bits) \ + vxge_bVALn(bits, 0, 64) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_RTH_KEY_KEY vxge_vBIT(val, 0, 64) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_QOS_ENTRY_EN(bits) \ + vxge_bVALn(bits, 3, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_QOS_ENTRY_EN vxge_mBIT(3) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DS_ENTRY_EN(bits) \ + vxge_bVALn(bits, 3, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DS_ENTRY_EN vxge_mBIT(3) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(bits) \ + vxge_bVALn(bits, 0, 48) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(val) \ + vxge_vBIT(val, 0, 48) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MODE(val) \ + vxge_vBIT(val, 62, 2) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_BUCKET_NUM(bits) \ + vxge_bVALn(bits, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_BUCKET_NUM(val) \ + vxge_vBIT(val, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_ENTRY_EN(bits) \ + vxge_bVALn(bits, 8, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_ENTRY_EN vxge_mBIT(8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM4_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 9, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM4_BUCKET_DATA(val) \ + vxge_vBIT(val, 9, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_BUCKET_NUM(bits) \ + vxge_bVALn(bits, 16, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_BUCKET_NUM(val) \ + vxge_vBIT(val, 16, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_ENTRY_EN(bits) \ + vxge_bVALn(bits, 24, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_ENTRY_EN vxge_mBIT(24) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM5_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 25, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM5_BUCKET_DATA(val) \ + vxge_vBIT(val, 25, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_BUCKET_NUM(bits) \ + vxge_bVALn(bits, 32, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_BUCKET_NUM(val) \ + vxge_vBIT(val, 32, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_ENTRY_EN(bits) \ + vxge_bVALn(bits, 40, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_ENTRY_EN vxge_mBIT(40) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM6_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 41, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM6_BUCKET_DATA(val) \ + vxge_vBIT(val, 41, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_BUCKET_NUM(bits) \ + vxge_bVALn(bits, 48, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_BUCKET_NUM(val) \ + vxge_vBIT(val, 48, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_ENTRY_EN(bits) \ + vxge_bVALn(bits, 56, 1) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_ENTRY_EN vxge_mBIT(56) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_RTH_ITEM7_BUCKET_DATA(bits) \ + vxge_bVALn(bits, 57, 7) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_RTH_ITEM7_BUCKET_DATA(val) \ + vxge_vBIT(val, 57, 7) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PART_NUMBER 0 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_SERIAL_NUMBER 1 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_VERSION 2 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_PCI_MODE 3 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_0 4 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_1 5 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_2 6 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_MEMO_ITEM_DESC_3 7 + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_LED_CONTROL_ON 1 +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_LED_CONTROL_OFF 0 + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_DAY(bits) \ + vxge_bVALn(bits, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_DAY(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MONTH(bits) \ + vxge_bVALn(bits, 8, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MONTH(val) vxge_vBIT(val, 8, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_YEAR(bits) \ + vxge_bVALn(bits, 16, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_YEAR(val) \ + vxge_vBIT(val, 16, 16) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MAJOR(bits) \ + vxge_bVALn(bits, 32, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MAJOR vxge_vBIT(val, 32, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_MINOR(bits) \ + vxge_bVALn(bits, 40, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_MINOR vxge_vBIT(val, 40, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_FW_VER_BUILD(bits) \ + vxge_bVALn(bits, 48, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_FW_VER_BUILD vxge_vBIT(val, 48, 16) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_DAY(bits) \ + vxge_bVALn(bits, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_DAY(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MONTH(bits) \ + vxge_bVALn(bits, 8, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MONTH(val) vxge_vBIT(val, 8, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_YEAR(bits) \ + vxge_bVALn(bits, 16, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_YEAR(val) \ + vxge_vBIT(val, 16, 16) + +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MAJOR(bits) \ + vxge_bVALn(bits, 32, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MAJOR vxge_vBIT(val, 32, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_MINOR(bits) \ + vxge_bVALn(bits, 40, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_MINOR vxge_vBIT(val, 40, 8) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_FLASH_VER_BUILD(bits) \ + vxge_bVALn(bits, 48, 16) +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_FLASH_VER_BUILD vxge_vBIT(val, 48, 16) + +#define VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_GET_PPIF_SRPCIM_TO_VPATH_ALARM(bits)\ + vxge_bVALn(bits, 0, 18) + +#define VXGE_HW_RX_MULTI_CAST_STATS_GET_FRAME_DISCARD(bits) \ + vxge_bVALn(bits, 48, 16) +#define VXGE_HW_RX_FRM_TRANSFERRED_GET_RX_FRM_TRANSFERRED(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_RXD_RETURNED_GET_RXD_RETURNED(bits) vxge_bVALn(bits, 48, 16) +#define VXGE_HW_VPATH_DEBUG_STATS0_GET_INI_NUM_MWR_SENT(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_VPATH_DEBUG_STATS1_GET_INI_NUM_MRD_SENT(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_VPATH_DEBUG_STATS2_GET_INI_NUM_CPL_RCVD(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_VPATH_DEBUG_STATS3_GET_INI_NUM_MWR_BYTE_SENT(bits) (bits) +#define VXGE_HW_VPATH_DEBUG_STATS4_GET_INI_NUM_CPL_BYTE_RCVD(bits) (bits) +#define VXGE_HW_VPATH_DEBUG_STATS5_GET_WRCRDTARB_XOFF(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_VPATH_DEBUG_STATS6_GET_RDCRDTARB_XOFF(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT1(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_VPATH_GENSTATS_COUNT01_GET_PPIF_VPATH_GENSTATS_COUNT0(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT3(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_VPATH_GENSTATS_COUNT23_GET_PPIF_VPATH_GENSTATS_COUNT2(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_VPATH_GENSTATS_COUNT4_GET_PPIF_VPATH_GENSTATS_COUNT4(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_VPATH_GENSTATS_COUNT5_GET_PPIF_VPATH_GENSTATS_COUNT5(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_GET_TX_VP_RESET_DISCARDED_FRMS(bits\ +) vxge_bVALn(bits, 48, 16) +#define VXGE_HW_DBG_STATS_GET_RX_MPA_CRC_FAIL_FRMS(bits) vxge_bVALn(bits, 0, 16) +#define VXGE_HW_DBG_STATS_GET_RX_MPA_MRK_FAIL_FRMS(bits) \ + vxge_bVALn(bits, 16, 16) +#define VXGE_HW_DBG_STATS_GET_RX_MPA_LEN_FAIL_FRMS(bits) \ + vxge_bVALn(bits, 32, 16) +#define VXGE_HW_DBG_STATS_GET_RX_FAU_RX_WOL_FRMS(bits) vxge_bVALn(bits, 0, 16) +#define VXGE_HW_DBG_STATS_GET_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(bits) \ + vxge_bVALn(bits, 16, 16) +#define VXGE_HW_DBG_STATS_GET_RX_FAU_RX_PERMITTED_FRMS(bits) \ + vxge_bVALn(bits, 32, 16) + +#define VXGE_HW_MRPCIM_DEBUG_STATS0_GET_INI_WR_DROP(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_MRPCIM_DEBUG_STATS0_GET_INI_RD_DROP(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_MRPCIM_DEBUG_STATS1_GET_VPLANE_WRCRDTARB_PH_CRDT_DEPLETED(bits\ +) vxge_bVALn(bits, 32, 32) +#define VXGE_HW_MRPCIM_DEBUG_STATS2_GET_VPLANE_WRCRDTARB_PD_CRDT_DEPLETED(bits\ +) vxge_bVALn(bits, 32, 32) +#define \ +VXGE_HW_MRPCIM_DEBUG_STATS3_GET_VPLANE_RDCRDTARB_NPH_CRDT_DEPLETED(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_MRPCIM_DEBUG_STATS4_GET_INI_WR_VPIN_DROP(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_MRPCIM_DEBUG_STATS4_GET_INI_RD_VPIN_DROP(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_GENSTATS_COUNT01_GET_GENSTATS_COUNT1(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_GENSTATS_COUNT01_GET_GENSTATS_COUNT0(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_GENSTATS_COUNT23_GET_GENSTATS_COUNT3(bits) \ + vxge_bVALn(bits, 0, 32) +#define VXGE_HW_GENSTATS_COUNT23_GET_GENSTATS_COUNT2(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_GENSTATS_COUNT4_GET_GENSTATS_COUNT4(bits) \ + vxge_bVALn(bits, 32, 32) +#define VXGE_HW_GENSTATS_COUNT5_GET_GENSTATS_COUNT5(bits) \ + vxge_bVALn(bits, 32, 32) + +#define VXGE_HW_DEBUG_STATS0_GET_RSTDROP_MSG(bits) vxge_bVALn(bits, 0, 32) +#define VXGE_HW_DEBUG_STATS0_GET_RSTDROP_CPL(bits) vxge_bVALn(bits, 32, 32) +#define VXGE_HW_DEBUG_STATS1_GET_RSTDROP_CLIENT0(bits) vxge_bVALn(bits, 0, 32) +#define VXGE_HW_DEBUG_STATS1_GET_RSTDROP_CLIENT1(bits) vxge_bVALn(bits, 32, 32) +#define VXGE_HW_DEBUG_STATS2_GET_RSTDROP_CLIENT2(bits) vxge_bVALn(bits, 0, 32) +#define VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_PH(bits) vxge_bVALn(bits, 0, 16) +#define VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_NPH(bits) vxge_bVALn(bits, 16, 16) +#define VXGE_HW_DEBUG_STATS3_GET_VPLANE_DEPL_CPLH(bits) vxge_bVALn(bits, 32, 16) +#define VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_PD(bits) vxge_bVALn(bits, 0, 16) +#define VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_NPD(bits) bVAL(bits, 16, 16) +#define VXGE_HW_DEBUG_STATS4_GET_VPLANE_DEPL_CPLD(bits) vxge_bVALn(bits, 32, 16) + +#define VXGE_HW_DBG_STATS_TPA_TX_PATH_GET_TX_PERMITTED_FRMS(bits) \ + vxge_bVALn(bits, 32, 32) + +#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT0_TX_ANY_FRMS(bits) \ + vxge_bVALn(bits, 0, 8) +#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT1_TX_ANY_FRMS(bits) \ + vxge_bVALn(bits, 8, 8) +#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_GET_PORT2_TX_ANY_FRMS(bits) \ + vxge_bVALn(bits, 16, 8) + +#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT0_RX_ANY_FRMS(bits) \ + vxge_bVALn(bits, 0, 8) +#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT1_RX_ANY_FRMS(bits) \ + vxge_bVALn(bits, 8, 8) +#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_GET_PORT2_RX_ANY_FRMS(bits) \ + vxge_bVALn(bits, 16, 8) + +#define VXGE_HW_CONFIG_PRIV_H + +#define VXGE_HW_SWAPPER_INITIAL_VALUE 0x0123456789abcdefULL +#define VXGE_HW_SWAPPER_BYTE_SWAPPED 0xefcdab8967452301ULL +#define VXGE_HW_SWAPPER_BIT_FLIPPED 0x80c4a2e691d5b3f7ULL +#define VXGE_HW_SWAPPER_BYTE_SWAPPED_BIT_FLIPPED 0xf7b3d591e6a2c480ULL + +#define VXGE_HW_SWAPPER_READ_BYTE_SWAP_ENABLE 0xFFFFFFFFFFFFFFFFULL +#define VXGE_HW_SWAPPER_READ_BYTE_SWAP_DISABLE 0x0000000000000000ULL + +#define VXGE_HW_SWAPPER_READ_BIT_FLAP_ENABLE 0xFFFFFFFFFFFFFFFFULL +#define VXGE_HW_SWAPPER_READ_BIT_FLAP_DISABLE 0x0000000000000000ULL + +#define VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_ENABLE 0xFFFFFFFFFFFFFFFFULL +#define VXGE_HW_SWAPPER_WRITE_BYTE_SWAP_DISABLE 0x0000000000000000ULL + +#define VXGE_HW_SWAPPER_WRITE_BIT_FLAP_ENABLE 0xFFFFFFFFFFFFFFFFULL +#define VXGE_HW_SWAPPER_WRITE_BIT_FLAP_DISABLE 0x0000000000000000ULL + +/* + * The registers are memory mapped and are native big-endian byte order. The + * little-endian hosts are handled by enabling hardware byte-swapping for + * register and dma operations. + */ +struct vxge_hw_legacy_reg { + + u8 unused00010[0x00010]; + +/*0x00010*/ u64 toc_swapper_fb; +#define VXGE_HW_TOC_SWAPPER_FB_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) +/*0x00018*/ u64 pifm_rd_swap_en; +#define VXGE_HW_PIFM_RD_SWAP_EN_PIFM_RD_SWAP_EN(val) vxge_vBIT(val, 0, 64) +/*0x00020*/ u64 pifm_rd_flip_en; +#define VXGE_HW_PIFM_RD_FLIP_EN_PIFM_RD_FLIP_EN(val) vxge_vBIT(val, 0, 64) +/*0x00028*/ u64 pifm_wr_swap_en; +#define VXGE_HW_PIFM_WR_SWAP_EN_PIFM_WR_SWAP_EN(val) vxge_vBIT(val, 0, 64) +/*0x00030*/ u64 pifm_wr_flip_en; +#define VXGE_HW_PIFM_WR_FLIP_EN_PIFM_WR_FLIP_EN(val) vxge_vBIT(val, 0, 64) +/*0x00038*/ u64 toc_first_pointer; +#define VXGE_HW_TOC_FIRST_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) +/*0x00040*/ u64 host_access_en; +#define VXGE_HW_HOST_ACCESS_EN_HOST_ACCESS_EN(val) vxge_vBIT(val, 0, 64) + +} __packed; + +struct vxge_hw_toc_reg { + + u8 unused00050[0x00050]; + +/*0x00050*/ u64 toc_common_pointer; +#define VXGE_HW_TOC_COMMON_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) +/*0x00058*/ u64 toc_memrepair_pointer; +#define VXGE_HW_TOC_MEMREPAIR_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) +/*0x00060*/ u64 toc_pcicfgmgmt_pointer[17]; +#define VXGE_HW_TOC_PCICFGMGMT_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) + u8 unused001e0[0x001e0-0x000e8]; + +/*0x001e0*/ u64 toc_mrpcim_pointer; +#define VXGE_HW_TOC_MRPCIM_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) +/*0x001e8*/ u64 toc_srpcim_pointer[17]; +#define VXGE_HW_TOC_SRPCIM_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) + u8 unused00278[0x00278-0x00270]; + +/*0x00278*/ u64 toc_vpmgmt_pointer[17]; +#define VXGE_HW_TOC_VPMGMT_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) + u8 unused00390[0x00390-0x00300]; + +/*0x00390*/ u64 toc_vpath_pointer[17]; +#define VXGE_HW_TOC_VPATH_POINTER_INITIAL_VAL(val) vxge_vBIT(val, 0, 64) + u8 unused004a0[0x004a0-0x00418]; + +/*0x004a0*/ u64 toc_kdfc; +#define VXGE_HW_TOC_KDFC_INITIAL_OFFSET(val) vxge_vBIT(val, 0, 61) +#define VXGE_HW_TOC_KDFC_INITIAL_BIR(val) vxge_vBIT(val, 61, 3) +/*0x004a8*/ u64 toc_usdc; +#define VXGE_HW_TOC_USDC_INITIAL_OFFSET(val) vxge_vBIT(val, 0, 61) +#define VXGE_HW_TOC_USDC_INITIAL_BIR(val) vxge_vBIT(val, 61, 3) +/*0x004b0*/ u64 toc_kdfc_vpath_stride; +#define VXGE_HW_TOC_KDFC_VPATH_STRIDE_INITIAL_TOC_KDFC_VPATH_STRIDE(val) \ + vxge_vBIT(val, 0, 64) +/*0x004b8*/ u64 toc_kdfc_fifo_stride; +#define VXGE_HW_TOC_KDFC_FIFO_STRIDE_INITIAL_TOC_KDFC_FIFO_STRIDE(val) \ + vxge_vBIT(val, 0, 64) + +} __packed; + +struct vxge_hw_common_reg { + + u8 unused00a00[0x00a00]; + +/*0x00a00*/ u64 prc_status1; +#define VXGE_HW_PRC_STATUS1_PRC_VP_QUIESCENT(n) vxge_mBIT(n) +/*0x00a08*/ u64 rxdcm_reset_in_progress; +#define VXGE_HW_RXDCM_RESET_IN_PROGRESS_PRC_VP(n) vxge_mBIT(n) +/*0x00a10*/ u64 replicq_flush_in_progress; +#define VXGE_HW_REPLICQ_FLUSH_IN_PROGRESS_NOA_VP(n) vxge_mBIT(n) +/*0x00a18*/ u64 rxpe_cmds_reset_in_progress; +#define VXGE_HW_RXPE_CMDS_RESET_IN_PROGRESS_NOA_VP(n) vxge_mBIT(n) +/*0x00a20*/ u64 mxp_cmds_reset_in_progress; +#define VXGE_HW_MXP_CMDS_RESET_IN_PROGRESS_NOA_VP(n) vxge_mBIT(n) +/*0x00a28*/ u64 noffload_reset_in_progress; +#define VXGE_HW_NOFFLOAD_RESET_IN_PROGRESS_PRC_VP(n) vxge_mBIT(n) +/*0x00a30*/ u64 rd_req_in_progress; +#define VXGE_HW_RD_REQ_IN_PROGRESS_VP(n) vxge_mBIT(n) +/*0x00a38*/ u64 rd_req_outstanding; +#define VXGE_HW_RD_REQ_OUTSTANDING_VP(n) vxge_mBIT(n) +/*0x00a40*/ u64 kdfc_reset_in_progress; +#define VXGE_HW_KDFC_RESET_IN_PROGRESS_NOA_VP(n) vxge_mBIT(n) + u8 unused00b00[0x00b00-0x00a48]; + +/*0x00b00*/ u64 one_cfg_vp; +#define VXGE_HW_ONE_CFG_VP_RDY(n) vxge_mBIT(n) +/*0x00b08*/ u64 one_common; +#define VXGE_HW_ONE_COMMON_PET_VPATH_RESET_IN_PROGRESS(n) vxge_mBIT(n) + u8 unused00b80[0x00b80-0x00b10]; + +/*0x00b80*/ u64 tim_int_en; +#define VXGE_HW_TIM_INT_EN_TIM_VP(n) vxge_mBIT(n) +/*0x00b88*/ u64 tim_set_int_en; +#define VXGE_HW_TIM_SET_INT_EN_VP(n) vxge_mBIT(n) +/*0x00b90*/ u64 tim_clr_int_en; +#define VXGE_HW_TIM_CLR_INT_EN_VP(n) vxge_mBIT(n) +/*0x00b98*/ u64 tim_mask_int_during_reset; +#define VXGE_HW_TIM_MASK_INT_DURING_RESET_VPATH(n) vxge_mBIT(n) +/*0x00ba0*/ u64 tim_reset_in_progress; +#define VXGE_HW_TIM_RESET_IN_PROGRESS_TIM_VPATH(n) vxge_mBIT(n) +/*0x00ba8*/ u64 tim_outstanding_bmap; +#define VXGE_HW_TIM_OUTSTANDING_BMAP_TIM_VPATH(n) vxge_mBIT(n) + u8 unused00c00[0x00c00-0x00bb0]; + +/*0x00c00*/ u64 msg_reset_in_progress; +#define VXGE_HW_MSG_RESET_IN_PROGRESS_MSG_COMPOSITE(val) vxge_vBIT(val, 0, 17) +/*0x00c08*/ u64 msg_mxp_mr_ready; +#define VXGE_HW_MSG_MXP_MR_READY_MP_BOOTED(n) vxge_mBIT(n) +/*0x00c10*/ u64 msg_uxp_mr_ready; +#define VXGE_HW_MSG_UXP_MR_READY_UP_BOOTED(n) vxge_mBIT(n) +/*0x00c18*/ u64 msg_dmq_noni_rtl_prefetch; +#define VXGE_HW_MSG_DMQ_NONI_RTL_PREFETCH_BYPASS_ENABLE(n) vxge_mBIT(n) +/*0x00c20*/ u64 msg_umq_rtl_bwr; +#define VXGE_HW_MSG_UMQ_RTL_BWR_PREFETCH_DISABLE(n) vxge_mBIT(n) + u8 unused00d00[0x00d00-0x00c28]; + +/*0x00d00*/ u64 cmn_rsthdlr_cfg0; +#define VXGE_HW_CMN_RSTHDLR_CFG0_SW_RESET_VPATH(val) vxge_vBIT(val, 0, 17) +/*0x00d08*/ u64 cmn_rsthdlr_cfg1; +#define VXGE_HW_CMN_RSTHDLR_CFG1_CLR_VPATH_RESET(val) vxge_vBIT(val, 0, 17) +/*0x00d10*/ u64 cmn_rsthdlr_cfg2; +#define VXGE_HW_CMN_RSTHDLR_CFG2_SW_RESET_FIFO0(val) vxge_vBIT(val, 0, 17) +/*0x00d18*/ u64 cmn_rsthdlr_cfg3; +#define VXGE_HW_CMN_RSTHDLR_CFG3_SW_RESET_FIFO1(val) vxge_vBIT(val, 0, 17) +/*0x00d20*/ u64 cmn_rsthdlr_cfg4; +#define VXGE_HW_CMN_RSTHDLR_CFG4_SW_RESET_FIFO2(val) vxge_vBIT(val, 0, 17) + u8 unused00d40[0x00d40-0x00d28]; + +/*0x00d40*/ u64 cmn_rsthdlr_cfg8; +#define VXGE_HW_CMN_RSTHDLR_CFG8_INCR_VPATH_INST_NUM(val) vxge_vBIT(val, 0, 17) +/*0x00d48*/ u64 stats_cfg0; +#define VXGE_HW_STATS_CFG0_STATS_ENABLE(val) vxge_vBIT(val, 0, 17) + u8 unused00da8[0x00da8-0x00d50]; + +/*0x00da8*/ u64 clear_msix_mask_vect[4]; +#define VXGE_HW_CLEAR_MSIX_MASK_VECT_CLEAR_MSIX_MASK_VECT(val) \ + vxge_vBIT(val, 0, 17) +/*0x00dc8*/ u64 set_msix_mask_vect[4]; +#define VXGE_HW_SET_MSIX_MASK_VECT_SET_MSIX_MASK_VECT(val) vxge_vBIT(val, 0, 17) +/*0x00de8*/ u64 clear_msix_mask_all_vect; +#define VXGE_HW_CLEAR_MSIX_MASK_ALL_VECT_CLEAR_MSIX_MASK_ALL_VECT(val) \ + vxge_vBIT(val, 0, 17) +/*0x00df0*/ u64 set_msix_mask_all_vect; +#define VXGE_HW_SET_MSIX_MASK_ALL_VECT_SET_MSIX_MASK_ALL_VECT(val) \ + vxge_vBIT(val, 0, 17) +/*0x00df8*/ u64 mask_vector[4]; +#define VXGE_HW_MASK_VECTOR_MASK_VECTOR(val) vxge_vBIT(val, 0, 17) +/*0x00e18*/ u64 msix_pending_vector[4]; +#define VXGE_HW_MSIX_PENDING_VECTOR_MSIX_PENDING_VECTOR(val) \ + vxge_vBIT(val, 0, 17) +/*0x00e38*/ u64 clr_msix_one_shot_vec[4]; +#define VXGE_HW_CLR_MSIX_ONE_SHOT_VEC_CLR_MSIX_ONE_SHOT_VEC(val) \ + vxge_vBIT(val, 0, 17) +/*0x00e58*/ u64 titan_asic_id; +#define VXGE_HW_TITAN_ASIC_ID_INITIAL_DEVICE_ID(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_TITAN_ASIC_ID_INITIAL_MAJOR_REVISION(val) vxge_vBIT(val, 48, 8) +#define VXGE_HW_TITAN_ASIC_ID_INITIAL_MINOR_REVISION(val) vxge_vBIT(val, 56, 8) +/*0x00e60*/ u64 titan_general_int_status; +#define VXGE_HW_TITAN_GENERAL_INT_STATUS_MRPCIM_ALARM_INT vxge_mBIT(0) +#define VXGE_HW_TITAN_GENERAL_INT_STATUS_SRPCIM_ALARM_INT vxge_mBIT(1) +#define VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_ALARM_INT vxge_mBIT(2) +#define VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(val) \ + vxge_vBIT(val, 3, 17) + u8 unused00e70[0x00e70-0x00e68]; + +/*0x00e70*/ u64 titan_mask_all_int; +#define VXGE_HW_TITAN_MASK_ALL_INT_ALARM vxge_mBIT(7) +#define VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC vxge_mBIT(15) + u8 unused00e80[0x00e80-0x00e78]; + +/*0x00e80*/ u64 tim_int_status0; +#define VXGE_HW_TIM_INT_STATUS0_TIM_INT_STATUS0(val) vxge_vBIT(val, 0, 64) +/*0x00e88*/ u64 tim_int_mask0; +#define VXGE_HW_TIM_INT_MASK0_TIM_INT_MASK0(val) vxge_vBIT(val, 0, 64) +/*0x00e90*/ u64 tim_int_status1; +#define VXGE_HW_TIM_INT_STATUS1_TIM_INT_STATUS1(val) vxge_vBIT(val, 0, 4) +/*0x00e98*/ u64 tim_int_mask1; +#define VXGE_HW_TIM_INT_MASK1_TIM_INT_MASK1(val) vxge_vBIT(val, 0, 4) +/*0x00ea0*/ u64 rti_int_status; +#define VXGE_HW_RTI_INT_STATUS_RTI_INT_STATUS(val) vxge_vBIT(val, 0, 17) +/*0x00ea8*/ u64 rti_int_mask; +#define VXGE_HW_RTI_INT_MASK_RTI_INT_MASK(val) vxge_vBIT(val, 0, 17) +/*0x00eb0*/ u64 adapter_status; +#define VXGE_HW_ADAPTER_STATUS_RTDMA_RTDMA_READY vxge_mBIT(0) +#define VXGE_HW_ADAPTER_STATUS_WRDMA_WRDMA_READY vxge_mBIT(1) +#define VXGE_HW_ADAPTER_STATUS_KDFC_KDFC_READY vxge_mBIT(2) +#define VXGE_HW_ADAPTER_STATUS_TPA_TMAC_BUF_EMPTY vxge_mBIT(3) +#define VXGE_HW_ADAPTER_STATUS_RDCTL_PIC_QUIESCENT vxge_mBIT(4) +#define VXGE_HW_ADAPTER_STATUS_XGMAC_NETWORK_FAULT vxge_mBIT(5) +#define VXGE_HW_ADAPTER_STATUS_ROCRC_OFFLOAD_QUIESCENT vxge_mBIT(6) +#define VXGE_HW_ADAPTER_STATUS_G3IF_FB_G3IF_FB_GDDR3_READY vxge_mBIT(7) +#define VXGE_HW_ADAPTER_STATUS_G3IF_CM_G3IF_CM_GDDR3_READY vxge_mBIT(8) +#define VXGE_HW_ADAPTER_STATUS_RIC_RIC_RUNNING vxge_mBIT(9) +#define VXGE_HW_ADAPTER_STATUS_CMG_C_PLL_IN_LOCK vxge_mBIT(10) +#define VXGE_HW_ADAPTER_STATUS_XGMAC_X_PLL_IN_LOCK vxge_mBIT(11) +#define VXGE_HW_ADAPTER_STATUS_FBIF_M_PLL_IN_LOCK vxge_mBIT(12) +#define VXGE_HW_ADAPTER_STATUS_PCC_PCC_IDLE(val) vxge_vBIT(val, 24, 8) +#define VXGE_HW_ADAPTER_STATUS_ROCRC_RC_PRC_QUIESCENT(val) vxge_vBIT(val, 44, 8) +/*0x00eb8*/ u64 gen_ctrl; +#define VXGE_HW_GEN_CTRL_SPI_MRPCIM_WR_DIS vxge_mBIT(0) +#define VXGE_HW_GEN_CTRL_SPI_MRPCIM_RD_DIS vxge_mBIT(1) +#define VXGE_HW_GEN_CTRL_SPI_SRPCIM_WR_DIS vxge_mBIT(2) +#define VXGE_HW_GEN_CTRL_SPI_SRPCIM_RD_DIS vxge_mBIT(3) +#define VXGE_HW_GEN_CTRL_SPI_DEBUG_DIS vxge_mBIT(4) +#define VXGE_HW_GEN_CTRL_SPI_APP_LTSSM_TIMER_DIS vxge_mBIT(5) +#define VXGE_HW_GEN_CTRL_SPI_NOT_USED(val) vxge_vBIT(val, 6, 4) + u8 unused00ed0[0x00ed0-0x00ec0]; + +/*0x00ed0*/ u64 adapter_ready; +#define VXGE_HW_ADAPTER_READY_ADAPTER_READY vxge_mBIT(63) +/*0x00ed8*/ u64 outstanding_read; +#define VXGE_HW_OUTSTANDING_READ_OUTSTANDING_READ(val) vxge_vBIT(val, 0, 17) +/*0x00ee0*/ u64 vpath_rst_in_prog; +#define VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(val) vxge_vBIT(val, 0, 17) +/*0x00ee8*/ u64 vpath_reg_modified; +#define VXGE_HW_VPATH_REG_MODIFIED_VPATH_REG_MODIFIED(val) vxge_vBIT(val, 0, 17) + u8 unused00fc0[0x00fc0-0x00ef0]; + +/*0x00fc0*/ u64 cp_reset_in_progress; +#define VXGE_HW_CP_RESET_IN_PROGRESS_CP_VPATH(n) vxge_mBIT(n) + u8 unused01080[0x01080-0x00fc8]; + +/*0x01080*/ u64 xgmac_ready; +#define VXGE_HW_XGMAC_READY_XMACJ_READY(val) vxge_vBIT(val, 0, 17) + u8 unused010c0[0x010c0-0x01088]; + +/*0x010c0*/ u64 fbif_ready; +#define VXGE_HW_FBIF_READY_FAU_READY(val) vxge_vBIT(val, 0, 17) + u8 unused01100[0x01100-0x010c8]; + +/*0x01100*/ u64 vplane_assignments; +#define VXGE_HW_VPLANE_ASSIGNMENTS_VPLANE_ASSIGNMENTS(val) vxge_vBIT(val, 3, 5) +/*0x01108*/ u64 vpath_assignments; +#define VXGE_HW_VPATH_ASSIGNMENTS_VPATH_ASSIGNMENTS(val) vxge_vBIT(val, 0, 17) +/*0x01110*/ u64 resource_assignments; +#define VXGE_HW_RESOURCE_ASSIGNMENTS_RESOURCE_ASSIGNMENTS(val) \ + vxge_vBIT(val, 0, 17) +/*0x01118*/ u64 host_type_assignments; +#define VXGE_HW_HOST_TYPE_ASSIGNMENTS_HOST_TYPE_ASSIGNMENTS(val) \ + vxge_vBIT(val, 5, 3) + u8 unused01128[0x01128-0x01120]; + +/*0x01128*/ u64 max_resource_assignments; +#define VXGE_HW_MAX_RESOURCE_ASSIGNMENTS_PCI_MAX_VPLANE(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_MAX_RESOURCE_ASSIGNMENTS_PCI_MAX_VPATHS(val) \ + vxge_vBIT(val, 11, 5) +/*0x01130*/ u64 pf_vpath_assignments; +#define VXGE_HW_PF_VPATH_ASSIGNMENTS_PF_VPATH_ASSIGNMENTS(val) \ + vxge_vBIT(val, 0, 17) + u8 unused01200[0x01200-0x01138]; + +/*0x01200*/ u64 rts_access_icmp; +#define VXGE_HW_RTS_ACCESS_ICMP_EN(val) vxge_vBIT(val, 0, 17) +/*0x01208*/ u64 rts_access_tcpsyn; +#define VXGE_HW_RTS_ACCESS_TCPSYN_EN(val) vxge_vBIT(val, 0, 17) +/*0x01210*/ u64 rts_access_zl4pyld; +#define VXGE_HW_RTS_ACCESS_ZL4PYLD_EN(val) vxge_vBIT(val, 0, 17) +/*0x01218*/ u64 rts_access_l4prtcl_tcp; +#define VXGE_HW_RTS_ACCESS_L4PRTCL_TCP_EN(val) vxge_vBIT(val, 0, 17) +/*0x01220*/ u64 rts_access_l4prtcl_udp; +#define VXGE_HW_RTS_ACCESS_L4PRTCL_UDP_EN(val) vxge_vBIT(val, 0, 17) +/*0x01228*/ u64 rts_access_l4prtcl_flex; +#define VXGE_HW_RTS_ACCESS_L4PRTCL_FLEX_EN(val) vxge_vBIT(val, 0, 17) +/*0x01230*/ u64 rts_access_ipfrag; +#define VXGE_HW_RTS_ACCESS_IPFRAG_EN(val) vxge_vBIT(val, 0, 17) + +} __packed; + +struct vxge_hw_memrepair_reg { + u64 unused1; + u64 unused2; +} __packed; + +struct vxge_hw_pcicfgmgmt_reg { + +/*0x00000*/ u64 resource_no; +#define VXGE_HW_RESOURCE_NO_PFN_OR_VF BIT(3) +/*0x00008*/ u64 bargrp_pf_or_vf_bar0_mask; +#define VXGE_HW_BARGRP_PF_OR_VF_BAR0_MASK_BARGRP_PF_OR_VF_BAR0_MASK(val) \ + vxge_vBIT(val, 2, 6) +/*0x00010*/ u64 bargrp_pf_or_vf_bar1_mask; +#define VXGE_HW_BARGRP_PF_OR_VF_BAR1_MASK_BARGRP_PF_OR_VF_BAR1_MASK(val) \ + vxge_vBIT(val, 2, 6) +/*0x00018*/ u64 bargrp_pf_or_vf_bar2_mask; +#define VXGE_HW_BARGRP_PF_OR_VF_BAR2_MASK_BARGRP_PF_OR_VF_BAR2_MASK(val) \ + vxge_vBIT(val, 2, 6) +/*0x00020*/ u64 msixgrp_no; +#define VXGE_HW_MSIXGRP_NO_TABLE_SIZE(val) vxge_vBIT(val, 5, 11) + +} __packed; + +struct vxge_hw_mrpcim_reg { +/*0x00000*/ u64 g3fbct_int_status; +#define VXGE_HW_G3FBCT_INT_STATUS_ERR_G3IF_INT vxge_mBIT(0) +/*0x00008*/ u64 g3fbct_int_mask; +/*0x00010*/ u64 g3fbct_err_reg; +#define VXGE_HW_G3FBCT_ERR_REG_G3IF_SM_ERR vxge_mBIT(4) +#define VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_DECC vxge_mBIT(5) +#define VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_U_DECC vxge_mBIT(6) +#define VXGE_HW_G3FBCT_ERR_REG_G3IF_CTRL_FIFO_DECC vxge_mBIT(7) +#define VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_SECC vxge_mBIT(29) +#define VXGE_HW_G3FBCT_ERR_REG_G3IF_GDDR3_U_SECC vxge_mBIT(30) +#define VXGE_HW_G3FBCT_ERR_REG_G3IF_CTRL_FIFO_SECC vxge_mBIT(31) +/*0x00018*/ u64 g3fbct_err_mask; +/*0x00020*/ u64 g3fbct_err_alarm; + + u8 unused00a00[0x00a00-0x00028]; + +/*0x00a00*/ u64 wrdma_int_status; +#define VXGE_HW_WRDMA_INT_STATUS_RC_ALARM_RC_INT vxge_mBIT(0) +#define VXGE_HW_WRDMA_INT_STATUS_RXDRM_SM_ERR_RXDRM_INT vxge_mBIT(1) +#define VXGE_HW_WRDMA_INT_STATUS_RXDCM_SM_ERR_RXDCM_SM_INT vxge_mBIT(2) +#define VXGE_HW_WRDMA_INT_STATUS_RXDWM_SM_ERR_RXDWM_INT vxge_mBIT(3) +#define VXGE_HW_WRDMA_INT_STATUS_RDA_ERR_RDA_INT vxge_mBIT(6) +#define VXGE_HW_WRDMA_INT_STATUS_RDA_ECC_DB_RDA_ECC_DB_INT vxge_mBIT(8) +#define VXGE_HW_WRDMA_INT_STATUS_RDA_ECC_SG_RDA_ECC_SG_INT vxge_mBIT(9) +#define VXGE_HW_WRDMA_INT_STATUS_FRF_ALARM_FRF_INT vxge_mBIT(12) +#define VXGE_HW_WRDMA_INT_STATUS_ROCRC_ALARM_ROCRC_INT vxge_mBIT(13) +#define VXGE_HW_WRDMA_INT_STATUS_WDE0_ALARM_WDE0_INT vxge_mBIT(14) +#define VXGE_HW_WRDMA_INT_STATUS_WDE1_ALARM_WDE1_INT vxge_mBIT(15) +#define VXGE_HW_WRDMA_INT_STATUS_WDE2_ALARM_WDE2_INT vxge_mBIT(16) +#define VXGE_HW_WRDMA_INT_STATUS_WDE3_ALARM_WDE3_INT vxge_mBIT(17) +/*0x00a08*/ u64 wrdma_int_mask; +/*0x00a10*/ u64 rc_alarm_reg; +#define VXGE_HW_RC_ALARM_REG_FTC_SM_ERR vxge_mBIT(0) +#define VXGE_HW_RC_ALARM_REG_FTC_SM_PHASE_ERR vxge_mBIT(1) +#define VXGE_HW_RC_ALARM_REG_BTDWM_SM_ERR vxge_mBIT(2) +#define VXGE_HW_RC_ALARM_REG_BTC_SM_ERR vxge_mBIT(3) +#define VXGE_HW_RC_ALARM_REG_BTDCM_SM_ERR vxge_mBIT(4) +#define VXGE_HW_RC_ALARM_REG_BTDRM_SM_ERR vxge_mBIT(5) +#define VXGE_HW_RC_ALARM_REG_RMM_RXD_RC_ECC_DB_ERR vxge_mBIT(6) +#define VXGE_HW_RC_ALARM_REG_RMM_RXD_RC_ECC_SG_ERR vxge_mBIT(7) +#define VXGE_HW_RC_ALARM_REG_RHS_RXD_RHS_ECC_DB_ERR vxge_mBIT(8) +#define VXGE_HW_RC_ALARM_REG_RHS_RXD_RHS_ECC_SG_ERR vxge_mBIT(9) +#define VXGE_HW_RC_ALARM_REG_RMM_SM_ERR vxge_mBIT(10) +#define VXGE_HW_RC_ALARM_REG_BTC_VPATH_MISMATCH_ERR vxge_mBIT(12) +/*0x00a18*/ u64 rc_alarm_mask; +/*0x00a20*/ u64 rc_alarm_alarm; +/*0x00a28*/ u64 rxdrm_sm_err_reg; +#define VXGE_HW_RXDRM_SM_ERR_REG_PRC_VP(n) vxge_mBIT(n) +/*0x00a30*/ u64 rxdrm_sm_err_mask; +/*0x00a38*/ u64 rxdrm_sm_err_alarm; +/*0x00a40*/ u64 rxdcm_sm_err_reg; +#define VXGE_HW_RXDCM_SM_ERR_REG_PRC_VP(n) vxge_mBIT(n) +/*0x00a48*/ u64 rxdcm_sm_err_mask; +/*0x00a50*/ u64 rxdcm_sm_err_alarm; +/*0x00a58*/ u64 rxdwm_sm_err_reg; +#define VXGE_HW_RXDWM_SM_ERR_REG_PRC_VP(n) vxge_mBIT(n) +/*0x00a60*/ u64 rxdwm_sm_err_mask; +/*0x00a68*/ u64 rxdwm_sm_err_alarm; +/*0x00a70*/ u64 rda_err_reg; +#define VXGE_HW_RDA_ERR_REG_RDA_SM0_ERR_ALARM vxge_mBIT(0) +#define VXGE_HW_RDA_ERR_REG_RDA_MISC_ERR vxge_mBIT(1) +#define VXGE_HW_RDA_ERR_REG_RDA_PCIX_ERR vxge_mBIT(2) +#define VXGE_HW_RDA_ERR_REG_RDA_RXD_ECC_DB_ERR vxge_mBIT(3) +#define VXGE_HW_RDA_ERR_REG_RDA_FRM_ECC_DB_ERR vxge_mBIT(4) +#define VXGE_HW_RDA_ERR_REG_RDA_UQM_ECC_DB_ERR vxge_mBIT(5) +#define VXGE_HW_RDA_ERR_REG_RDA_IMM_ECC_DB_ERR vxge_mBIT(6) +#define VXGE_HW_RDA_ERR_REG_RDA_TIM_ECC_DB_ERR vxge_mBIT(7) +/*0x00a78*/ u64 rda_err_mask; +/*0x00a80*/ u64 rda_err_alarm; +/*0x00a88*/ u64 rda_ecc_db_reg; +#define VXGE_HW_RDA_ECC_DB_REG_RDA_RXD_ERR(n) vxge_mBIT(n) +/*0x00a90*/ u64 rda_ecc_db_mask; +/*0x00a98*/ u64 rda_ecc_db_alarm; +/*0x00aa0*/ u64 rda_ecc_sg_reg; +#define VXGE_HW_RDA_ECC_SG_REG_RDA_RXD_ERR(n) vxge_mBIT(n) +/*0x00aa8*/ u64 rda_ecc_sg_mask; +/*0x00ab0*/ u64 rda_ecc_sg_alarm; +/*0x00ab8*/ u64 rqa_err_reg; +#define VXGE_HW_RQA_ERR_REG_RQA_SM_ERR_ALARM vxge_mBIT(0) +/*0x00ac0*/ u64 rqa_err_mask; +/*0x00ac8*/ u64 rqa_err_alarm; +/*0x00ad0*/ u64 frf_alarm_reg; +#define VXGE_HW_FRF_ALARM_REG_PRC_VP_FRF_SM_ERR(n) vxge_mBIT(n) +/*0x00ad8*/ u64 frf_alarm_mask; +/*0x00ae0*/ u64 frf_alarm_alarm; +/*0x00ae8*/ u64 rocrc_alarm_reg; +#define VXGE_HW_ROCRC_ALARM_REG_QCQ_QCC_BYP_ECC_DB vxge_mBIT(0) +#define VXGE_HW_ROCRC_ALARM_REG_QCQ_QCC_BYP_ECC_SG vxge_mBIT(1) +#define VXGE_HW_ROCRC_ALARM_REG_NOA_NMA_SM_ERR vxge_mBIT(2) +#define VXGE_HW_ROCRC_ALARM_REG_NOA_IMMM_ECC_DB vxge_mBIT(3) +#define VXGE_HW_ROCRC_ALARM_REG_NOA_IMMM_ECC_SG vxge_mBIT(4) +#define VXGE_HW_ROCRC_ALARM_REG_UDQ_UMQM_ECC_DB vxge_mBIT(5) +#define VXGE_HW_ROCRC_ALARM_REG_UDQ_UMQM_ECC_SG vxge_mBIT(6) +#define VXGE_HW_ROCRC_ALARM_REG_NOA_RCBM_ECC_DB vxge_mBIT(11) +#define VXGE_HW_ROCRC_ALARM_REG_NOA_RCBM_ECC_SG vxge_mBIT(12) +#define VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_EGB_RSVD_ERR vxge_mBIT(13) +#define VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_EGB_OWN_ERR vxge_mBIT(14) +#define VXGE_HW_ROCRC_ALARM_REG_QCQ_MULTI_BYP_OWN_ERR vxge_mBIT(15) +#define VXGE_HW_ROCRC_ALARM_REG_QCQ_OWN_NOT_ASSIGNED_ERR vxge_mBIT(16) +#define VXGE_HW_ROCRC_ALARM_REG_QCQ_OWN_RSVD_SYNC_ERR vxge_mBIT(17) +#define VXGE_HW_ROCRC_ALARM_REG_QCQ_LOST_EGB_ERR vxge_mBIT(18) +#define VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ0_OVERFLOW vxge_mBIT(19) +#define VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ1_OVERFLOW vxge_mBIT(20) +#define VXGE_HW_ROCRC_ALARM_REG_RCQ_BYPQ2_OVERFLOW vxge_mBIT(21) +#define VXGE_HW_ROCRC_ALARM_REG_NOA_WCT_CMD_FIFO_ERR vxge_mBIT(22) +/*0x00af0*/ u64 rocrc_alarm_mask; +/*0x00af8*/ u64 rocrc_alarm_alarm; +/*0x00b00*/ u64 wde0_alarm_reg; +#define VXGE_HW_WDE0_ALARM_REG_WDE0_DCC_SM_ERR vxge_mBIT(0) +#define VXGE_HW_WDE0_ALARM_REG_WDE0_PRM_SM_ERR vxge_mBIT(1) +#define VXGE_HW_WDE0_ALARM_REG_WDE0_CP_SM_ERR vxge_mBIT(2) +#define VXGE_HW_WDE0_ALARM_REG_WDE0_CP_CMD_ERR vxge_mBIT(3) +#define VXGE_HW_WDE0_ALARM_REG_WDE0_PCR_SM_ERR vxge_mBIT(4) +/*0x00b08*/ u64 wde0_alarm_mask; +/*0x00b10*/ u64 wde0_alarm_alarm; +/*0x00b18*/ u64 wde1_alarm_reg; +#define VXGE_HW_WDE1_ALARM_REG_WDE1_DCC_SM_ERR vxge_mBIT(0) +#define VXGE_HW_WDE1_ALARM_REG_WDE1_PRM_SM_ERR vxge_mBIT(1) +#define VXGE_HW_WDE1_ALARM_REG_WDE1_CP_SM_ERR vxge_mBIT(2) +#define VXGE_HW_WDE1_ALARM_REG_WDE1_CP_CMD_ERR vxge_mBIT(3) +#define VXGE_HW_WDE1_ALARM_REG_WDE1_PCR_SM_ERR vxge_mBIT(4) +/*0x00b20*/ u64 wde1_alarm_mask; +/*0x00b28*/ u64 wde1_alarm_alarm; +/*0x00b30*/ u64 wde2_alarm_reg; +#define VXGE_HW_WDE2_ALARM_REG_WDE2_DCC_SM_ERR vxge_mBIT(0) +#define VXGE_HW_WDE2_ALARM_REG_WDE2_PRM_SM_ERR vxge_mBIT(1) +#define VXGE_HW_WDE2_ALARM_REG_WDE2_CP_SM_ERR vxge_mBIT(2) +#define VXGE_HW_WDE2_ALARM_REG_WDE2_CP_CMD_ERR vxge_mBIT(3) +#define VXGE_HW_WDE2_ALARM_REG_WDE2_PCR_SM_ERR vxge_mBIT(4) +/*0x00b38*/ u64 wde2_alarm_mask; +/*0x00b40*/ u64 wde2_alarm_alarm; +/*0x00b48*/ u64 wde3_alarm_reg; +#define VXGE_HW_WDE3_ALARM_REG_WDE3_DCC_SM_ERR vxge_mBIT(0) +#define VXGE_HW_WDE3_ALARM_REG_WDE3_PRM_SM_ERR vxge_mBIT(1) +#define VXGE_HW_WDE3_ALARM_REG_WDE3_CP_SM_ERR vxge_mBIT(2) +#define VXGE_HW_WDE3_ALARM_REG_WDE3_CP_CMD_ERR vxge_mBIT(3) +#define VXGE_HW_WDE3_ALARM_REG_WDE3_PCR_SM_ERR vxge_mBIT(4) +/*0x00b50*/ u64 wde3_alarm_mask; +/*0x00b58*/ u64 wde3_alarm_alarm; + + u8 unused00be8[0x00be8-0x00b60]; + +/*0x00be8*/ u64 rx_w_round_robin_0; +#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2(val) vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3(val) vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4(val) vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5(val) vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6(val) vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7(val) vxge_vBIT(val, 59, 5) +/*0x00bf0*/ u64 rx_w_round_robin_1; +#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_8(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_9(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_10(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_11(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_12(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_13(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_14(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_1_RX_W_PRIORITY_SS_15(val) \ + vxge_vBIT(val, 59, 5) +/*0x00bf8*/ u64 rx_w_round_robin_2; +#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_16(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_17(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_18(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_19(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_20(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_21(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_22(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_2_RX_W_PRIORITY_SS_23(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c00*/ u64 rx_w_round_robin_3; +#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_24(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_25(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_26(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_27(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_28(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_29(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_30(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_3_RX_W_PRIORITY_SS_31(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c08*/ u64 rx_w_round_robin_4; +#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_32(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_33(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_34(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_35(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_36(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_37(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_38(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_4_RX_W_PRIORITY_SS_39(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c10*/ u64 rx_w_round_robin_5; +#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_40(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_41(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_42(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_43(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_44(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_45(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_46(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_5_RX_W_PRIORITY_SS_47(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c18*/ u64 rx_w_round_robin_6; +#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_48(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_49(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_50(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_51(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_52(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_53(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_54(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_6_RX_W_PRIORITY_SS_55(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c20*/ u64 rx_w_round_robin_7; +#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_56(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_57(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_58(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_59(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_60(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_61(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_62(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_7_RX_W_PRIORITY_SS_63(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c28*/ u64 rx_w_round_robin_8; +#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_64(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_65(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_66(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_67(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_68(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_69(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_70(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_8_RX_W_PRIORITY_SS_71(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c30*/ u64 rx_w_round_robin_9; +#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_72(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_73(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_74(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_75(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_76(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_77(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_78(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_9_RX_W_PRIORITY_SS_79(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c38*/ u64 rx_w_round_robin_10; +#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_80(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_81(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_82(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_83(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_84(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_85(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_86(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_10_RX_W_PRIORITY_SS_87(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c40*/ u64 rx_w_round_robin_11; +#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_88(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_89(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_90(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_91(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_92(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_93(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_94(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_11_RX_W_PRIORITY_SS_95(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c48*/ u64 rx_w_round_robin_12; +#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_96(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_97(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_98(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_99(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_100(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_101(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_102(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_12_RX_W_PRIORITY_SS_103(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c50*/ u64 rx_w_round_robin_13; +#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_104(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_105(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_106(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_107(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_108(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_109(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_110(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_13_RX_W_PRIORITY_SS_111(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c58*/ u64 rx_w_round_robin_14; +#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_112(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_113(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_114(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_115(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_116(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_117(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_118(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_14_RX_W_PRIORITY_SS_119(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c60*/ u64 rx_w_round_robin_15; +#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_120(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_121(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_122(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_123(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_124(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_125(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_126(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_15_RX_W_PRIORITY_SS_127(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c68*/ u64 rx_w_round_robin_16; +#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_128(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_129(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_130(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_131(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_132(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_133(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_134(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_16_RX_W_PRIORITY_SS_135(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c70*/ u64 rx_w_round_robin_17; +#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_136(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_137(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_138(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_139(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_140(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_141(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_142(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_17_RX_W_PRIORITY_SS_143(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c78*/ u64 rx_w_round_robin_18; +#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_144(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_145(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_146(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_147(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_148(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_149(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_150(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_18_RX_W_PRIORITY_SS_151(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c80*/ u64 rx_w_round_robin_19; +#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_152(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_153(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_154(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_155(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_156(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_157(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_158(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_19_RX_W_PRIORITY_SS_159(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c88*/ u64 rx_w_round_robin_20; +#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_160(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_161(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_162(val) \ + vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_163(val) \ + vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_164(val) \ + vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_165(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_166(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_20_RX_W_PRIORITY_SS_167(val) \ + vxge_vBIT(val, 59, 5) +/*0x00c90*/ u64 rx_w_round_robin_21; +#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_168(val) \ + vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_169(val) \ + vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_W_ROUND_ROBIN_21_RX_W_PRIORITY_SS_170(val) \ + vxge_vBIT(val, 19, 5) + +#define VXGE_HW_WRR_RING_SERVICE_STATES 171 +#define VXGE_HW_WRR_RING_COUNT 22 + +/*0x00c98*/ u64 rx_queue_priority_0; +#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(val) vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(val) vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(val) vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(val) vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(val) vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(val) vxge_vBIT(val, 59, 5) +/*0x00ca0*/ u64 rx_queue_priority_1; +#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(val) vxge_vBIT(val, 19, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(val) vxge_vBIT(val, 27, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(val) vxge_vBIT(val, 35, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(val) vxge_vBIT(val, 43, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(val) vxge_vBIT(val, 51, 5) +#define VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(val) vxge_vBIT(val, 59, 5) +/*0x00ca8*/ u64 rx_queue_priority_2; +#define VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(val) vxge_vBIT(val, 3, 5) + u8 unused00cc8[0x00cc8-0x00cb0]; + +/*0x00cc8*/ u64 replication_queue_priority; +#define VXGE_HW_REPLICATION_QUEUE_PRIORITY_REPLICATION_QUEUE_PRIORITY(val) \ + vxge_vBIT(val, 59, 5) +/*0x00cd0*/ u64 rx_queue_select; +#define VXGE_HW_RX_QUEUE_SELECT_NUMBER(n) vxge_mBIT(n) +#define VXGE_HW_RX_QUEUE_SELECT_ENABLE_CODE vxge_mBIT(15) +#define VXGE_HW_RX_QUEUE_SELECT_ENABLE_HIERARCHICAL_PRTY vxge_mBIT(23) +/*0x00cd8*/ u64 rqa_vpbp_ctrl; +#define VXGE_HW_RQA_VPBP_CTRL_WR_XON_DIS vxge_mBIT(15) +#define VXGE_HW_RQA_VPBP_CTRL_ROCRC_DIS vxge_mBIT(23) +#define VXGE_HW_RQA_VPBP_CTRL_TXPE_DIS vxge_mBIT(31) +/*0x00ce0*/ u64 rx_multi_cast_ctrl; +#define VXGE_HW_RX_MULTI_CAST_CTRL_TIME_OUT_DIS vxge_mBIT(0) +#define VXGE_HW_RX_MULTI_CAST_CTRL_FRM_DROP_DIS vxge_mBIT(1) +#define VXGE_HW_RX_MULTI_CAST_CTRL_NO_RXD_TIME_OUT_CNT(val) \ + vxge_vBIT(val, 2, 30) +#define VXGE_HW_RX_MULTI_CAST_CTRL_TIME_OUT_CNT(val) vxge_vBIT(val, 32, 32) +/*0x00ce8*/ u64 wde_prm_ctrl; +#define VXGE_HW_WDE_PRM_CTRL_SPAV_THRESHOLD(val) vxge_vBIT(val, 2, 10) +#define VXGE_HW_WDE_PRM_CTRL_SPLIT_THRESHOLD(val) vxge_vBIT(val, 18, 14) +#define VXGE_HW_WDE_PRM_CTRL_SPLIT_ON_1ST_ROW vxge_mBIT(32) +#define VXGE_HW_WDE_PRM_CTRL_SPLIT_ON_ROW_BNDRY vxge_mBIT(33) +#define VXGE_HW_WDE_PRM_CTRL_FB_ROW_SIZE(val) vxge_vBIT(val, 46, 2) +/*0x00cf0*/ u64 noa_ctrl; +#define VXGE_HW_NOA_CTRL_FRM_PRTY_QUOTA(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_NOA_CTRL_NON_FRM_PRTY_QUOTA(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_NOA_CTRL_IGNORE_KDFC_IF_STATUS vxge_mBIT(16) +#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE0(val) vxge_vBIT(val, 37, 4) +#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE1(val) vxge_vBIT(val, 45, 4) +#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE2(val) vxge_vBIT(val, 53, 4) +#define VXGE_HW_NOA_CTRL_MAX_JOB_CNT_FOR_WDE3(val) vxge_vBIT(val, 60, 4) +/*0x00cf8*/ u64 phase_cfg; +#define VXGE_HW_PHASE_CFG_QCC_WR_PHASE_EN vxge_mBIT(0) +#define VXGE_HW_PHASE_CFG_QCC_RD_PHASE_EN vxge_mBIT(3) +#define VXGE_HW_PHASE_CFG_IMMM_WR_PHASE_EN vxge_mBIT(7) +#define VXGE_HW_PHASE_CFG_IMMM_RD_PHASE_EN vxge_mBIT(11) +#define VXGE_HW_PHASE_CFG_UMQM_WR_PHASE_EN vxge_mBIT(15) +#define VXGE_HW_PHASE_CFG_UMQM_RD_PHASE_EN vxge_mBIT(19) +#define VXGE_HW_PHASE_CFG_RCBM_WR_PHASE_EN vxge_mBIT(23) +#define VXGE_HW_PHASE_CFG_RCBM_RD_PHASE_EN vxge_mBIT(27) +#define VXGE_HW_PHASE_CFG_RXD_RC_WR_PHASE_EN vxge_mBIT(31) +#define VXGE_HW_PHASE_CFG_RXD_RC_RD_PHASE_EN vxge_mBIT(35) +#define VXGE_HW_PHASE_CFG_RXD_RHS_WR_PHASE_EN vxge_mBIT(39) +#define VXGE_HW_PHASE_CFG_RXD_RHS_RD_PHASE_EN vxge_mBIT(43) +/*0x00d00*/ u64 rcq_bypq_cfg; +#define VXGE_HW_RCQ_BYPQ_CFG_OVERFLOW_THRESHOLD(val) vxge_vBIT(val, 10, 22) +#define VXGE_HW_RCQ_BYPQ_CFG_BYP_ON_THRESHOLD(val) vxge_vBIT(val, 39, 9) +#define VXGE_HW_RCQ_BYPQ_CFG_BYP_OFF_THRESHOLD(val) vxge_vBIT(val, 55, 9) + u8 unused00e00[0x00e00-0x00d08]; + +/*0x00e00*/ u64 doorbell_int_status; +#define VXGE_HW_DOORBELL_INT_STATUS_KDFC_ERR_REG_TXDMA_KDFC_INT vxge_mBIT(7) +#define VXGE_HW_DOORBELL_INT_STATUS_USDC_ERR_REG_TXDMA_USDC_INT vxge_mBIT(15) +/*0x00e08*/ u64 doorbell_int_mask; +/*0x00e10*/ u64 kdfc_err_reg; +#define VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_ECC_SG_ERR vxge_mBIT(7) +#define VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_ECC_DB_ERR vxge_mBIT(15) +#define VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_SM_ERR_ALARM vxge_mBIT(23) +#define VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_MISC_ERR_1 vxge_mBIT(32) +#define VXGE_HW_KDFC_ERR_REG_KDFC_KDFC_PCIX_ERR vxge_mBIT(39) +/*0x00e18*/ u64 kdfc_err_mask; +/*0x00e20*/ u64 kdfc_err_reg_alarm; +#define VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_ECC_SG_ERR vxge_mBIT(7) +#define VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_ECC_DB_ERR vxge_mBIT(15) +#define VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_SM_ERR_ALARM vxge_mBIT(23) +#define VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_MISC_ERR_1 vxge_mBIT(32) +#define VXGE_HW_KDFC_ERR_REG_ALARM_KDFC_KDFC_PCIX_ERR vxge_mBIT(39) + u8 unused00e40[0x00e40-0x00e28]; +/*0x00e40*/ u64 kdfc_vp_partition_0; +#define VXGE_HW_KDFC_VP_PARTITION_0_ENABLE vxge_mBIT(0) +#define VXGE_HW_KDFC_VP_PARTITION_0_NUMBER_0(val) vxge_vBIT(val, 5, 3) +#define VXGE_HW_KDFC_VP_PARTITION_0_LENGTH_0(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_VP_PARTITION_0_NUMBER_1(val) vxge_vBIT(val, 37, 3) +#define VXGE_HW_KDFC_VP_PARTITION_0_LENGTH_1(val) vxge_vBIT(val, 49, 15) +/*0x00e48*/ u64 kdfc_vp_partition_1; +#define VXGE_HW_KDFC_VP_PARTITION_1_NUMBER_2(val) vxge_vBIT(val, 5, 3) +#define VXGE_HW_KDFC_VP_PARTITION_1_LENGTH_2(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_VP_PARTITION_1_NUMBER_3(val) vxge_vBIT(val, 37, 3) +#define VXGE_HW_KDFC_VP_PARTITION_1_LENGTH_3(val) vxge_vBIT(val, 49, 15) +/*0x00e50*/ u64 kdfc_vp_partition_2; +#define VXGE_HW_KDFC_VP_PARTITION_2_NUMBER_4(val) vxge_vBIT(val, 5, 3) +#define VXGE_HW_KDFC_VP_PARTITION_2_LENGTH_4(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_VP_PARTITION_2_NUMBER_5(val) vxge_vBIT(val, 37, 3) +#define VXGE_HW_KDFC_VP_PARTITION_2_LENGTH_5(val) vxge_vBIT(val, 49, 15) +/*0x00e58*/ u64 kdfc_vp_partition_3; +#define VXGE_HW_KDFC_VP_PARTITION_3_NUMBER_6(val) vxge_vBIT(val, 5, 3) +#define VXGE_HW_KDFC_VP_PARTITION_3_LENGTH_6(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_VP_PARTITION_3_NUMBER_7(val) vxge_vBIT(val, 37, 3) +#define VXGE_HW_KDFC_VP_PARTITION_3_LENGTH_7(val) vxge_vBIT(val, 49, 15) +/*0x00e60*/ u64 kdfc_vp_partition_4; +#define VXGE_HW_KDFC_VP_PARTITION_4_LENGTH_8(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_VP_PARTITION_4_LENGTH_9(val) vxge_vBIT(val, 49, 15) +/*0x00e68*/ u64 kdfc_vp_partition_5; +#define VXGE_HW_KDFC_VP_PARTITION_5_LENGTH_10(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_VP_PARTITION_5_LENGTH_11(val) vxge_vBIT(val, 49, 15) +/*0x00e70*/ u64 kdfc_vp_partition_6; +#define VXGE_HW_KDFC_VP_PARTITION_6_LENGTH_12(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_VP_PARTITION_6_LENGTH_13(val) vxge_vBIT(val, 49, 15) +/*0x00e78*/ u64 kdfc_vp_partition_7; +#define VXGE_HW_KDFC_VP_PARTITION_7_LENGTH_14(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_VP_PARTITION_7_LENGTH_15(val) vxge_vBIT(val, 49, 15) +/*0x00e80*/ u64 kdfc_vp_partition_8; +#define VXGE_HW_KDFC_VP_PARTITION_8_LENGTH_16(val) vxge_vBIT(val, 17, 15) +/*0x00e88*/ u64 kdfc_w_round_robin_0; +#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(val) vxge_vBIT(val, 19, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(val) vxge_vBIT(val, 27, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(val) vxge_vBIT(val, 35, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(val) vxge_vBIT(val, 43, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(val) vxge_vBIT(val, 51, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(val) vxge_vBIT(val, 59, 5) + + u8 unused0f28[0x0f28-0x0e90]; + +/*0x00f28*/ u64 kdfc_w_round_robin_20; +#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_0(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_1(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_2(val) vxge_vBIT(val, 19, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_3(val) vxge_vBIT(val, 27, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_4(val) vxge_vBIT(val, 35, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_5(val) vxge_vBIT(val, 43, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_6(val) vxge_vBIT(val, 51, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_20_NUMBER_7(val) vxge_vBIT(val, 59, 5) + +#define VXGE_HW_WRR_FIFO_COUNT 20 + + u8 unused0fc8[0x0fc8-0x0f30]; + +/*0x00fc8*/ u64 kdfc_w_round_robin_40; +#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_0(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_1(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_2(val) vxge_vBIT(val, 19, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_3(val) vxge_vBIT(val, 27, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_4(val) vxge_vBIT(val, 35, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_5(val) vxge_vBIT(val, 43, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_6(val) vxge_vBIT(val, 51, 5) +#define VXGE_HW_KDFC_W_ROUND_ROBIN_40_NUMBER_7(val) vxge_vBIT(val, 59, 5) + + u8 unused1068[0x01068-0x0fd0]; + +/*0x01068*/ u64 kdfc_entry_type_sel_0; +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(val) vxge_vBIT(val, 14, 2) +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(val) vxge_vBIT(val, 22, 2) +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(val) vxge_vBIT(val, 30, 2) +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(val) vxge_vBIT(val, 38, 2) +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(val) vxge_vBIT(val, 46, 2) +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(val) vxge_vBIT(val, 54, 2) +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(val) vxge_vBIT(val, 62, 2) +/*0x01070*/ u64 kdfc_entry_type_sel_1; +#define VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(val) vxge_vBIT(val, 6, 2) +/*0x01078*/ u64 kdfc_fifo_0_ctrl; +#define VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_WEIGHTED_RR_SERVICE_STATES 176 +#define VXGE_HW_WRR_FIFO_SERVICE_STATES 153 + + u8 unused1100[0x01100-0x1080]; + +/*0x01100*/ u64 kdfc_fifo_17_ctrl; +#define VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(val) vxge_vBIT(val, 3, 5) + + u8 unused1600[0x01600-0x1108]; + +/*0x01600*/ u64 rxmac_int_status; +#define VXGE_HW_RXMAC_INT_STATUS_RXMAC_GEN_ERR_RXMAC_GEN_INT vxge_mBIT(3) +#define VXGE_HW_RXMAC_INT_STATUS_RXMAC_ECC_ERR_RXMAC_ECC_INT vxge_mBIT(7) +#define VXGE_HW_RXMAC_INT_STATUS_RXMAC_VARIOUS_ERR_RXMAC_VARIOUS_INT \ + vxge_mBIT(11) +/*0x01608*/ u64 rxmac_int_mask; + u8 unused01618[0x01618-0x01610]; + +/*0x01618*/ u64 rxmac_gen_err_reg; +/*0x01620*/ u64 rxmac_gen_err_mask; +/*0x01628*/ u64 rxmac_gen_err_alarm; +/*0x01630*/ u64 rxmac_ecc_err_reg; +#define VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT0_RMAC_RTS_PART_SG_ERR(val) \ + vxge_vBIT(val, 0, 4) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT0_RMAC_RTS_PART_DB_ERR(val) \ + vxge_vBIT(val, 4, 4) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT1_RMAC_RTS_PART_SG_ERR(val) \ + vxge_vBIT(val, 8, 4) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT1_RMAC_RTS_PART_DB_ERR(val) \ + vxge_vBIT(val, 12, 4) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT2_RMAC_RTS_PART_SG_ERR(val) \ + vxge_vBIT(val, 16, 4) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RMAC_PORT2_RMAC_RTS_PART_DB_ERR(val) \ + vxge_vBIT(val, 20, 4) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT0_SG_ERR(val) \ + vxge_vBIT(val, 24, 2) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT0_DB_ERR(val) \ + vxge_vBIT(val, 26, 2) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT1_SG_ERR(val) \ + vxge_vBIT(val, 28, 2) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DA_LKP_PRT1_DB_ERR(val) \ + vxge_vBIT(val, 30, 2) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_VID_LKP_SG_ERR vxge_mBIT(32) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_VID_LKP_DB_ERR vxge_mBIT(33) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT0_SG_ERR vxge_mBIT(34) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT0_DB_ERR vxge_mBIT(35) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT1_SG_ERR vxge_mBIT(36) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT1_DB_ERR vxge_mBIT(37) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT2_SG_ERR vxge_mBIT(38) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_PN_LKP_PRT2_DB_ERR vxge_mBIT(39) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_MASK_SG_ERR(val) \ + vxge_vBIT(val, 40, 7) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_MASK_DB_ERR(val) \ + vxge_vBIT(val, 47, 7) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_LKP_SG_ERR(val) \ + vxge_vBIT(val, 54, 3) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_RTH_LKP_DB_ERR(val) \ + vxge_vBIT(val, 57, 3) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DS_LKP_SG_ERR \ + vxge_mBIT(60) +#define VXGE_HW_RXMAC_ECC_ERR_REG_RTSJ_RMAC_DS_LKP_DB_ERR \ + vxge_mBIT(61) +/*0x01638*/ u64 rxmac_ecc_err_mask; +/*0x01640*/ u64 rxmac_ecc_err_alarm; +/*0x01648*/ u64 rxmac_various_err_reg; +#define VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT0_FSM_ERR vxge_mBIT(0) +#define VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT1_FSM_ERR vxge_mBIT(1) +#define VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMAC_RMAC_PORT2_FSM_ERR vxge_mBIT(2) +#define VXGE_HW_RXMAC_VARIOUS_ERR_REG_RMACJ_RMACJ_FSM_ERR vxge_mBIT(3) +/*0x01650*/ u64 rxmac_various_err_mask; +/*0x01658*/ u64 rxmac_various_err_alarm; +/*0x01660*/ u64 rxmac_gen_cfg; +#define VXGE_HW_RXMAC_GEN_CFG_SCALE_RMAC_UTIL vxge_mBIT(11) +/*0x01668*/ u64 rxmac_authorize_all_addr; +#define VXGE_HW_RXMAC_AUTHORIZE_ALL_ADDR_VP(n) vxge_mBIT(n) +/*0x01670*/ u64 rxmac_authorize_all_vid; +#define VXGE_HW_RXMAC_AUTHORIZE_ALL_VID_VP(n) vxge_mBIT(n) + u8 unused016c0[0x016c0-0x01678]; + +/*0x016c0*/ u64 rxmac_red_rate_repl_queue; +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR0(val) vxge_vBIT(val, 0, 4) +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR1(val) vxge_vBIT(val, 4, 4) +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR2(val) vxge_vBIT(val, 8, 4) +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_CRATE_THR3(val) vxge_vBIT(val, 12, 4) +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR0(val) vxge_vBIT(val, 16, 4) +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR1(val) vxge_vBIT(val, 20, 4) +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR2(val) vxge_vBIT(val, 24, 4) +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_FRATE_THR3(val) vxge_vBIT(val, 28, 4) +#define VXGE_HW_RXMAC_RED_RATE_REPL_QUEUE_TRICKLE_EN vxge_mBIT(35) + u8 unused016e0[0x016e0-0x016c8]; + +/*0x016e0*/ u64 rxmac_cfg0_port[3]; +#define VXGE_HW_RXMAC_CFG0_PORT_RMAC_EN vxge_mBIT(3) +#define VXGE_HW_RXMAC_CFG0_PORT_STRIP_FCS vxge_mBIT(7) +#define VXGE_HW_RXMAC_CFG0_PORT_DISCARD_PFRM vxge_mBIT(11) +#define VXGE_HW_RXMAC_CFG0_PORT_IGNORE_FCS_ERR vxge_mBIT(15) +#define VXGE_HW_RXMAC_CFG0_PORT_IGNORE_LONG_ERR vxge_mBIT(19) +#define VXGE_HW_RXMAC_CFG0_PORT_IGNORE_USIZED_ERR vxge_mBIT(23) +#define VXGE_HW_RXMAC_CFG0_PORT_IGNORE_LEN_MISMATCH vxge_mBIT(27) +#define VXGE_HW_RXMAC_CFG0_PORT_MAX_PYLD_LEN(val) vxge_vBIT(val, 50, 14) + u8 unused01710[0x01710-0x016f8]; + +/*0x01710*/ u64 rxmac_cfg2_port[3]; +#define VXGE_HW_RXMAC_CFG2_PORT_PROM_EN vxge_mBIT(3) +/*0x01728*/ u64 rxmac_pause_cfg_port[3]; +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN vxge_mBIT(3) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN vxge_mBIT(7) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_ACCEL_SEND(val) vxge_vBIT(val, 9, 3) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_DUAL_THR vxge_mBIT(15) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_HIGH_PTIME(val) vxge_vBIT(val, 20, 16) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_IGNORE_PF_FCS_ERR vxge_mBIT(39) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_IGNORE_PF_LEN_ERR vxge_mBIT(43) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_LIMITER_EN vxge_mBIT(47) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_MAX_LIMIT(val) vxge_vBIT(val, 48, 8) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_PERMIT_RATEMGMT_CTRL vxge_mBIT(59) + u8 unused01758[0x01758-0x01740]; + +/*0x01758*/ u64 rxmac_red_cfg0_port[3]; +#define VXGE_HW_RXMAC_RED_CFG0_PORT_RED_EN_VP(n) vxge_mBIT(n) +/*0x01770*/ u64 rxmac_red_cfg1_port[3]; +#define VXGE_HW_RXMAC_RED_CFG1_PORT_FINE_EN vxge_mBIT(3) +#define VXGE_HW_RXMAC_RED_CFG1_PORT_RED_EN_REPL_QUEUE vxge_mBIT(11) +/*0x01788*/ u64 rxmac_red_cfg2_port[3]; +#define VXGE_HW_RXMAC_RED_CFG2_PORT_TRICKLE_EN_VP(n) vxge_mBIT(n) +/*0x017a0*/ u64 rxmac_link_util_port[3]; +#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_UTILIZATION(val) \ + vxge_vBIT(val, 1, 7) +#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_UTIL_CFG(val) vxge_vBIT(val, 8, 4) +#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_FRAC_UTIL(val) \ + vxge_vBIT(val, 12, 4) +#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_PKT_WEIGHT(val) vxge_vBIT(val, 16, 4) +#define VXGE_HW_RXMAC_LINK_UTIL_PORT_RMAC_RMAC_SCALE_FACTOR vxge_mBIT(23) + u8 unused017d0[0x017d0-0x017b8]; + +/*0x017d0*/ u64 rxmac_status_port[3]; +#define VXGE_HW_RXMAC_STATUS_PORT_RMAC_RX_FRM_RCVD vxge_mBIT(3) + u8 unused01800[0x01800-0x017e8]; + +/*0x01800*/ u64 rxmac_rx_pa_cfg0; +#define VXGE_HW_RXMAC_RX_PA_CFG0_IGNORE_FRAME_ERR vxge_mBIT(3) +#define VXGE_HW_RXMAC_RX_PA_CFG0_SUPPORT_SNAP_AB_N vxge_mBIT(7) +#define VXGE_HW_RXMAC_RX_PA_CFG0_SEARCH_FOR_HAO vxge_mBIT(18) +#define VXGE_HW_RXMAC_RX_PA_CFG0_SUPPORT_MOBILE_IPV6_HDRS vxge_mBIT(19) +#define VXGE_HW_RXMAC_RX_PA_CFG0_IPV6_STOP_SEARCHING vxge_mBIT(23) +#define VXGE_HW_RXMAC_RX_PA_CFG0_NO_PS_IF_UNKNOWN vxge_mBIT(27) +#define VXGE_HW_RXMAC_RX_PA_CFG0_SEARCH_FOR_ETYPE vxge_mBIT(35) +#define VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_L3_CSUM_ERR vxge_mBIT(39) +#define VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_L3_CSUM_ERR vxge_mBIT(43) +#define VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_L4_CSUM_ERR vxge_mBIT(47) +#define VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_L4_CSUM_ERR vxge_mBIT(51) +#define VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_ANY_FRM_IF_RPA_ERR vxge_mBIT(55) +#define VXGE_HW_RXMAC_RX_PA_CFG0_TOSS_OFFLD_FRM_IF_RPA_ERR vxge_mBIT(59) +#define VXGE_HW_RXMAC_RX_PA_CFG0_JUMBO_SNAP_EN vxge_mBIT(63) +/*0x01808*/ u64 rxmac_rx_pa_cfg1; +#define VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV4_TCP_INCL_PH vxge_mBIT(3) +#define VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV6_TCP_INCL_PH vxge_mBIT(7) +#define VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV4_UDP_INCL_PH vxge_mBIT(11) +#define VXGE_HW_RXMAC_RX_PA_CFG1_REPL_IPV6_UDP_INCL_PH vxge_mBIT(15) +#define VXGE_HW_RXMAC_RX_PA_CFG1_REPL_L4_INCL_CF vxge_mBIT(19) +#define VXGE_HW_RXMAC_RX_PA_CFG1_REPL_STRIP_VLAN_TAG vxge_mBIT(23) + u8 unused01828[0x01828-0x01810]; + +/*0x01828*/ u64 rts_mgr_cfg0; +#define VXGE_HW_RTS_MGR_CFG0_RTS_DP_SP_PRIORITY vxge_mBIT(3) +#define VXGE_HW_RTS_MGR_CFG0_FLEX_L4PRTCL_VALUE(val) vxge_vBIT(val, 24, 8) +#define VXGE_HW_RTS_MGR_CFG0_ICMP_TRASH vxge_mBIT(35) +#define VXGE_HW_RTS_MGR_CFG0_TCPSYN_TRASH vxge_mBIT(39) +#define VXGE_HW_RTS_MGR_CFG0_ZL4PYLD_TRASH vxge_mBIT(43) +#define VXGE_HW_RTS_MGR_CFG0_L4PRTCL_TCP_TRASH vxge_mBIT(47) +#define VXGE_HW_RTS_MGR_CFG0_L4PRTCL_UDP_TRASH vxge_mBIT(51) +#define VXGE_HW_RTS_MGR_CFG0_L4PRTCL_FLEX_TRASH vxge_mBIT(55) +#define VXGE_HW_RTS_MGR_CFG0_IPFRAG_TRASH vxge_mBIT(59) +/*0x01830*/ u64 rts_mgr_cfg1; +#define VXGE_HW_RTS_MGR_CFG1_DA_ACTIVE_TABLE vxge_mBIT(3) +#define VXGE_HW_RTS_MGR_CFG1_PN_ACTIVE_TABLE vxge_mBIT(7) +/*0x01838*/ u64 rts_mgr_criteria_priority; +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ETYPE(val) vxge_vBIT(val, 5, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ICMP_TCPSYN(val) vxge_vBIT(val, 9, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_L4PN(val) vxge_vBIT(val, 13, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_RANGE_L4PN(val) vxge_vBIT(val, 17, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_RTH_IT(val) vxge_vBIT(val, 21, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_DS(val) vxge_vBIT(val, 25, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_QOS(val) vxge_vBIT(val, 29, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_ZL4PYLD(val) vxge_vBIT(val, 33, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_L4PRTCL(val) vxge_vBIT(val, 37, 3) +/*0x01840*/ u64 rts_mgr_da_pause_cfg; +#define VXGE_HW_RTS_MGR_DA_PAUSE_CFG_VPATH_VECTOR(val) vxge_vBIT(val, 0, 17) +/*0x01848*/ u64 rts_mgr_da_slow_proto_cfg; +#define VXGE_HW_RTS_MGR_DA_SLOW_PROTO_CFG_VPATH_VECTOR(val) \ + vxge_vBIT(val, 0, 17) + u8 unused01890[0x01890-0x01850]; +/*0x01890*/ u64 rts_mgr_cbasin_cfg; + u8 unused01968[0x01968-0x01898]; + +/*0x01968*/ u64 dbg_stat_rx_any_frms; +#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT0_RX_ANY_FRMS(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT1_RX_ANY_FRMS(val) vxge_vBIT(val, 8, 8) +#define VXGE_HW_DBG_STAT_RX_ANY_FRMS_PORT2_RX_ANY_FRMS(val) \ + vxge_vBIT(val, 16, 8) + u8 unused01a00[0x01a00-0x01970]; + +/*0x01a00*/ u64 rxmac_red_rate_vp[17]; +#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR0(val) vxge_vBIT(val, 0, 4) +#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR1(val) vxge_vBIT(val, 4, 4) +#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR2(val) vxge_vBIT(val, 8, 4) +#define VXGE_HW_RXMAC_RED_RATE_VP_CRATE_THR3(val) vxge_vBIT(val, 12, 4) +#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR0(val) vxge_vBIT(val, 16, 4) +#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR1(val) vxge_vBIT(val, 20, 4) +#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR2(val) vxge_vBIT(val, 24, 4) +#define VXGE_HW_RXMAC_RED_RATE_VP_FRATE_THR3(val) vxge_vBIT(val, 28, 4) + u8 unused01e00[0x01e00-0x01a88]; + +/*0x01e00*/ u64 xgmac_int_status; +#define VXGE_HW_XGMAC_INT_STATUS_XMAC_GEN_ERR_XMAC_GEN_INT vxge_mBIT(3) +#define VXGE_HW_XGMAC_INT_STATUS_XMAC_LINK_ERR_PORT0_XMAC_LINK_INT_PORT0 \ + vxge_mBIT(7) +#define VXGE_HW_XGMAC_INT_STATUS_XMAC_LINK_ERR_PORT1_XMAC_LINK_INT_PORT1 \ + vxge_mBIT(11) +#define VXGE_HW_XGMAC_INT_STATUS_XGXS_GEN_ERR_XGXS_GEN_INT vxge_mBIT(15) +#define VXGE_HW_XGMAC_INT_STATUS_ASIC_NTWK_ERR_ASIC_NTWK_INT vxge_mBIT(19) +#define VXGE_HW_XGMAC_INT_STATUS_ASIC_GPIO_ERR_ASIC_GPIO_INT vxge_mBIT(23) +/*0x01e08*/ u64 xgmac_int_mask; +/*0x01e10*/ u64 xmac_gen_err_reg; +#define VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_ACTOR_CHURN_DETECTED \ + vxge_mBIT(7) +#define VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_PARTNER_CHURN_DETECTED \ + vxge_mBIT(11) +#define VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT0_RECEIVED_LACPDU vxge_mBIT(15) +#define VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_ACTOR_CHURN_DETECTED \ + vxge_mBIT(19) +#define VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_PARTNER_CHURN_DETECTED \ + vxge_mBIT(23) +#define VXGE_HW_XMAC_GEN_ERR_REG_LAGC_LAG_PORT1_RECEIVED_LACPDU vxge_mBIT(27) +#define VXGE_HW_XMAC_GEN_ERR_REG_XLCM_LAG_FAILOVER_DETECTED vxge_mBIT(31) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE0_SG_ERR(val) \ + vxge_vBIT(val, 40, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE0_DB_ERR(val) \ + vxge_vBIT(val, 42, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE1_SG_ERR(val) \ + vxge_vBIT(val, 44, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE1_DB_ERR(val) \ + vxge_vBIT(val, 46, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE2_SG_ERR(val) \ + vxge_vBIT(val, 48, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE2_DB_ERR(val) \ + vxge_vBIT(val, 50, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE3_SG_ERR(val) \ + vxge_vBIT(val, 52, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE3_DB_ERR(val) \ + vxge_vBIT(val, 54, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE4_SG_ERR(val) \ + vxge_vBIT(val, 56, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XSTATS_RMAC_STATS_TILE4_DB_ERR(val) \ + vxge_vBIT(val, 58, 2) +#define VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR vxge_mBIT(63) +/*0x01e18*/ u64 xmac_gen_err_mask; +/*0x01e20*/ u64 xmac_gen_err_alarm; +/*0x01e28*/ u64 xmac_link_err_port_reg[2]; +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN vxge_mBIT(3) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP vxge_mBIT(7) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN vxge_mBIT(11) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_UP vxge_mBIT(15) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_REAFFIRMED_FAULT \ + vxge_mBIT(19) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_REAFFIRMED_OK vxge_mBIT(23) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_LINK_DOWN vxge_mBIT(27) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_LINK_UP vxge_mBIT(31) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_RATE_CHANGE vxge_mBIT(35) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV vxge_mBIT(39) +#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \ + vxge_mBIT(47) +/*0x01e30*/ u64 xmac_link_err_port_mask[2]; +/*0x01e38*/ u64 xmac_link_err_port_alarm[2]; +/*0x01e58*/ u64 xgxs_gen_err_reg; +#define VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR vxge_mBIT(63) +/*0x01e60*/ u64 xgxs_gen_err_mask; +/*0x01e68*/ u64 xgxs_gen_err_alarm; +/*0x01e70*/ u64 asic_ntwk_err_reg; +#define VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_DOWN vxge_mBIT(3) +#define VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_UP vxge_mBIT(7) +#define VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_WENT_DOWN vxge_mBIT(11) +#define VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_WENT_UP vxge_mBIT(15) +#define VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT vxge_mBIT(19) +#define VXGE_HW_ASIC_NTWK_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK vxge_mBIT(23) +/*0x01e78*/ u64 asic_ntwk_err_mask; +/*0x01e80*/ u64 asic_ntwk_err_alarm; +/*0x01e88*/ u64 asic_gpio_err_reg; +#define VXGE_HW_ASIC_GPIO_ERR_REG_XMACJ_GPIO_INT(n) vxge_mBIT(n) +/*0x01e90*/ u64 asic_gpio_err_mask; +/*0x01e98*/ u64 asic_gpio_err_alarm; +/*0x01ea0*/ u64 xgmac_gen_status; +#define VXGE_HW_XGMAC_GEN_STATUS_XMACJ_NTWK_OK vxge_mBIT(3) +#define VXGE_HW_XGMAC_GEN_STATUS_XMACJ_NTWK_DATA_RATE vxge_mBIT(11) +/*0x01ea8*/ u64 xgmac_gen_fw_memo_status; +#define VXGE_HW_XGMAC_GEN_FW_MEMO_STATUS_XMACJ_EVENTS_PENDING(val) \ + vxge_vBIT(val, 0, 17) +/*0x01eb0*/ u64 xgmac_gen_fw_memo_mask; +#define VXGE_HW_XGMAC_GEN_FW_MEMO_MASK_MASK(val) vxge_vBIT(val, 0, 64) +/*0x01eb8*/ u64 xgmac_gen_fw_vpath_to_vsport_status; +#define VXGE_HW_XGMAC_GEN_FW_VPATH_TO_VSPORT_STATUS_XMACJ_EVENTS_PENDING(val) \ + vxge_vBIT(val, 0, 17) +/*0x01ec0*/ u64 xgmac_main_cfg_port[2]; +#define VXGE_HW_XGMAC_MAIN_CFG_PORT_PORT_EN vxge_mBIT(3) + u8 unused01f40[0x01f40-0x01ed0]; + +/*0x01f40*/ u64 xmac_gen_cfg; +#define VXGE_HW_XMAC_GEN_CFG_RATEMGMT_MAC_RATE_SEL(val) vxge_vBIT(val, 2, 2) +#define VXGE_HW_XMAC_GEN_CFG_TX_HEAD_DROP_WHEN_FAULT vxge_mBIT(7) +#define VXGE_HW_XMAC_GEN_CFG_FAULT_BEHAVIOUR vxge_mBIT(27) +#define VXGE_HW_XMAC_GEN_CFG_PERIOD_NTWK_UP(val) vxge_vBIT(val, 28, 4) +#define VXGE_HW_XMAC_GEN_CFG_PERIOD_NTWK_DOWN(val) vxge_vBIT(val, 32, 4) +/*0x01f48*/ u64 xmac_timestamp; +#define VXGE_HW_XMAC_TIMESTAMP_EN vxge_mBIT(3) +#define VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_XMAC_TIMESTAMP_INTERVAL(val) vxge_vBIT(val, 12, 4) +#define VXGE_HW_XMAC_TIMESTAMP_TIMER_RESTART vxge_mBIT(19) +#define VXGE_HW_XMAC_TIMESTAMP_XMACJ_ROLLOVER_CNT(val) vxge_vBIT(val, 32, 16) +/*0x01f50*/ u64 xmac_stats_gen_cfg; +#define VXGE_HW_XMAC_STATS_GEN_CFG_PRTAGGR_CUM_TIMER(val) vxge_vBIT(val, 4, 4) +#define VXGE_HW_XMAC_STATS_GEN_CFG_VPATH_CUM_TIMER(val) vxge_vBIT(val, 8, 4) +#define VXGE_HW_XMAC_STATS_GEN_CFG_VLAN_HANDLING vxge_mBIT(15) +/*0x01f58*/ u64 xmac_stats_sys_cmd; +#define VXGE_HW_XMAC_STATS_SYS_CMD_OP(val) vxge_vBIT(val, 5, 3) +#define VXGE_HW_XMAC_STATS_SYS_CMD_STROBE vxge_mBIT(15) +#define VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(val) vxge_vBIT(val, 27, 5) +#define VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(val) vxge_vBIT(val, 32, 8) +/*0x01f60*/ u64 xmac_stats_sys_data; +#define VXGE_HW_XMAC_STATS_SYS_DATA_XSMGR_DATA(val) vxge_vBIT(val, 0, 64) + u8 unused01f80[0x01f80-0x01f68]; + +/*0x01f80*/ u64 asic_ntwk_ctrl; +#define VXGE_HW_ASIC_NTWK_CTRL_REQ_TEST_NTWK vxge_mBIT(3) +#define VXGE_HW_ASIC_NTWK_CTRL_PORT0_REQ_TEST_PORT vxge_mBIT(11) +#define VXGE_HW_ASIC_NTWK_CTRL_PORT1_REQ_TEST_PORT vxge_mBIT(15) +/*0x01f88*/ u64 asic_ntwk_cfg_show_port_info; +#define VXGE_HW_ASIC_NTWK_CFG_SHOW_PORT_INFO_VP(n) vxge_mBIT(n) +/*0x01f90*/ u64 asic_ntwk_cfg_port_num; +#define VXGE_HW_ASIC_NTWK_CFG_PORT_NUM_VP(n) vxge_mBIT(n) +/*0x01f98*/ u64 xmac_cfg_port[3]; +#define VXGE_HW_XMAC_CFG_PORT_XGMII_LOOPBACK vxge_mBIT(3) +#define VXGE_HW_XMAC_CFG_PORT_XGMII_REVERSE_LOOPBACK vxge_mBIT(7) +#define VXGE_HW_XMAC_CFG_PORT_XGMII_TX_BEHAV vxge_mBIT(11) +#define VXGE_HW_XMAC_CFG_PORT_XGMII_RX_BEHAV vxge_mBIT(15) +/*0x01fb0*/ u64 xmac_station_addr_port[2]; +#define VXGE_HW_XMAC_STATION_ADDR_PORT_MAC_ADDR(val) vxge_vBIT(val, 0, 48) + u8 unused02020[0x02020-0x01fc0]; + +/*0x02020*/ u64 lag_cfg; +#define VXGE_HW_LAG_CFG_EN vxge_mBIT(3) +#define VXGE_HW_LAG_CFG_MODE(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_LAG_CFG_TX_DISCARD_BEHAV vxge_mBIT(11) +#define VXGE_HW_LAG_CFG_RX_DISCARD_BEHAV vxge_mBIT(15) +#define VXGE_HW_LAG_CFG_PREF_INDIV_PORT_NUM vxge_mBIT(19) +/*0x02028*/ u64 lag_status; +#define VXGE_HW_LAG_STATUS_XLCM_WAITING_TO_FAILBACK vxge_mBIT(3) +#define VXGE_HW_LAG_STATUS_XLCM_TIMER_VAL_COLD_FAILOVER(val) \ + vxge_vBIT(val, 8, 8) +/*0x02030*/ u64 lag_active_passive_cfg; +#define VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_HOT_STANDBY vxge_mBIT(3) +#define VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_LACP_DECIDES vxge_mBIT(7) +#define VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_PREF_ACTIVE_PORT_NUM vxge_mBIT(11) +#define VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_AUTO_FAILBACK vxge_mBIT(15) +#define VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_FAILBACK_EN vxge_mBIT(19) +#define VXGE_HW_LAG_ACTIVE_PASSIVE_CFG_COLD_FAILOVER_TIMEOUT(val) \ + vxge_vBIT(val, 32, 16) + u8 unused02040[0x02040-0x02038]; + +/*0x02040*/ u64 lag_lacp_cfg; +#define VXGE_HW_LAG_LACP_CFG_EN vxge_mBIT(3) +#define VXGE_HW_LAG_LACP_CFG_LACP_BEGIN vxge_mBIT(7) +#define VXGE_HW_LAG_LACP_CFG_DISCARD_LACP vxge_mBIT(11) +#define VXGE_HW_LAG_LACP_CFG_LIBERAL_LEN_CHK vxge_mBIT(15) +/*0x02048*/ u64 lag_timer_cfg_1; +#define VXGE_HW_LAG_TIMER_CFG_1_FAST_PER(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_LAG_TIMER_CFG_1_SLOW_PER(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_LAG_TIMER_CFG_1_SHORT_TIMEOUT(val) vxge_vBIT(val, 32, 16) +#define VXGE_HW_LAG_TIMER_CFG_1_LONG_TIMEOUT(val) vxge_vBIT(val, 48, 16) +/*0x02050*/ u64 lag_timer_cfg_2; +#define VXGE_HW_LAG_TIMER_CFG_2_CHURN_DET(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_LAG_TIMER_CFG_2_AGGR_WAIT(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_LAG_TIMER_CFG_2_SHORT_TIMER_SCALE(val) vxge_vBIT(val, 32, 16) +#define VXGE_HW_LAG_TIMER_CFG_2_LONG_TIMER_SCALE(val) vxge_vBIT(val, 48, 16) +/*0x02058*/ u64 lag_sys_id; +#define VXGE_HW_LAG_SYS_ID_ADDR(val) vxge_vBIT(val, 0, 48) +#define VXGE_HW_LAG_SYS_ID_USE_PORT_ADDR vxge_mBIT(51) +#define VXGE_HW_LAG_SYS_ID_ADDR_SEL vxge_mBIT(55) +/*0x02060*/ u64 lag_sys_cfg; +#define VXGE_HW_LAG_SYS_CFG_SYS_PRI(val) vxge_vBIT(val, 0, 16) + u8 unused02070[0x02070-0x02068]; + +/*0x02070*/ u64 lag_aggr_addr_cfg[2]; +#define VXGE_HW_LAG_AGGR_ADDR_CFG_ADDR(val) vxge_vBIT(val, 0, 48) +#define VXGE_HW_LAG_AGGR_ADDR_CFG_USE_PORT_ADDR vxge_mBIT(51) +#define VXGE_HW_LAG_AGGR_ADDR_CFG_ADDR_SEL vxge_mBIT(55) +/*0x02080*/ u64 lag_aggr_id_cfg[2]; +#define VXGE_HW_LAG_AGGR_ID_CFG_ID(val) vxge_vBIT(val, 0, 16) +/*0x02090*/ u64 lag_aggr_admin_key[2]; +#define VXGE_HW_LAG_AGGR_ADMIN_KEY_KEY(val) vxge_vBIT(val, 0, 16) +/*0x020a0*/ u64 lag_aggr_alt_admin_key; +#define VXGE_HW_LAG_AGGR_ALT_ADMIN_KEY_KEY(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_LAG_AGGR_ALT_ADMIN_KEY_ALT_AGGR vxge_mBIT(19) +/*0x020a8*/ u64 lag_aggr_oper_key[2]; +#define VXGE_HW_LAG_AGGR_OPER_KEY_LAGC_KEY(val) vxge_vBIT(val, 0, 16) +/*0x020b8*/ u64 lag_aggr_partner_sys_id[2]; +#define VXGE_HW_LAG_AGGR_PARTNER_SYS_ID_LAGC_ADDR(val) vxge_vBIT(val, 0, 48) +/*0x020c8*/ u64 lag_aggr_partner_info[2]; +#define VXGE_HW_LAG_AGGR_PARTNER_INFO_LAGC_SYS_PRI(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_LAG_AGGR_PARTNER_INFO_LAGC_OPER_KEY(val) \ + vxge_vBIT(val, 16, 16) +/*0x020d8*/ u64 lag_aggr_state[2]; +#define VXGE_HW_LAG_AGGR_STATE_LAGC_TX vxge_mBIT(3) +#define VXGE_HW_LAG_AGGR_STATE_LAGC_RX vxge_mBIT(7) +#define VXGE_HW_LAG_AGGR_STATE_LAGC_READY vxge_mBIT(11) +#define VXGE_HW_LAG_AGGR_STATE_LAGC_INDIVIDUAL vxge_mBIT(15) + u8 unused020f0[0x020f0-0x020e8]; + +/*0x020f0*/ u64 lag_port_cfg[2]; +#define VXGE_HW_LAG_PORT_CFG_EN vxge_mBIT(3) +#define VXGE_HW_LAG_PORT_CFG_DISCARD_SLOW_PROTO vxge_mBIT(7) +#define VXGE_HW_LAG_PORT_CFG_HOST_CHOSEN_AGGR vxge_mBIT(11) +#define VXGE_HW_LAG_PORT_CFG_DISCARD_UNKNOWN_SLOW_PROTO vxge_mBIT(15) +/*0x02100*/ u64 lag_port_actor_admin_cfg[2]; +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_PORT_NUM(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_PORT_PRI(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_KEY_10G(val) vxge_vBIT(val, 32, 16) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_CFG_KEY_1G(val) vxge_vBIT(val, 48, 16) +/*0x02110*/ u64 lag_port_actor_admin_state[2]; +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_LACP_ACTIVITY vxge_mBIT(3) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_LACP_TIMEOUT vxge_mBIT(7) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_AGGREGATION vxge_mBIT(11) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_SYNCHRONIZATION vxge_mBIT(15) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_COLLECTING vxge_mBIT(19) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_DISTRIBUTING vxge_mBIT(23) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_DEFAULTED vxge_mBIT(27) +#define VXGE_HW_LAG_PORT_ACTOR_ADMIN_STATE_EXPIRED vxge_mBIT(31) +/*0x02120*/ u64 lag_port_partner_admin_sys_id[2]; +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_SYS_ID_ADDR(val) vxge_vBIT(val, 0, 48) +/*0x02130*/ u64 lag_port_partner_admin_cfg[2]; +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_SYS_PRI(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_KEY(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_PORT_NUM(val) \ + vxge_vBIT(val, 32, 16) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_CFG_PORT_PRI(val) \ + vxge_vBIT(val, 48, 16) +/*0x02140*/ u64 lag_port_partner_admin_state[2]; +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_LACP_ACTIVITY vxge_mBIT(3) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_LACP_TIMEOUT vxge_mBIT(7) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_AGGREGATION vxge_mBIT(11) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_SYNCHRONIZATION vxge_mBIT(15) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_COLLECTING vxge_mBIT(19) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_DISTRIBUTING vxge_mBIT(23) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_DEFAULTED vxge_mBIT(27) +#define VXGE_HW_LAG_PORT_PARTNER_ADMIN_STATE_EXPIRED vxge_mBIT(31) +/*0x02150*/ u64 lag_port_to_aggr[2]; +#define VXGE_HW_LAG_PORT_TO_AGGR_LAGC_AGGR_ID(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_LAG_PORT_TO_AGGR_LAGC_AGGR_VLD_ID vxge_mBIT(19) +/*0x02160*/ u64 lag_port_actor_oper_key[2]; +#define VXGE_HW_LAG_PORT_ACTOR_OPER_KEY_LAGC_KEY(val) vxge_vBIT(val, 0, 16) +/*0x02170*/ u64 lag_port_actor_oper_state[2]; +#define VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_LACP_ACTIVITY vxge_mBIT(3) +#define VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_LACP_TIMEOUT vxge_mBIT(7) +#define VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_AGGREGATION vxge_mBIT(11) +#define VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_SYNCHRONIZATION vxge_mBIT(15) +#define VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_COLLECTING vxge_mBIT(19) +#define VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_DISTRIBUTING vxge_mBIT(23) +#define VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_DEFAULTED vxge_mBIT(27) +#define VXGE_HW_LAG_PORT_ACTOR_OPER_STATE_LAGC_EXPIRED vxge_mBIT(31) +/*0x02180*/ u64 lag_port_partner_oper_sys_id[2]; +#define VXGE_HW_LAG_PORT_PARTNER_OPER_SYS_ID_LAGC_ADDR(val) \ + vxge_vBIT(val, 0, 48) +/*0x02190*/ u64 lag_port_partner_oper_info[2]; +#define VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_SYS_PRI(val) \ + vxge_vBIT(val, 0, 16) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_KEY(val) \ + vxge_vBIT(val, 16, 16) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_PORT_NUM(val) \ + vxge_vBIT(val, 32, 16) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_INFO_LAGC_PORT_PRI(val) \ + vxge_vBIT(val, 48, 16) +/*0x021a0*/ u64 lag_port_partner_oper_state[2]; +#define VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_LACP_ACTIVITY vxge_mBIT(3) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_LACP_TIMEOUT vxge_mBIT(7) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_AGGREGATION vxge_mBIT(11) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_SYNCHRONIZATION \ + vxge_mBIT(15) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_COLLECTING vxge_mBIT(19) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_DISTRIBUTING vxge_mBIT(23) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_DEFAULTED vxge_mBIT(27) +#define VXGE_HW_LAG_PORT_PARTNER_OPER_STATE_LAGC_EXPIRED vxge_mBIT(31) +/*0x021b0*/ u64 lag_port_state_vars[2]; +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_READY vxge_mBIT(3) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_SELECTED(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_AGGR_NUM vxge_mBIT(11) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_MOVED vxge_mBIT(15) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_ENABLED vxge_mBIT(18) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PORT_DISABLED vxge_mBIT(19) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_NTT vxge_mBIT(23) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN vxge_mBIT(27) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN vxge_mBIT(31) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_INFO_LEN_MISMATCH \ + vxge_mBIT(32) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_INFO_LEN_MISMATCH \ + vxge_mBIT(33) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_COLL_INFO_LEN_MISMATCH vxge_mBIT(34) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_TERM_INFO_LEN_MISMATCH vxge_mBIT(35) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_RX_FSM_STATE(val) vxge_vBIT(val, 37, 3) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_MUX_FSM_STATE(val) \ + vxge_vBIT(val, 41, 3) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_MUX_REASON(val) vxge_vBIT(val, 44, 4) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN_STATE vxge_mBIT(54) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN_STATE vxge_mBIT(55) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_ACTOR_CHURN_COUNT(val) \ + vxge_vBIT(val, 56, 4) +#define VXGE_HW_LAG_PORT_STATE_VARS_LAGC_PARTNER_CHURN_COUNT(val) \ + vxge_vBIT(val, 60, 4) +/*0x021c0*/ u64 lag_port_timer_cntr[2]; +#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_CURRENT_WHILE(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PERIODIC_WHILE(val) \ + vxge_vBIT(val, 8, 8) +#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_WAIT_WHILE(val) vxge_vBIT(val, 16, 8) +#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_TX_LACP(val) vxge_vBIT(val, 24, 8) +#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_ACTOR_SYNC_TRANSITION_COUNT(val) \ + vxge_vBIT(val, 32, 8) +#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PARTNER_SYNC_TRANSITION_COUNT(val) \ + vxge_vBIT(val, 40, 8) +#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_ACTOR_CHANGE_COUNT(val) \ + vxge_vBIT(val, 48, 8) +#define VXGE_HW_LAG_PORT_TIMER_CNTR_LAGC_PARTNER_CHANGE_COUNT(val) \ + vxge_vBIT(val, 56, 8) + u8 unused02208[0x02700-0x021d0]; + +/*0x02700*/ u64 rtdma_int_status; +#define VXGE_HW_RTDMA_INT_STATUS_PDA_ALARM_PDA_INT vxge_mBIT(1) +#define VXGE_HW_RTDMA_INT_STATUS_PCC_ERROR_PCC_INT vxge_mBIT(2) +#define VXGE_HW_RTDMA_INT_STATUS_LSO_ERROR_LSO_INT vxge_mBIT(4) +#define VXGE_HW_RTDMA_INT_STATUS_SM_ERROR_SM_INT vxge_mBIT(5) +/*0x02708*/ u64 rtdma_int_mask; +/*0x02710*/ u64 pda_alarm_reg; +#define VXGE_HW_PDA_ALARM_REG_PDA_HSC_FIFO_ERR vxge_mBIT(0) +#define VXGE_HW_PDA_ALARM_REG_PDA_SM_ERR vxge_mBIT(1) +/*0x02718*/ u64 pda_alarm_mask; +/*0x02720*/ u64 pda_alarm_alarm; +/*0x02728*/ u64 pcc_error_reg; +#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FRM_BUF_SBE(n) vxge_mBIT(n) +#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_TXDO_SBE(n) vxge_mBIT(n) +#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FRM_BUF_DBE(n) vxge_mBIT(n) +#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_TXDO_DBE(n) vxge_mBIT(n) +#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_FSM_ERR_ALARM(n) vxge_mBIT(n) +#define VXGE_HW_PCC_ERROR_REG_PCC_PCC_SERR(n) vxge_mBIT(n) +/*0x02730*/ u64 pcc_error_mask; +/*0x02738*/ u64 pcc_error_alarm; +/*0x02740*/ u64 lso_error_reg; +#define VXGE_HW_LSO_ERROR_REG_PCC_LSO_ABORT(n) vxge_mBIT(n) +#define VXGE_HW_LSO_ERROR_REG_PCC_LSO_FSM_ERR_ALARM(n) vxge_mBIT(n) +/*0x02748*/ u64 lso_error_mask; +/*0x02750*/ u64 lso_error_alarm; +/*0x02758*/ u64 sm_error_reg; +#define VXGE_HW_SM_ERROR_REG_SM_FSM_ERR_ALARM vxge_mBIT(15) +/*0x02760*/ u64 sm_error_mask; +/*0x02768*/ u64 sm_error_alarm; + + u8 unused027a8[0x027a8-0x02770]; + +/*0x027a8*/ u64 txd_ownership_ctrl; +#define VXGE_HW_TXD_OWNERSHIP_CTRL_KEEP_OWNERSHIP vxge_mBIT(7) +/*0x027b0*/ u64 pcc_cfg; +#define VXGE_HW_PCC_CFG_PCC_ENABLE(n) vxge_mBIT(n) +#define VXGE_HW_PCC_CFG_PCC_ECC_ENABLE_N(n) vxge_mBIT(n) +/*0x027b8*/ u64 pcc_control; +#define VXGE_HW_PCC_CONTROL_FE_ENABLE(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_PCC_CONTROL_EARLY_ASSIGN_EN vxge_mBIT(15) +#define VXGE_HW_PCC_CONTROL_UNBLOCK_DB_ERR vxge_mBIT(31) +/*0x027c0*/ u64 pda_status1; +#define VXGE_HW_PDA_STATUS1_PDA_WRAP_0_CTR(val) vxge_vBIT(val, 4, 4) +#define VXGE_HW_PDA_STATUS1_PDA_WRAP_1_CTR(val) vxge_vBIT(val, 12, 4) +#define VXGE_HW_PDA_STATUS1_PDA_WRAP_2_CTR(val) vxge_vBIT(val, 20, 4) +#define VXGE_HW_PDA_STATUS1_PDA_WRAP_3_CTR(val) vxge_vBIT(val, 28, 4) +#define VXGE_HW_PDA_STATUS1_PDA_WRAP_4_CTR(val) vxge_vBIT(val, 36, 4) +#define VXGE_HW_PDA_STATUS1_PDA_WRAP_5_CTR(val) vxge_vBIT(val, 44, 4) +#define VXGE_HW_PDA_STATUS1_PDA_WRAP_6_CTR(val) vxge_vBIT(val, 52, 4) +#define VXGE_HW_PDA_STATUS1_PDA_WRAP_7_CTR(val) vxge_vBIT(val, 60, 4) +/*0x027c8*/ u64 rtdma_bw_timer; +#define VXGE_HW_RTDMA_BW_TIMER_TIMER_CTRL(val) vxge_vBIT(val, 12, 4) + + u8 unused02900[0x02900-0x027d0]; +/*0x02900*/ u64 g3cmct_int_status; +#define VXGE_HW_G3CMCT_INT_STATUS_ERR_G3IF_INT vxge_mBIT(0) +/*0x02908*/ u64 g3cmct_int_mask; +/*0x02910*/ u64 g3cmct_err_reg; +#define VXGE_HW_G3CMCT_ERR_REG_G3IF_SM_ERR vxge_mBIT(4) +#define VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_DECC vxge_mBIT(5) +#define VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_U_DECC vxge_mBIT(6) +#define VXGE_HW_G3CMCT_ERR_REG_G3IF_CTRL_FIFO_DECC vxge_mBIT(7) +#define VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_SECC vxge_mBIT(29) +#define VXGE_HW_G3CMCT_ERR_REG_G3IF_GDDR3_U_SECC vxge_mBIT(30) +#define VXGE_HW_G3CMCT_ERR_REG_G3IF_CTRL_FIFO_SECC vxge_mBIT(31) +/*0x02918*/ u64 g3cmct_err_mask; +/*0x02920*/ u64 g3cmct_err_alarm; + u8 unused03000[0x03000-0x02928]; + +/*0x03000*/ u64 mc_int_status; +#define VXGE_HW_MC_INT_STATUS_MC_ERR_MC_INT vxge_mBIT(3) +#define VXGE_HW_MC_INT_STATUS_GROCRC_ALARM_ROCRC_INT vxge_mBIT(7) +#define VXGE_HW_MC_INT_STATUS_FAU_GEN_ERR_FAU_GEN_INT vxge_mBIT(11) +#define VXGE_HW_MC_INT_STATUS_FAU_ECC_ERR_FAU_ECC_INT vxge_mBIT(15) +/*0x03008*/ u64 mc_int_mask; +/*0x03010*/ u64 mc_err_reg; +#define VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_SG_ERR_A vxge_mBIT(3) +#define VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_SG_ERR_B vxge_mBIT(4) +#define VXGE_HW_MC_ERR_REG_MC_G3IF_RD_FIFO_ECC_SG_ERR vxge_mBIT(5) +#define VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_SG_ERR_0 vxge_mBIT(6) +#define VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_SG_ERR_1 vxge_mBIT(7) +#define VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_DB_ERR_A vxge_mBIT(10) +#define VXGE_HW_MC_ERR_REG_MC_XFMD_MEM_ECC_DB_ERR_B vxge_mBIT(11) +#define VXGE_HW_MC_ERR_REG_MC_G3IF_RD_FIFO_ECC_DB_ERR vxge_mBIT(12) +#define VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_DB_ERR_0 vxge_mBIT(13) +#define VXGE_HW_MC_ERR_REG_MC_MIRI_ECC_DB_ERR_1 vxge_mBIT(14) +#define VXGE_HW_MC_ERR_REG_MC_SM_ERR vxge_mBIT(15) +/*0x03018*/ u64 mc_err_mask; +/*0x03020*/ u64 mc_err_alarm; +/*0x03028*/ u64 grocrc_alarm_reg; +#define VXGE_HW_GROCRC_ALARM_REG_XFMD_WR_FIFO_ERR vxge_mBIT(3) +#define VXGE_HW_GROCRC_ALARM_REG_WDE2MSR_RD_FIFO_ERR vxge_mBIT(7) +/*0x03030*/ u64 grocrc_alarm_mask; +/*0x03038*/ u64 grocrc_alarm_alarm; + u8 unused03100[0x03100-0x03040]; + +/*0x03100*/ u64 rx_thresh_cfg_repl; +#define VXGE_HW_RX_THRESH_CFG_REPL_PAUSE_LOW_THR(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_RX_THRESH_CFG_REPL_PAUSE_HIGH_THR(val) vxge_vBIT(val, 8, 8) +#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_0(val) vxge_vBIT(val, 16, 8) +#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_1(val) vxge_vBIT(val, 24, 8) +#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_2(val) vxge_vBIT(val, 32, 8) +#define VXGE_HW_RX_THRESH_CFG_REPL_RED_THR_3(val) vxge_vBIT(val, 40, 8) +#define VXGE_HW_RX_THRESH_CFG_REPL_GLOBAL_WOL_EN vxge_mBIT(62) +#define VXGE_HW_RX_THRESH_CFG_REPL_EXACT_VP_MATCH_REQ vxge_mBIT(63) + u8 unused033b8[0x033b8-0x03108]; + +/*0x033b8*/ u64 fbmc_ecc_cfg; +#define VXGE_HW_FBMC_ECC_CFG_ENABLE(val) vxge_vBIT(val, 3, 5) + u8 unused03400[0x03400-0x033c0]; + +/*0x03400*/ u64 pcipif_int_status; +#define VXGE_HW_PCIPIF_INT_STATUS_DBECC_ERR_DBECC_ERR_INT vxge_mBIT(3) +#define VXGE_HW_PCIPIF_INT_STATUS_SBECC_ERR_SBECC_ERR_INT vxge_mBIT(7) +#define VXGE_HW_PCIPIF_INT_STATUS_GENERAL_ERR_GENERAL_ERR_INT vxge_mBIT(11) +#define VXGE_HW_PCIPIF_INT_STATUS_SRPCIM_MSG_SRPCIM_MSG_INT vxge_mBIT(15) +#define VXGE_HW_PCIPIF_INT_STATUS_MRPCIM_SPARE_R1_MRPCIM_SPARE_R1_INT \ + vxge_mBIT(19) +/*0x03408*/ u64 pcipif_int_mask; +/*0x03410*/ u64 dbecc_err_reg; +#define VXGE_HW_DBECC_ERR_REG_PCI_RETRY_BUF_DB_ERR vxge_mBIT(3) +#define VXGE_HW_DBECC_ERR_REG_PCI_RETRY_SOT_DB_ERR vxge_mBIT(7) +#define VXGE_HW_DBECC_ERR_REG_PCI_P_HDR_DB_ERR vxge_mBIT(11) +#define VXGE_HW_DBECC_ERR_REG_PCI_P_DATA_DB_ERR vxge_mBIT(15) +#define VXGE_HW_DBECC_ERR_REG_PCI_NP_HDR_DB_ERR vxge_mBIT(19) +#define VXGE_HW_DBECC_ERR_REG_PCI_NP_DATA_DB_ERR vxge_mBIT(23) +/*0x03418*/ u64 dbecc_err_mask; +/*0x03420*/ u64 dbecc_err_alarm; +/*0x03428*/ u64 sbecc_err_reg; +#define VXGE_HW_SBECC_ERR_REG_PCI_RETRY_BUF_SG_ERR vxge_mBIT(3) +#define VXGE_HW_SBECC_ERR_REG_PCI_RETRY_SOT_SG_ERR vxge_mBIT(7) +#define VXGE_HW_SBECC_ERR_REG_PCI_P_HDR_SG_ERR vxge_mBIT(11) +#define VXGE_HW_SBECC_ERR_REG_PCI_P_DATA_SG_ERR vxge_mBIT(15) +#define VXGE_HW_SBECC_ERR_REG_PCI_NP_HDR_SG_ERR vxge_mBIT(19) +#define VXGE_HW_SBECC_ERR_REG_PCI_NP_DATA_SG_ERR vxge_mBIT(23) +/*0x03430*/ u64 sbecc_err_mask; +/*0x03438*/ u64 sbecc_err_alarm; +/*0x03440*/ u64 general_err_reg; +#define VXGE_HW_GENERAL_ERR_REG_PCI_DROPPED_ILLEGAL_CFG vxge_mBIT(3) +#define VXGE_HW_GENERAL_ERR_REG_PCI_ILLEGAL_MEM_MAP_PROG vxge_mBIT(7) +#define VXGE_HW_GENERAL_ERR_REG_PCI_LINK_RST_FSM_ERR vxge_mBIT(11) +#define VXGE_HW_GENERAL_ERR_REG_PCI_RX_ILLEGAL_TLP_VPLANE vxge_mBIT(15) +#define VXGE_HW_GENERAL_ERR_REG_PCI_TRAINING_RESET_DET vxge_mBIT(19) +#define VXGE_HW_GENERAL_ERR_REG_PCI_PCI_LINK_DOWN_DET vxge_mBIT(23) +#define VXGE_HW_GENERAL_ERR_REG_PCI_RESET_ACK_DLLP vxge_mBIT(27) +/*0x03448*/ u64 general_err_mask; +/*0x03450*/ u64 general_err_alarm; +/*0x03458*/ u64 srpcim_msg_reg; +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE0_RMSG_INT \ + vxge_mBIT(0) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE1_RMSG_INT \ + vxge_mBIT(1) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE2_RMSG_INT \ + vxge_mBIT(2) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE3_RMSG_INT \ + vxge_mBIT(3) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE4_RMSG_INT \ + vxge_mBIT(4) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE5_RMSG_INT \ + vxge_mBIT(5) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE6_RMSG_INT \ + vxge_mBIT(6) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE7_RMSG_INT \ + vxge_mBIT(7) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE8_RMSG_INT \ + vxge_mBIT(8) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE9_RMSG_INT \ + vxge_mBIT(9) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE10_RMSG_INT \ + vxge_mBIT(10) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE11_RMSG_INT \ + vxge_mBIT(11) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE12_RMSG_INT \ + vxge_mBIT(12) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE13_RMSG_INT \ + vxge_mBIT(13) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE14_RMSG_INT \ + vxge_mBIT(14) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE15_RMSG_INT \ + vxge_mBIT(15) +#define VXGE_HW_SRPCIM_MSG_REG_SWIF_SRPCIM_TO_MRPCIM_VPLANE16_RMSG_INT \ + vxge_mBIT(16) +/*0x03460*/ u64 srpcim_msg_mask; +/*0x03468*/ u64 srpcim_msg_alarm; + u8 unused03600[0x03600-0x03470]; + +/*0x03600*/ u64 gcmg1_int_status; +#define VXGE_HW_GCMG1_INT_STATUS_GSSCC_ERR_GSSCC_INT vxge_mBIT(0) +#define VXGE_HW_GCMG1_INT_STATUS_GSSC0_ERR0_GSSC0_0_INT vxge_mBIT(1) +#define VXGE_HW_GCMG1_INT_STATUS_GSSC0_ERR1_GSSC0_1_INT vxge_mBIT(2) +#define VXGE_HW_GCMG1_INT_STATUS_GSSC1_ERR0_GSSC1_0_INT vxge_mBIT(3) +#define VXGE_HW_GCMG1_INT_STATUS_GSSC1_ERR1_GSSC1_1_INT vxge_mBIT(4) +#define VXGE_HW_GCMG1_INT_STATUS_GSSC2_ERR0_GSSC2_0_INT vxge_mBIT(5) +#define VXGE_HW_GCMG1_INT_STATUS_GSSC2_ERR1_GSSC2_1_INT vxge_mBIT(6) +#define VXGE_HW_GCMG1_INT_STATUS_UQM_ERR_UQM_INT vxge_mBIT(7) +#define VXGE_HW_GCMG1_INT_STATUS_GQCC_ERR_GQCC_INT vxge_mBIT(8) +/*0x03608*/ u64 gcmg1_int_mask; + u8 unused03a00[0x03a00-0x03610]; + +/*0x03a00*/ u64 pcmg1_int_status; +#define VXGE_HW_PCMG1_INT_STATUS_PSSCC_ERR_PSSCC_INT vxge_mBIT(0) +#define VXGE_HW_PCMG1_INT_STATUS_PQCC_ERR_PQCC_INT vxge_mBIT(1) +#define VXGE_HW_PCMG1_INT_STATUS_PQCC_CQM_ERR_PQCC_CQM_INT vxge_mBIT(2) +#define VXGE_HW_PCMG1_INT_STATUS_PQCC_SQM_ERR_PQCC_SQM_INT vxge_mBIT(3) +/*0x03a08*/ u64 pcmg1_int_mask; + u8 unused04000[0x04000-0x03a10]; + +/*0x04000*/ u64 one_int_status; +#define VXGE_HW_ONE_INT_STATUS_RXPE_ERR_RXPE_INT vxge_mBIT(7) +#define VXGE_HW_ONE_INT_STATUS_TXPE_BCC_MEM_SG_ECC_ERR_TXPE_BCC_MEM_SG_ECC_INT \ + vxge_mBIT(13) +#define VXGE_HW_ONE_INT_STATUS_TXPE_BCC_MEM_DB_ECC_ERR_TXPE_BCC_MEM_DB_ECC_INT \ + vxge_mBIT(14) +#define VXGE_HW_ONE_INT_STATUS_TXPE_ERR_TXPE_INT vxge_mBIT(15) +#define VXGE_HW_ONE_INT_STATUS_DLM_ERR_DLM_INT vxge_mBIT(23) +#define VXGE_HW_ONE_INT_STATUS_PE_ERR_PE_INT vxge_mBIT(31) +#define VXGE_HW_ONE_INT_STATUS_RPE_ERR_RPE_INT vxge_mBIT(39) +#define VXGE_HW_ONE_INT_STATUS_RPE_FSM_ERR_RPE_FSM_INT vxge_mBIT(47) +#define VXGE_HW_ONE_INT_STATUS_OES_ERR_OES_INT vxge_mBIT(55) +/*0x04008*/ u64 one_int_mask; + u8 unused04818[0x04818-0x04010]; + +/*0x04818*/ u64 noa_wct_ctrl; +#define VXGE_HW_NOA_WCT_CTRL_VP_INT_NUM vxge_mBIT(0) +/*0x04820*/ u64 rc_cfg2; +#define VXGE_HW_RC_CFG2_BUFF1_SIZE(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_RC_CFG2_BUFF2_SIZE(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_RC_CFG2_BUFF3_SIZE(val) vxge_vBIT(val, 32, 16) +#define VXGE_HW_RC_CFG2_BUFF4_SIZE(val) vxge_vBIT(val, 48, 16) +/*0x04828*/ u64 rc_cfg3; +#define VXGE_HW_RC_CFG3_BUFF5_SIZE(val) vxge_vBIT(val, 0, 16) +/*0x04830*/ u64 rx_multi_cast_ctrl1; +#define VXGE_HW_RX_MULTI_CAST_CTRL1_ENABLE vxge_mBIT(7) +#define VXGE_HW_RX_MULTI_CAST_CTRL1_DELAY_COUNT(val) vxge_vBIT(val, 11, 5) +/*0x04838*/ u64 rxdm_dbg_rd; +#define VXGE_HW_RXDM_DBG_RD_ADDR(val) vxge_vBIT(val, 0, 12) +#define VXGE_HW_RXDM_DBG_RD_ENABLE vxge_mBIT(31) +/*0x04840*/ u64 rxdm_dbg_rd_data; +#define VXGE_HW_RXDM_DBG_RD_DATA_RMC_RXDM_DBG_RD_DATA(val) vxge_vBIT(val, 0, 64) +/*0x04848*/ u64 rqa_top_prty_for_vh[17]; +#define VXGE_HW_RQA_TOP_PRTY_FOR_VH_RQA_TOP_PRTY_FOR_VH(val) \ + vxge_vBIT(val, 59, 5) + u8 unused04900[0x04900-0x048d0]; + +/*0x04900*/ u64 tim_status; +#define VXGE_HW_TIM_STATUS_TIM_RESET_IN_PROGRESS vxge_mBIT(0) +/*0x04908*/ u64 tim_ecc_enable; +#define VXGE_HW_TIM_ECC_ENABLE_VBLS_N vxge_mBIT(7) +#define VXGE_HW_TIM_ECC_ENABLE_BMAP_N vxge_mBIT(15) +#define VXGE_HW_TIM_ECC_ENABLE_BMAP_MSG_N vxge_mBIT(23) +/*0x04910*/ u64 tim_bp_ctrl; +#define VXGE_HW_TIM_BP_CTRL_RD_XON vxge_mBIT(7) +#define VXGE_HW_TIM_BP_CTRL_WR_XON vxge_mBIT(15) +#define VXGE_HW_TIM_BP_CTRL_ROCRC_BYP vxge_mBIT(23) +/*0x04918*/ u64 tim_resource_assignment_vh[17]; +#define VXGE_HW_TIM_RESOURCE_ASSIGNMENT_VH_BMAP_ROOT(val) vxge_vBIT(val, 0, 32) +/*0x049a0*/ u64 tim_bmap_mapping_vp_err[17]; +#define VXGE_HW_TIM_BMAP_MAPPING_VP_ERR_TIM_DEST_VPATH(val) vxge_vBIT(val, 3, 5) + u8 unused04b00[0x04b00-0x04a28]; + +/*0x04b00*/ u64 gcmg2_int_status; +#define VXGE_HW_GCMG2_INT_STATUS_GXTMC_ERR_GXTMC_INT vxge_mBIT(7) +#define VXGE_HW_GCMG2_INT_STATUS_GCP_ERR_GCP_INT vxge_mBIT(15) +#define VXGE_HW_GCMG2_INT_STATUS_CMC_ERR_CMC_INT vxge_mBIT(23) +/*0x04b08*/ u64 gcmg2_int_mask; +/*0x04b10*/ u64 gxtmc_err_reg; +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_MEM_DB_ERR(val) vxge_vBIT(val, 0, 4) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_MEM_SG_ERR(val) vxge_vBIT(val, 4, 4) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CMC_RD_DATA_DB_ERR vxge_mBIT(8) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_REQ_FIFO_ERR vxge_mBIT(9) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_REQ_DATA_FIFO_ERR vxge_mBIT(10) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_WR_RSP_FIFO_ERR vxge_mBIT(11) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_RD_RSP_FIFO_ERR vxge_mBIT(12) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_WRP_FIFO_ERR vxge_mBIT(13) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_WRP_ERR vxge_mBIT(14) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_RRP_FIFO_ERR vxge_mBIT(15) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_RRP_ERR vxge_mBIT(16) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_DATA_SM_ERR vxge_mBIT(17) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_CMC0_IF_ERR vxge_mBIT(18) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_ARB_SM_ERR vxge_mBIT(19) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_CFC_SM_ERR vxge_mBIT(20) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_CREDIT_OVERFLOW \ + vxge_mBIT(21) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_CREDIT_UNDERFLOW \ + vxge_mBIT(22) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_DFETCH_SM_ERR vxge_mBIT(23) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_CREDIT_OVERFLOW \ + vxge_mBIT(24) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_CREDIT_UNDERFLOW \ + vxge_mBIT(25) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_RCTRL_SM_ERR vxge_mBIT(26) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WCOMPL_SM_ERR vxge_mBIT(27) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WCOMPL_TAG_ERR vxge_mBIT(28) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WREQ_SM_ERR vxge_mBIT(29) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_BDT_CMI_WREQ_FIFO_ERR vxge_mBIT(30) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CP2BDT_RFIFO_POP_ERR vxge_mBIT(31) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_CMI_OP_ERR vxge_mBIT(32) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_DFETCH_OP_ERR vxge_mBIT(33) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_XTMC_BDT_DFIFO_ERR vxge_mBIT(34) +#define VXGE_HW_GXTMC_ERR_REG_XTMC_CMI_ARB_SM_ERR vxge_mBIT(35) +/*0x04b18*/ u64 gxtmc_err_mask; +/*0x04b20*/ u64 gxtmc_err_alarm; +/*0x04b28*/ u64 cmc_err_reg; +#define VXGE_HW_CMC_ERR_REG_CMC_CMC_SM_ERR vxge_mBIT(0) +/*0x04b30*/ u64 cmc_err_mask; +/*0x04b38*/ u64 cmc_err_alarm; +/*0x04b40*/ u64 gcp_err_reg; +#define VXGE_HW_GCP_ERR_REG_CP_H2L2CP_FIFO_ERR vxge_mBIT(0) +#define VXGE_HW_GCP_ERR_REG_CP_STC2CP_FIFO_ERR vxge_mBIT(1) +#define VXGE_HW_GCP_ERR_REG_CP_STE2CP_FIFO_ERR vxge_mBIT(2) +#define VXGE_HW_GCP_ERR_REG_CP_TTE2CP_FIFO_ERR vxge_mBIT(3) +/*0x04b48*/ u64 gcp_err_mask; +/*0x04b50*/ u64 gcp_err_alarm; + u8 unused04f00[0x04f00-0x04b58]; + +/*0x04f00*/ u64 pcmg2_int_status; +#define VXGE_HW_PCMG2_INT_STATUS_PXTMC_ERR_PXTMC_INT vxge_mBIT(7) +#define VXGE_HW_PCMG2_INT_STATUS_CP_EXC_CP_XT_EXC_INT vxge_mBIT(15) +#define VXGE_HW_PCMG2_INT_STATUS_CP_ERR_CP_ERR_INT vxge_mBIT(23) +/*0x04f08*/ u64 pcmg2_int_mask; +/*0x04f10*/ u64 pxtmc_err_reg; +#define VXGE_HW_PXTMC_ERR_REG_XTMC_XT_PIF_SRAM_DB_ERR(val) vxge_vBIT(val, 0, 2) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_FIFO_ERR vxge_mBIT(2) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_PRSP_FIFO_ERR vxge_mBIT(3) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_WRSP_FIFO_ERR vxge_mBIT(4) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_FIFO_ERR vxge_mBIT(5) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_PRSP_FIFO_ERR vxge_mBIT(6) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_WRSP_FIFO_ERR vxge_mBIT(7) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_FIFO_ERR vxge_mBIT(8) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_PRSP_FIFO_ERR vxge_mBIT(9) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_WRSP_FIFO_ERR vxge_mBIT(10) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_REQ_FIFO_ERR vxge_mBIT(11) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_REQ_DATA_FIFO_ERR vxge_mBIT(12) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_WR_RSP_FIFO_ERR vxge_mBIT(13) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_RD_RSP_FIFO_ERR vxge_mBIT(14) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_SHADOW_ERR vxge_mBIT(15) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_RSP_SHADOW_ERR vxge_mBIT(16) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_SHADOW_ERR vxge_mBIT(17) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_RSP_SHADOW_ERR vxge_mBIT(18) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_SHADOW_ERR vxge_mBIT(19) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_RSP_SHADOW_ERR vxge_mBIT(20) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_XIL_SHADOW_ERR vxge_mBIT(21) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_ARB_SHADOW_ERR vxge_mBIT(22) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_RAM_SHADOW_ERR vxge_mBIT(23) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CMW_SHADOW_ERR vxge_mBIT(24) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CMR_SHADOW_ERR vxge_mBIT(25) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_REQ_FSM_ERR vxge_mBIT(26) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MPT_RSP_FSM_ERR vxge_mBIT(27) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_REQ_FSM_ERR vxge_mBIT(28) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UPT_RSP_FSM_ERR vxge_mBIT(29) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_REQ_FSM_ERR vxge_mBIT(30) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CPT_RSP_FSM_ERR vxge_mBIT(31) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_XIL_FSM_ERR vxge_mBIT(32) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_ARB_FSM_ERR vxge_mBIT(33) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CMW_FSM_ERR vxge_mBIT(34) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CMR_FSM_ERR vxge_mBIT(35) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_RD_PROT_ERR vxge_mBIT(36) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_RD_PROT_ERR vxge_mBIT(37) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_RD_PROT_ERR vxge_mBIT(38) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_WR_PROT_ERR vxge_mBIT(39) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_WR_PROT_ERR vxge_mBIT(40) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_WR_PROT_ERR vxge_mBIT(41) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_INV_ADDR_ERR vxge_mBIT(42) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_INV_ADDR_ERR vxge_mBIT(43) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_INV_ADDR_ERR vxge_mBIT(44) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_RD_PROT_INFO_ERR vxge_mBIT(45) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_RD_PROT_INFO_ERR vxge_mBIT(46) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_RD_PROT_INFO_ERR vxge_mBIT(47) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_WR_PROT_INFO_ERR vxge_mBIT(48) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_WR_PROT_INFO_ERR vxge_mBIT(49) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_WR_PROT_INFO_ERR vxge_mBIT(50) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_MXP_INV_ADDR_INFO_ERR vxge_mBIT(51) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_UXP_INV_ADDR_INFO_ERR vxge_mBIT(52) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CXP_INV_ADDR_INFO_ERR vxge_mBIT(53) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_XT_PIF_SRAM_SG_ERR(val) vxge_vBIT(val, 54, 2) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CP2BDT_DFIFO_PUSH_ERR vxge_mBIT(56) +#define VXGE_HW_PXTMC_ERR_REG_XTMC_CP2BDT_RFIFO_PUSH_ERR vxge_mBIT(57) +/*0x04f18*/ u64 pxtmc_err_mask; +/*0x04f20*/ u64 pxtmc_err_alarm; +/*0x04f28*/ u64 cp_err_reg; +#define VXGE_HW_CP_ERR_REG_CP_CP_DCACHE_SG_ERR(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_CP_ERR_REG_CP_CP_ICACHE_SG_ERR(val) vxge_vBIT(val, 8, 2) +#define VXGE_HW_CP_ERR_REG_CP_CP_DTAG_SG_ERR vxge_mBIT(10) +#define VXGE_HW_CP_ERR_REG_CP_CP_ITAG_SG_ERR vxge_mBIT(11) +#define VXGE_HW_CP_ERR_REG_CP_CP_TRACE_SG_ERR vxge_mBIT(12) +#define VXGE_HW_CP_ERR_REG_CP_DMA2CP_SG_ERR vxge_mBIT(13) +#define VXGE_HW_CP_ERR_REG_CP_MP2CP_SG_ERR vxge_mBIT(14) +#define VXGE_HW_CP_ERR_REG_CP_QCC2CP_SG_ERR vxge_mBIT(15) +#define VXGE_HW_CP_ERR_REG_CP_STC2CP_SG_ERR(val) vxge_vBIT(val, 16, 2) +#define VXGE_HW_CP_ERR_REG_CP_CP_DCACHE_DB_ERR(val) vxge_vBIT(val, 24, 8) +#define VXGE_HW_CP_ERR_REG_CP_CP_ICACHE_DB_ERR(val) vxge_vBIT(val, 32, 2) +#define VXGE_HW_CP_ERR_REG_CP_CP_DTAG_DB_ERR vxge_mBIT(34) +#define VXGE_HW_CP_ERR_REG_CP_CP_ITAG_DB_ERR vxge_mBIT(35) +#define VXGE_HW_CP_ERR_REG_CP_CP_TRACE_DB_ERR vxge_mBIT(36) +#define VXGE_HW_CP_ERR_REG_CP_DMA2CP_DB_ERR vxge_mBIT(37) +#define VXGE_HW_CP_ERR_REG_CP_MP2CP_DB_ERR vxge_mBIT(38) +#define VXGE_HW_CP_ERR_REG_CP_QCC2CP_DB_ERR vxge_mBIT(39) +#define VXGE_HW_CP_ERR_REG_CP_STC2CP_DB_ERR(val) vxge_vBIT(val, 40, 2) +#define VXGE_HW_CP_ERR_REG_CP_H2L2CP_FIFO_ERR vxge_mBIT(48) +#define VXGE_HW_CP_ERR_REG_CP_STC2CP_FIFO_ERR vxge_mBIT(49) +#define VXGE_HW_CP_ERR_REG_CP_STE2CP_FIFO_ERR vxge_mBIT(50) +#define VXGE_HW_CP_ERR_REG_CP_TTE2CP_FIFO_ERR vxge_mBIT(51) +#define VXGE_HW_CP_ERR_REG_CP_SWIF2CP_FIFO_ERR vxge_mBIT(52) +#define VXGE_HW_CP_ERR_REG_CP_CP2DMA_FIFO_ERR vxge_mBIT(53) +#define VXGE_HW_CP_ERR_REG_CP_DAM2CP_FIFO_ERR vxge_mBIT(54) +#define VXGE_HW_CP_ERR_REG_CP_MP2CP_FIFO_ERR vxge_mBIT(55) +#define VXGE_HW_CP_ERR_REG_CP_QCC2CP_FIFO_ERR vxge_mBIT(56) +#define VXGE_HW_CP_ERR_REG_CP_DMA2CP_FIFO_ERR vxge_mBIT(57) +#define VXGE_HW_CP_ERR_REG_CP_CP_WAKE_FSM_INTEGRITY_ERR vxge_mBIT(60) +#define VXGE_HW_CP_ERR_REG_CP_CP_PMON_FSM_INTEGRITY_ERR vxge_mBIT(61) +#define VXGE_HW_CP_ERR_REG_CP_DMA_RD_SHADOW_ERR vxge_mBIT(62) +#define VXGE_HW_CP_ERR_REG_CP_PIFT_CREDIT_ERR vxge_mBIT(63) +/*0x04f30*/ u64 cp_err_mask; +/*0x04f38*/ u64 cp_err_alarm; + u8 unused04fe8[0x04f50-0x04f40]; + +/*0x04f50*/ u64 cp_exc_reg; +#define VXGE_HW_CP_EXC_REG_CP_CP_CAUSE_INFO_INT vxge_mBIT(47) +#define VXGE_HW_CP_EXC_REG_CP_CP_CAUSE_CRIT_INT vxge_mBIT(55) +#define VXGE_HW_CP_EXC_REG_CP_CP_SERR vxge_mBIT(63) +/*0x04f58*/ u64 cp_exc_mask; +/*0x04f60*/ u64 cp_exc_alarm; +/*0x04f68*/ u64 cp_exc_cause; +#define VXGE_HW_CP_EXC_CAUSE_CP_CP_CAUSE(val) vxge_vBIT(val, 32, 32) + u8 unused05200[0x05200-0x04f70]; + +/*0x05200*/ u64 msg_int_status; +#define VXGE_HW_MSG_INT_STATUS_TIM_ERR_TIM_INT vxge_mBIT(7) +#define VXGE_HW_MSG_INT_STATUS_MSG_EXC_MSG_XT_EXC_INT vxge_mBIT(60) +#define VXGE_HW_MSG_INT_STATUS_MSG_ERR3_MSG_ERR3_INT vxge_mBIT(61) +#define VXGE_HW_MSG_INT_STATUS_MSG_ERR2_MSG_ERR2_INT vxge_mBIT(62) +#define VXGE_HW_MSG_INT_STATUS_MSG_ERR_MSG_ERR_INT vxge_mBIT(63) +/*0x05208*/ u64 msg_int_mask; +/*0x05210*/ u64 tim_err_reg; +#define VXGE_HW_TIM_ERR_REG_TIM_VBLS_SG_ERR vxge_mBIT(4) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_PA_SG_ERR vxge_mBIT(5) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_PB_SG_ERR vxge_mBIT(6) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_SG_ERR vxge_mBIT(7) +#define VXGE_HW_TIM_ERR_REG_TIM_VBLS_DB_ERR vxge_mBIT(12) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_PA_DB_ERR vxge_mBIT(13) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_PB_DB_ERR vxge_mBIT(14) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_DB_ERR vxge_mBIT(15) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_MEM_CNTRL_SM_ERR vxge_mBIT(18) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_MSG_MEM_CNTRL_SM_ERR vxge_mBIT(19) +#define VXGE_HW_TIM_ERR_REG_TIM_MPIF_PCIWR_ERR vxge_mBIT(20) +#define VXGE_HW_TIM_ERR_REG_TIM_ROCRC_BMAP_UPDT_FIFO_ERR vxge_mBIT(22) +#define VXGE_HW_TIM_ERR_REG_TIM_CREATE_BMAPMSG_FIFO_ERR vxge_mBIT(23) +#define VXGE_HW_TIM_ERR_REG_TIM_ROCRCIF_MISMATCH vxge_mBIT(46) +#define VXGE_HW_TIM_ERR_REG_TIM_BMAP_MAPPING_VP_ERR(n) vxge_mBIT(n) +/*0x05218*/ u64 tim_err_mask; +/*0x05220*/ u64 tim_err_alarm; +/*0x05228*/ u64 msg_err_reg; +#define VXGE_HW_MSG_ERR_REG_UP_UXP_WAKE_FSM_INTEGRITY_ERR vxge_mBIT(0) +#define VXGE_HW_MSG_ERR_REG_MP_MXP_WAKE_FSM_INTEGRITY_ERR vxge_mBIT(1) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_DMA_READ_CMD_FSM_INTEGRITY_ERR \ + vxge_mBIT(2) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_DMA_RESP_FSM_INTEGRITY_ERR \ + vxge_mBIT(3) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_OWN_FSM_INTEGRITY_ERR vxge_mBIT(4) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_PDA_ACC_FSM_INTEGRITY_ERR vxge_mBIT(5) +#define VXGE_HW_MSG_ERR_REG_MP_MXP_PMON_FSM_INTEGRITY_ERR vxge_mBIT(6) +#define VXGE_HW_MSG_ERR_REG_UP_UXP_PMON_FSM_INTEGRITY_ERR vxge_mBIT(7) +#define VXGE_HW_MSG_ERR_REG_UP_UXP_DTAG_SG_ERR vxge_mBIT(8) +#define VXGE_HW_MSG_ERR_REG_UP_UXP_ITAG_SG_ERR vxge_mBIT(10) +#define VXGE_HW_MSG_ERR_REG_MP_MXP_DTAG_SG_ERR vxge_mBIT(12) +#define VXGE_HW_MSG_ERR_REG_MP_MXP_ITAG_SG_ERR vxge_mBIT(14) +#define VXGE_HW_MSG_ERR_REG_UP_UXP_TRACE_SG_ERR vxge_mBIT(16) +#define VXGE_HW_MSG_ERR_REG_MP_MXP_TRACE_SG_ERR vxge_mBIT(17) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_CMG2MSG_SG_ERR vxge_mBIT(18) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_TXPE2MSG_SG_ERR vxge_mBIT(19) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_RXPE2MSG_SG_ERR vxge_mBIT(20) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_RPE2MSG_SG_ERR vxge_mBIT(21) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_SG_ERR vxge_mBIT(26) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_PF_SG_ERR vxge_mBIT(27) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_ECC_SG_ERR vxge_mBIT(29) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_RESP_ECC_SG_ERR vxge_mBIT(31) +#define VXGE_HW_MSG_ERR_REG_MSG_XFMDQRY_FSM_INTEGRITY_ERR vxge_mBIT(33) +#define VXGE_HW_MSG_ERR_REG_MSG_FRMQRY_FSM_INTEGRITY_ERR vxge_mBIT(34) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_WRITE_FSM_INTEGRITY_ERR vxge_mBIT(35) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_BWR_PF_FSM_INTEGRITY_ERR \ + vxge_mBIT(36) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_REG_RESP_FIFO_ERR vxge_mBIT(38) +#define VXGE_HW_MSG_ERR_REG_UP_UXP_DTAG_DB_ERR vxge_mBIT(39) +#define VXGE_HW_MSG_ERR_REG_UP_UXP_ITAG_DB_ERR vxge_mBIT(41) +#define VXGE_HW_MSG_ERR_REG_MP_MXP_DTAG_DB_ERR vxge_mBIT(43) +#define VXGE_HW_MSG_ERR_REG_MP_MXP_ITAG_DB_ERR vxge_mBIT(45) +#define VXGE_HW_MSG_ERR_REG_UP_UXP_TRACE_DB_ERR vxge_mBIT(47) +#define VXGE_HW_MSG_ERR_REG_MP_MXP_TRACE_DB_ERR vxge_mBIT(48) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_CMG2MSG_DB_ERR vxge_mBIT(49) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_TXPE2MSG_DB_ERR vxge_mBIT(50) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_RXPE2MSG_DB_ERR vxge_mBIT(51) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_RPE2MSG_DB_ERR vxge_mBIT(52) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_REG_READ_FIFO_ERR vxge_mBIT(53) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_MXP2UXP_FIFO_ERR vxge_mBIT(54) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_KDFC_SIF_FIFO_ERR vxge_mBIT(55) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_CXP2SWIF_FIFO_ERR vxge_mBIT(56) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_UMQ_DB_ERR vxge_mBIT(57) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_PF_DB_ERR vxge_mBIT(58) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_BWR_SIF_FIFO_ERR vxge_mBIT(59) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_DMQ_ECC_DB_ERR vxge_mBIT(60) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_READ_FIFO_ERR vxge_mBIT(61) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_DMA_RESP_ECC_DB_ERR vxge_mBIT(62) +#define VXGE_HW_MSG_ERR_REG_MSG_QUE_UXP2MXP_FIFO_ERR vxge_mBIT(63) +/*0x05230*/ u64 msg_err_mask; +/*0x05238*/ u64 msg_err_alarm; + u8 unused05340[0x05340-0x05240]; + +/*0x05340*/ u64 msg_exc_reg; +#define VXGE_HW_MSG_EXC_REG_MP_MXP_CAUSE_INFO_INT vxge_mBIT(50) +#define VXGE_HW_MSG_EXC_REG_MP_MXP_CAUSE_CRIT_INT vxge_mBIT(51) +#define VXGE_HW_MSG_EXC_REG_UP_UXP_CAUSE_INFO_INT vxge_mBIT(54) +#define VXGE_HW_MSG_EXC_REG_UP_UXP_CAUSE_CRIT_INT vxge_mBIT(55) +#define VXGE_HW_MSG_EXC_REG_MP_MXP_SERR vxge_mBIT(62) +#define VXGE_HW_MSG_EXC_REG_UP_UXP_SERR vxge_mBIT(63) +/*0x05348*/ u64 msg_exc_mask; +/*0x05350*/ u64 msg_exc_alarm; +/*0x05358*/ u64 msg_exc_cause; +#define VXGE_HW_MSG_EXC_CAUSE_MP_MXP(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_MSG_EXC_CAUSE_UP_UXP(val) vxge_vBIT(val, 32, 32) + u8 unused05368[0x05380-0x05360]; + +/*0x05380*/ u64 msg_err2_reg; +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_CMG2MSG_DISPATCH_FSM_INTEGRITY_ERR \ + vxge_mBIT(0) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_DMQ_DISPATCH_FSM_INTEGRITY_ERR \ + vxge_mBIT(1) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIF_DISPATCH_FSM_INTEGRITY_ERR \ + vxge_mBIT(2) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_PIC_WRITE_FSM_INTEGRITY_ERR \ + vxge_mBIT(3) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIFREG_FSM_INTEGRITY_ERR vxge_mBIT(4) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_TIM_WRITE_FSM_INTEGRITY_ERR \ + vxge_mBIT(5) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_UMQ_TA_FSM_INTEGRITY_ERR vxge_mBIT(6) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_TXPE_TA_FSM_INTEGRITY_ERR vxge_mBIT(7) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_RXPE_TA_FSM_INTEGRITY_ERR vxge_mBIT(8) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_SWIF_TA_FSM_INTEGRITY_ERR vxge_mBIT(9) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_DMA_TA_FSM_INTEGRITY_ERR vxge_mBIT(10) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_CP_TA_FSM_INTEGRITY_ERR vxge_mBIT(11) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA16_FSM_INTEGRITY_ERR \ + vxge_mBIT(12) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA15_FSM_INTEGRITY_ERR \ + vxge_mBIT(13) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA14_FSM_INTEGRITY_ERR \ + vxge_mBIT(14) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA13_FSM_INTEGRITY_ERR \ + vxge_mBIT(15) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA12_FSM_INTEGRITY_ERR \ + vxge_mBIT(16) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA11_FSM_INTEGRITY_ERR \ + vxge_mBIT(17) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA10_FSM_INTEGRITY_ERR \ + vxge_mBIT(18) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA9_FSM_INTEGRITY_ERR \ + vxge_mBIT(19) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA8_FSM_INTEGRITY_ERR \ + vxge_mBIT(20) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA7_FSM_INTEGRITY_ERR \ + vxge_mBIT(21) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA6_FSM_INTEGRITY_ERR \ + vxge_mBIT(22) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA5_FSM_INTEGRITY_ERR \ + vxge_mBIT(23) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA4_FSM_INTEGRITY_ERR \ + vxge_mBIT(24) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA3_FSM_INTEGRITY_ERR \ + vxge_mBIT(25) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA2_FSM_INTEGRITY_ERR \ + vxge_mBIT(26) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA1_FSM_INTEGRITY_ERR \ + vxge_mBIT(27) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_LONGTERMUMQ_TA0_FSM_INTEGRITY_ERR \ + vxge_mBIT(28) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_FBMC_OWN_FSM_INTEGRITY_ERR vxge_mBIT(29) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_TXPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \ + vxge_mBIT(30) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_RXPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \ + vxge_mBIT(31) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_RPE2MSG_DISPATCH_FSM_INTEGRITY_ERR \ + vxge_mBIT(32) +#define VXGE_HW_MSG_ERR2_REG_MP_MP_PIFT_IF_CREDIT_CNT_ERR vxge_mBIT(33) +#define VXGE_HW_MSG_ERR2_REG_UP_UP_PIFT_IF_CREDIT_CNT_ERR vxge_mBIT(34) +#define VXGE_HW_MSG_ERR2_REG_MSG_QUE_UMQ2PIC_CMD_FIFO_ERR vxge_mBIT(62) +#define VXGE_HW_MSG_ERR2_REG_TIM_TIM2MSG_CMD_FIFO_ERR vxge_mBIT(63) +/*0x05388*/ u64 msg_err2_mask; +/*0x05390*/ u64 msg_err2_alarm; +/*0x05398*/ u64 msg_err3_reg; +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR0 vxge_mBIT(0) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR1 vxge_mBIT(1) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR2 vxge_mBIT(2) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR3 vxge_mBIT(3) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR4 vxge_mBIT(4) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR5 vxge_mBIT(5) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR6 vxge_mBIT(6) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_SG_ERR7 vxge_mBIT(7) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_SG_ERR0 vxge_mBIT(8) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_SG_ERR1 vxge_mBIT(9) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR0 vxge_mBIT(16) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR1 vxge_mBIT(17) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR2 vxge_mBIT(18) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR3 vxge_mBIT(19) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR4 vxge_mBIT(20) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR5 vxge_mBIT(21) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR6 vxge_mBIT(22) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_SG_ERR7 vxge_mBIT(23) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_SG_ERR0 vxge_mBIT(24) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_SG_ERR1 vxge_mBIT(25) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR0 vxge_mBIT(32) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR1 vxge_mBIT(33) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR2 vxge_mBIT(34) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR3 vxge_mBIT(35) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR4 vxge_mBIT(36) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR5 vxge_mBIT(37) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR6 vxge_mBIT(38) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_DCACHE_DB_ERR7 vxge_mBIT(39) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_DB_ERR0 vxge_mBIT(40) +#define VXGE_HW_MSG_ERR3_REG_UP_UXP_ICACHE_DB_ERR1 vxge_mBIT(41) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR0 vxge_mBIT(48) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR1 vxge_mBIT(49) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR2 vxge_mBIT(50) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR3 vxge_mBIT(51) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR4 vxge_mBIT(52) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR5 vxge_mBIT(53) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR6 vxge_mBIT(54) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_DCACHE_DB_ERR7 vxge_mBIT(55) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_DB_ERR0 vxge_mBIT(56) +#define VXGE_HW_MSG_ERR3_REG_MP_MXP_ICACHE_DB_ERR1 vxge_mBIT(57) +/*0x053a0*/ u64 msg_err3_mask; +/*0x053a8*/ u64 msg_err3_alarm; + u8 unused05600[0x05600-0x053b0]; + +/*0x05600*/ u64 fau_gen_err_reg; +#define VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT0_PERMANENT_STOP vxge_mBIT(3) +#define VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT1_PERMANENT_STOP vxge_mBIT(7) +#define VXGE_HW_FAU_GEN_ERR_REG_FMPF_PORT2_PERMANENT_STOP vxge_mBIT(11) +#define VXGE_HW_FAU_GEN_ERR_REG_FALR_AUTO_LRO_NOTIFICATION vxge_mBIT(15) +/*0x05608*/ u64 fau_gen_err_mask; +/*0x05610*/ u64 fau_gen_err_alarm; +/*0x05618*/ u64 fau_ecc_err_reg; +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_N_SG_ERR vxge_mBIT(0) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_N_DB_ERR vxge_mBIT(1) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_W_SG_ERR(val) \ + vxge_vBIT(val, 2, 2) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT0_FAU_MAC2F_W_DB_ERR(val) \ + vxge_vBIT(val, 4, 2) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_N_SG_ERR vxge_mBIT(6) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_N_DB_ERR vxge_mBIT(7) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_W_SG_ERR(val) \ + vxge_vBIT(val, 8, 2) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT1_FAU_MAC2F_W_DB_ERR(val) \ + vxge_vBIT(val, 10, 2) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_N_SG_ERR vxge_mBIT(12) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_N_DB_ERR vxge_mBIT(13) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_W_SG_ERR(val) \ + vxge_vBIT(val, 14, 2) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_PORT2_FAU_MAC2F_W_DB_ERR(val) \ + vxge_vBIT(val, 16, 2) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_FAU_XFMD_INS_SG_ERR(val) \ + vxge_vBIT(val, 18, 2) +#define VXGE_HW_FAU_ECC_ERR_REG_FAU_FAU_XFMD_INS_DB_ERR(val) \ + vxge_vBIT(val, 20, 2) +#define VXGE_HW_FAU_ECC_ERR_REG_FAUJ_FAU_FSM_ERR vxge_mBIT(31) +/*0x05620*/ u64 fau_ecc_err_mask; +/*0x05628*/ u64 fau_ecc_err_alarm; + u8 unused05658[0x05658-0x05630]; +/*0x05658*/ u64 fau_pa_cfg; +#define VXGE_HW_FAU_PA_CFG_REPL_L4_COMP_CSUM vxge_mBIT(3) +#define VXGE_HW_FAU_PA_CFG_REPL_L3_INCL_CF vxge_mBIT(7) +#define VXGE_HW_FAU_PA_CFG_REPL_L3_COMP_CSUM vxge_mBIT(11) + u8 unused05668[0x05668-0x05660]; + +/*0x05668*/ u64 dbg_stats_fau_rx_path; +#define VXGE_HW_DBG_STATS_FAU_RX_PATH_RX_PERMITTED_FRMS(val) \ + vxge_vBIT(val, 32, 32) + u8 unused056c0[0x056c0-0x05670]; + +/*0x056c0*/ u64 fau_lag_cfg; +#define VXGE_HW_FAU_LAG_CFG_COLL_ALG(val) vxge_vBIT(val, 2, 2) +#define VXGE_HW_FAU_LAG_CFG_INCR_RX_AGGR_STATS vxge_mBIT(7) + u8 unused05800[0x05800-0x056c8]; + +/*0x05800*/ u64 tpa_int_status; +#define VXGE_HW_TPA_INT_STATUS_ORP_ERR_ORP_INT vxge_mBIT(15) +#define VXGE_HW_TPA_INT_STATUS_PTM_ALARM_PTM_INT vxge_mBIT(23) +#define VXGE_HW_TPA_INT_STATUS_TPA_ERROR_TPA_INT vxge_mBIT(31) +/*0x05808*/ u64 tpa_int_mask; +/*0x05810*/ u64 orp_err_reg; +#define VXGE_HW_ORP_ERR_REG_ORP_FIFO_SG_ERR vxge_mBIT(3) +#define VXGE_HW_ORP_ERR_REG_ORP_FIFO_DB_ERR vxge_mBIT(7) +#define VXGE_HW_ORP_ERR_REG_ORP_XFMD_FIFO_UFLOW_ERR vxge_mBIT(11) +#define VXGE_HW_ORP_ERR_REG_ORP_FRM_FIFO_UFLOW_ERR vxge_mBIT(15) +#define VXGE_HW_ORP_ERR_REG_ORP_XFMD_RCV_FSM_ERR vxge_mBIT(19) +#define VXGE_HW_ORP_ERR_REG_ORP_OUTREAD_FSM_ERR vxge_mBIT(23) +#define VXGE_HW_ORP_ERR_REG_ORP_OUTQEM_FSM_ERR vxge_mBIT(27) +#define VXGE_HW_ORP_ERR_REG_ORP_XFMD_RCV_SHADOW_ERR vxge_mBIT(31) +#define VXGE_HW_ORP_ERR_REG_ORP_OUTREAD_SHADOW_ERR vxge_mBIT(35) +#define VXGE_HW_ORP_ERR_REG_ORP_OUTQEM_SHADOW_ERR vxge_mBIT(39) +#define VXGE_HW_ORP_ERR_REG_ORP_OUTFRM_SHADOW_ERR vxge_mBIT(43) +#define VXGE_HW_ORP_ERR_REG_ORP_OPTPRS_SHADOW_ERR vxge_mBIT(47) +/*0x05818*/ u64 orp_err_mask; +/*0x05820*/ u64 orp_err_alarm; +/*0x05828*/ u64 ptm_alarm_reg; +#define VXGE_HW_PTM_ALARM_REG_PTM_RDCTRL_SYNC_ERR vxge_mBIT(3) +#define VXGE_HW_PTM_ALARM_REG_PTM_RDCTRL_FIFO_ERR vxge_mBIT(7) +#define VXGE_HW_PTM_ALARM_REG_XFMD_RD_FIFO_ERR vxge_mBIT(11) +#define VXGE_HW_PTM_ALARM_REG_WDE2MSR_WR_FIFO_ERR vxge_mBIT(15) +#define VXGE_HW_PTM_ALARM_REG_PTM_FRMM_ECC_DB_ERR(val) vxge_vBIT(val, 18, 2) +#define VXGE_HW_PTM_ALARM_REG_PTM_FRMM_ECC_SG_ERR(val) vxge_vBIT(val, 22, 2) +/*0x05830*/ u64 ptm_alarm_mask; +/*0x05838*/ u64 ptm_alarm_alarm; +/*0x05840*/ u64 tpa_error_reg; +#define VXGE_HW_TPA_ERROR_REG_TPA_FSM_ERR_ALARM vxge_mBIT(3) +#define VXGE_HW_TPA_ERROR_REG_TPA_TPA_DA_LKUP_PRT0_DB_ERR vxge_mBIT(7) +#define VXGE_HW_TPA_ERROR_REG_TPA_TPA_DA_LKUP_PRT0_SG_ERR vxge_mBIT(11) +/*0x05848*/ u64 tpa_error_mask; +/*0x05850*/ u64 tpa_error_alarm; +/*0x05858*/ u64 tpa_global_cfg; +#define VXGE_HW_TPA_GLOBAL_CFG_SUPPORT_SNAP_AB_N vxge_mBIT(7) +#define VXGE_HW_TPA_GLOBAL_CFG_ECC_ENABLE_N vxge_mBIT(35) + u8 unused05868[0x05870-0x05860]; + +/*0x05870*/ u64 ptm_ecc_cfg; +#define VXGE_HW_PTM_ECC_CFG_PTM_FRMM_ECC_EN_N vxge_mBIT(3) +/*0x05878*/ u64 ptm_phase_cfg; +#define VXGE_HW_PTM_PHASE_CFG_FRMM_WR_PHASE_EN vxge_mBIT(3) +#define VXGE_HW_PTM_PHASE_CFG_FRMM_RD_PHASE_EN vxge_mBIT(7) + u8 unused05898[0x05898-0x05880]; + +/*0x05898*/ u64 dbg_stats_tpa_tx_path; +#define VXGE_HW_DBG_STATS_TPA_TX_PATH_TX_PERMITTED_FRMS(val) \ + vxge_vBIT(val, 32, 32) + u8 unused05900[0x05900-0x058a0]; + +/*0x05900*/ u64 tmac_int_status; +#define VXGE_HW_TMAC_INT_STATUS_TXMAC_GEN_ERR_TXMAC_GEN_INT vxge_mBIT(3) +#define VXGE_HW_TMAC_INT_STATUS_TXMAC_ECC_ERR_TXMAC_ECC_INT vxge_mBIT(7) +/*0x05908*/ u64 tmac_int_mask; +/*0x05910*/ u64 txmac_gen_err_reg; +#define VXGE_HW_TXMAC_GEN_ERR_REG_TMACJ_PERMANENT_STOP vxge_mBIT(3) +#define VXGE_HW_TXMAC_GEN_ERR_REG_TMACJ_NO_VALID_VSPORT vxge_mBIT(7) +/*0x05918*/ u64 txmac_gen_err_mask; +/*0x05920*/ u64 txmac_gen_err_alarm; +/*0x05928*/ u64 txmac_ecc_err_reg; +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2MAC_SG_ERR vxge_mBIT(3) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2MAC_DB_ERR vxge_mBIT(7) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_SB_SG_ERR vxge_mBIT(11) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_SB_DB_ERR vxge_mBIT(15) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_DA_SG_ERR vxge_mBIT(19) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMAC_TPA2M_DA_DB_ERR vxge_mBIT(23) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT0_FSM_ERR vxge_mBIT(27) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT1_FSM_ERR vxge_mBIT(31) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMAC_TMAC_PORT2_FSM_ERR vxge_mBIT(35) +#define VXGE_HW_TXMAC_ECC_ERR_REG_TMACJ_TMACJ_FSM_ERR vxge_mBIT(39) +/*0x05930*/ u64 txmac_ecc_err_mask; +/*0x05938*/ u64 txmac_ecc_err_alarm; + u8 unused05978[0x05978-0x05940]; + +/*0x05978*/ u64 dbg_stat_tx_any_frms; +#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT0_TX_ANY_FRMS(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT1_TX_ANY_FRMS(val) vxge_vBIT(val, 8, 8) +#define VXGE_HW_DBG_STAT_TX_ANY_FRMS_PORT2_TX_ANY_FRMS(val) \ + vxge_vBIT(val, 16, 8) + u8 unused059a0[0x059a0-0x05980]; + +/*0x059a0*/ u64 txmac_link_util_port[3]; +#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_UTILIZATION(val) \ + vxge_vBIT(val, 1, 7) +#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_UTIL_CFG(val) vxge_vBIT(val, 8, 4) +#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_FRAC_UTIL(val) \ + vxge_vBIT(val, 12, 4) +#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_PKT_WEIGHT(val) vxge_vBIT(val, 16, 4) +#define VXGE_HW_TXMAC_LINK_UTIL_PORT_TMAC_TMAC_SCALE_FACTOR vxge_mBIT(23) +/*0x059b8*/ u64 txmac_cfg0_port[3]; +#define VXGE_HW_TXMAC_CFG0_PORT_TMAC_EN vxge_mBIT(3) +#define VXGE_HW_TXMAC_CFG0_PORT_APPEND_PAD vxge_mBIT(7) +#define VXGE_HW_TXMAC_CFG0_PORT_PAD_BYTE(val) vxge_vBIT(val, 8, 8) +/*0x059d0*/ u64 txmac_cfg1_port[3]; +#define VXGE_HW_TXMAC_CFG1_PORT_AVG_IPG(val) vxge_vBIT(val, 40, 8) +/*0x059e8*/ u64 txmac_status_port[3]; +#define VXGE_HW_TXMAC_STATUS_PORT_TMAC_TX_FRM_SENT vxge_mBIT(3) + u8 unused05a20[0x05a20-0x05a00]; + +/*0x05a20*/ u64 lag_distrib_dest; +#define VXGE_HW_LAG_DISTRIB_DEST_MAP_VPATH(n) vxge_mBIT(n) +/*0x05a28*/ u64 lag_marker_cfg; +#define VXGE_HW_LAG_MARKER_CFG_GEN_RCVR_EN vxge_mBIT(3) +#define VXGE_HW_LAG_MARKER_CFG_RESP_EN vxge_mBIT(7) +#define VXGE_HW_LAG_MARKER_CFG_RESP_TIMEOUT(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_LAG_MARKER_CFG_SLOW_PROTO_MRKR_MIN_INTERVAL(val) \ + vxge_vBIT(val, 32, 16) +#define VXGE_HW_LAG_MARKER_CFG_THROTTLE_MRKR_RESP vxge_mBIT(51) +/*0x05a30*/ u64 lag_tx_cfg; +#define VXGE_HW_LAG_TX_CFG_INCR_TX_AGGR_STATS vxge_mBIT(3) +#define VXGE_HW_LAG_TX_CFG_DISTRIB_ALG_SEL(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_LAG_TX_CFG_DISTRIB_REMAP_IF_FAIL vxge_mBIT(11) +#define VXGE_HW_LAG_TX_CFG_COLL_MAX_DELAY(val) vxge_vBIT(val, 16, 16) +/*0x05a38*/ u64 lag_tx_status; +#define VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_EMPTIED_LINK(val) \ + vxge_vBIT(val, 0, 8) +#define VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_SLOW_PROTO_MRKR(val) \ + vxge_vBIT(val, 8, 8) +#define VXGE_HW_LAG_TX_STATUS_TLAG_TIMER_VAL_SLOW_PROTO_MRKRRESP(val) \ + vxge_vBIT(val, 16, 8) + u8 unused05d48[0x05d48-0x05a40]; + +/*0x05d48*/ u64 srpcim_to_mrpcim_vplane_rmsg[17]; +#define \ +VXGE_HAL_SRPCIM_TO_MRPCIM_VPLANE_RMSG_SWIF_SRPCIM_TO_MRPCIM_VPLANE_RMSG(val)\ + vxge_vBIT(val, 0, 64) + u8 unused06420[0x06420-0x05dd0]; + +/*0x06420*/ u64 mrpcim_to_srpcim_vplane_wmsg[17]; +#define VXGE_HW_MRPCIM_TO_SRPCIM_VPLANE_WMSG_MRPCIM_TO_SRPCIM_VPLANE_WMSG(val) \ + vxge_vBIT(val, 0, 64) +/*0x064a8*/ u64 mrpcim_to_srpcim_vplane_wmsg_trig[17]; + +/*0x06530*/ u64 debug_stats0; +#define VXGE_HW_DEBUG_STATS0_RSTDROP_MSG(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_DEBUG_STATS0_RSTDROP_CPL(val) vxge_vBIT(val, 32, 32) +/*0x06538*/ u64 debug_stats1; +#define VXGE_HW_DEBUG_STATS1_RSTDROP_CLIENT0(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_DEBUG_STATS1_RSTDROP_CLIENT1(val) vxge_vBIT(val, 32, 32) +/*0x06540*/ u64 debug_stats2; +#define VXGE_HW_DEBUG_STATS2_RSTDROP_CLIENT2(val) vxge_vBIT(val, 0, 32) +/*0x06548*/ u64 debug_stats3_vplane[17]; +#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_PH(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_NPH(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_DEBUG_STATS3_VPLANE_DEPL_CPLH(val) vxge_vBIT(val, 32, 16) +/*0x065d0*/ u64 debug_stats4_vplane[17]; +#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_PD(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_NPD(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_DEBUG_STATS4_VPLANE_DEPL_CPLD(val) vxge_vBIT(val, 32, 16) + + u8 unused07000[0x07000-0x06658]; + +/*0x07000*/ u64 mrpcim_general_int_status; +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PIC_INT vxge_mBIT(0) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCI_INT vxge_mBIT(1) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_RTDMA_INT vxge_mBIT(2) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_WRDMA_INT vxge_mBIT(3) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMCT_INT vxge_mBIT(4) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG1_INT vxge_mBIT(5) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG2_INT vxge_mBIT(6) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_GCMG3_INT vxge_mBIT(7) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMIFL_INT vxge_mBIT(8) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3CMIFU_INT vxge_mBIT(9) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG1_INT vxge_mBIT(10) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG2_INT vxge_mBIT(11) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_PCMG3_INT vxge_mBIT(12) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_XMAC_INT vxge_mBIT(13) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_RXMAC_INT vxge_mBIT(14) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_TMAC_INT vxge_mBIT(15) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3FBIF_INT vxge_mBIT(16) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_FBMC_INT vxge_mBIT(17) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_G3FBCT_INT vxge_mBIT(18) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_TPA_INT vxge_mBIT(19) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_DRBELL_INT vxge_mBIT(20) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_ONE_INT vxge_mBIT(21) +#define VXGE_HW_MRPCIM_GENERAL_INT_STATUS_MSG_INT vxge_mBIT(22) +/*0x07008*/ u64 mrpcim_general_int_mask; +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_PIC_INT vxge_mBIT(0) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCI_INT vxge_mBIT(1) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_RTDMA_INT vxge_mBIT(2) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_WRDMA_INT vxge_mBIT(3) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMCT_INT vxge_mBIT(4) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG1_INT vxge_mBIT(5) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG2_INT vxge_mBIT(6) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_GCMG3_INT vxge_mBIT(7) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMIFL_INT vxge_mBIT(8) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3CMIFU_INT vxge_mBIT(9) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG1_INT vxge_mBIT(10) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG2_INT vxge_mBIT(11) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_PCMG3_INT vxge_mBIT(12) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_XMAC_INT vxge_mBIT(13) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_RXMAC_INT vxge_mBIT(14) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_TMAC_INT vxge_mBIT(15) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3FBIF_INT vxge_mBIT(16) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_FBMC_INT vxge_mBIT(17) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_G3FBCT_INT vxge_mBIT(18) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_TPA_INT vxge_mBIT(19) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_DRBELL_INT vxge_mBIT(20) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_ONE_INT vxge_mBIT(21) +#define VXGE_HW_MRPCIM_GENERAL_INT_MASK_MSG_INT vxge_mBIT(22) +/*0x07010*/ u64 mrpcim_ppif_int_status; +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_INI_ERRORS_INI_INT vxge_mBIT(3) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_DMA_ERRORS_DMA_INT vxge_mBIT(7) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_TGT_ERRORS_TGT_INT vxge_mBIT(11) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CONFIG_ERRORS_CONFIG_INT vxge_mBIT(15) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_CRDT_INT vxge_mBIT(19) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_PLL_ERRORS_PLL_INT vxge_mBIT(27) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE0_CRD_INT_VPLANE0_INT\ + vxge_mBIT(31) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE1_CRD_INT_VPLANE1_INT\ + vxge_mBIT(32) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE2_CRD_INT_VPLANE2_INT\ + vxge_mBIT(33) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE3_CRD_INT_VPLANE3_INT\ + vxge_mBIT(34) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE4_CRD_INT_VPLANE4_INT\ + vxge_mBIT(35) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE5_CRD_INT_VPLANE5_INT\ + vxge_mBIT(36) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE6_CRD_INT_VPLANE6_INT\ + vxge_mBIT(37) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE7_CRD_INT_VPLANE7_INT\ + vxge_mBIT(38) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE8_CRD_INT_VPLANE8_INT\ + vxge_mBIT(39) +#define VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE9_CRD_INT_VPLANE9_INT\ + vxge_mBIT(40) +#define \ +VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE10_CRD_INT_VPLANE10_INT \ + vxge_mBIT(41) +#define \ +VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE11_CRD_INT_VPLANE11_INT \ + vxge_mBIT(42) +#define \ +VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE12_CRD_INT_VPLANE12_INT \ + vxge_mBIT(43) +#define \ +VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE13_CRD_INT_VPLANE13_INT \ + vxge_mBIT(44) +#define \ +VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE14_CRD_INT_VPLANE14_INT \ + vxge_mBIT(45) +#define \ +VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE15_CRD_INT_VPLANE15_INT \ + vxge_mBIT(46) +#define \ +VXGE_HW_MRPCIM_PPIF_INT_STATUS_CRDT_ERRORS_VPLANE16_CRD_INT_VPLANE16_INT \ + vxge_mBIT(47) +#define \ +VXGE_HW_MRPCIM_PPIF_INT_STATUS_VPATH_TO_MRPCIM_ALARM_VPATH_TO_MRPCIM_ALARM_INT \ + vxge_mBIT(55) +/*0x07018*/ u64 mrpcim_ppif_int_mask; + u8 unused07028[0x07028-0x07020]; + +/*0x07028*/ u64 ini_errors_reg; +#define VXGE_HW_INI_ERRORS_REG_SCPL_CPL_TIMEOUT_UNUSED_TAG vxge_mBIT(3) +#define VXGE_HW_INI_ERRORS_REG_SCPL_CPL_TIMEOUT vxge_mBIT(7) +#define VXGE_HW_INI_ERRORS_REG_DCPL_FSM_ERR vxge_mBIT(11) +#define VXGE_HW_INI_ERRORS_REG_DCPL_POISON vxge_mBIT(12) +#define VXGE_HW_INI_ERRORS_REG_DCPL_UNSUPPORTED vxge_mBIT(15) +#define VXGE_HW_INI_ERRORS_REG_DCPL_ABORT vxge_mBIT(19) +#define VXGE_HW_INI_ERRORS_REG_INI_TLP_ABORT vxge_mBIT(23) +#define VXGE_HW_INI_ERRORS_REG_INI_DLLP_ABORT vxge_mBIT(27) +#define VXGE_HW_INI_ERRORS_REG_INI_ECRC_ERR vxge_mBIT(31) +#define VXGE_HW_INI_ERRORS_REG_INI_BUF_DB_ERR vxge_mBIT(35) +#define VXGE_HW_INI_ERRORS_REG_INI_BUF_SG_ERR vxge_mBIT(39) +#define VXGE_HW_INI_ERRORS_REG_INI_DATA_OVERFLOW vxge_mBIT(43) +#define VXGE_HW_INI_ERRORS_REG_INI_HDR_OVERFLOW vxge_mBIT(47) +#define VXGE_HW_INI_ERRORS_REG_INI_MRD_SYS_DROP vxge_mBIT(51) +#define VXGE_HW_INI_ERRORS_REG_INI_MWR_SYS_DROP vxge_mBIT(55) +#define VXGE_HW_INI_ERRORS_REG_INI_MRD_CLIENT_DROP vxge_mBIT(59) +#define VXGE_HW_INI_ERRORS_REG_INI_MWR_CLIENT_DROP vxge_mBIT(63) +/*0x07030*/ u64 ini_errors_mask; +/*0x07038*/ u64 ini_errors_alarm; +/*0x07040*/ u64 dma_errors_reg; +#define VXGE_HW_DMA_ERRORS_REG_RDARB_FSM_ERR vxge_mBIT(3) +#define VXGE_HW_DMA_ERRORS_REG_WRARB_FSM_ERR vxge_mBIT(7) +#define VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_HDR_OVERFLOW vxge_mBIT(8) +#define VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_HDR_UNDERFLOW vxge_mBIT(9) +#define VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_DATA_OVERFLOW vxge_mBIT(10) +#define VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_WR_DATA_UNDERFLOW vxge_mBIT(11) +#define VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_HDR_OVERFLOW vxge_mBIT(12) +#define VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_HDR_UNDERFLOW vxge_mBIT(13) +#define VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_DATA_OVERFLOW vxge_mBIT(14) +#define VXGE_HW_DMA_ERRORS_REG_DMA_MSG_WR_DATA_UNDERFLOW vxge_mBIT(15) +#define VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_HDR_OVERFLOW vxge_mBIT(16) +#define VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_HDR_UNDERFLOW vxge_mBIT(17) +#define VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_DATA_OVERFLOW vxge_mBIT(18) +#define VXGE_HW_DMA_ERRORS_REG_DMA_STATS_WR_DATA_UNDERFLOW vxge_mBIT(19) +#define VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_HDR_OVERFLOW vxge_mBIT(20) +#define VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_HDR_UNDERFLOW vxge_mBIT(21) +#define VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_DATA_OVERFLOW vxge_mBIT(22) +#define VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_WR_DATA_UNDERFLOW vxge_mBIT(23) +#define VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_RD_HDR_OVERFLOW vxge_mBIT(24) +#define VXGE_HW_DMA_ERRORS_REG_DMA_WRDMA_RD_HDR_UNDERFLOW vxge_mBIT(25) +#define VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_RD_HDR_OVERFLOW vxge_mBIT(28) +#define VXGE_HW_DMA_ERRORS_REG_DMA_RTDMA_RD_HDR_UNDERFLOW vxge_mBIT(29) +#define VXGE_HW_DMA_ERRORS_REG_DBLGEN_FSM_ERR vxge_mBIT(32) +#define VXGE_HW_DMA_ERRORS_REG_DBLGEN_CREDIT_FSM_ERR vxge_mBIT(33) +#define VXGE_HW_DMA_ERRORS_REG_DBLGEN_DMA_WRR_SM_ERR vxge_mBIT(34) +/*0x07048*/ u64 dma_errors_mask; +/*0x07050*/ u64 dma_errors_alarm; +/*0x07058*/ u64 tgt_errors_reg; +#define VXGE_HW_TGT_ERRORS_REG_TGT_VENDOR_MSG vxge_mBIT(0) +#define VXGE_HW_TGT_ERRORS_REG_TGT_MSG_UNLOCK vxge_mBIT(1) +#define VXGE_HW_TGT_ERRORS_REG_TGT_ILLEGAL_TLP_BE vxge_mBIT(2) +#define VXGE_HW_TGT_ERRORS_REG_TGT_BOOT_WRITE vxge_mBIT(3) +#define VXGE_HW_TGT_ERRORS_REG_TGT_PIF_WR_CROSS_QWRANGE vxge_mBIT(4) +#define VXGE_HW_TGT_ERRORS_REG_TGT_PIF_READ_CROSS_QWRANGE vxge_mBIT(5) +#define VXGE_HW_TGT_ERRORS_REG_TGT_KDFC_READ vxge_mBIT(6) +#define VXGE_HW_TGT_ERRORS_REG_TGT_USDC_READ vxge_mBIT(7) +#define VXGE_HW_TGT_ERRORS_REG_TGT_USDC_WR_CROSS_QWRANGE vxge_mBIT(8) +#define VXGE_HW_TGT_ERRORS_REG_TGT_MSIX_BEYOND_RANGE vxge_mBIT(9) +#define VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_KDFC_POISON vxge_mBIT(10) +#define VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_USDC_POISON vxge_mBIT(11) +#define VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_PIF_POISON vxge_mBIT(12) +#define VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_MSIX_POISON vxge_mBIT(13) +#define VXGE_HW_TGT_ERRORS_REG_TGT_WR_TO_MRIOV_POISON vxge_mBIT(14) +#define VXGE_HW_TGT_ERRORS_REG_TGT_NOT_MEM_TLP vxge_mBIT(15) +#define VXGE_HW_TGT_ERRORS_REG_TGT_UNKNOWN_MEM_TLP vxge_mBIT(16) +#define VXGE_HW_TGT_ERRORS_REG_TGT_REQ_FSM_ERR vxge_mBIT(17) +#define VXGE_HW_TGT_ERRORS_REG_TGT_CPL_FSM_ERR vxge_mBIT(18) +#define VXGE_HW_TGT_ERRORS_REG_TGT_KDFC_PROT_ERR vxge_mBIT(19) +#define VXGE_HW_TGT_ERRORS_REG_TGT_SWIF_PROT_ERR vxge_mBIT(20) +#define VXGE_HW_TGT_ERRORS_REG_TGT_MRIOV_MEM_MAP_CFG_ERR vxge_mBIT(21) +/*0x07060*/ u64 tgt_errors_mask; +/*0x07068*/ u64 tgt_errors_alarm; +/*0x07070*/ u64 config_errors_reg; +#define VXGE_HW_CONFIG_ERRORS_REG_I2C_ILLEGAL_STOP_COND vxge_mBIT(3) +#define VXGE_HW_CONFIG_ERRORS_REG_I2C_ILLEGAL_START_COND vxge_mBIT(7) +#define VXGE_HW_CONFIG_ERRORS_REG_I2C_EXP_RD_CNT vxge_mBIT(11) +#define VXGE_HW_CONFIG_ERRORS_REG_I2C_EXTRA_CYCLE vxge_mBIT(15) +#define VXGE_HW_CONFIG_ERRORS_REG_I2C_MAIN_FSM_ERR vxge_mBIT(19) +#define VXGE_HW_CONFIG_ERRORS_REG_I2C_REQ_COLLISION vxge_mBIT(23) +#define VXGE_HW_CONFIG_ERRORS_REG_I2C_REG_FSM_ERR vxge_mBIT(27) +#define VXGE_HW_CONFIG_ERRORS_REG_CFGM_I2C_TIMEOUT vxge_mBIT(31) +#define VXGE_HW_CONFIG_ERRORS_REG_RIC_I2C_TIMEOUT vxge_mBIT(35) +#define VXGE_HW_CONFIG_ERRORS_REG_CFGM_FSM_ERR vxge_mBIT(39) +#define VXGE_HW_CONFIG_ERRORS_REG_RIC_FSM_ERR vxge_mBIT(43) +#define VXGE_HW_CONFIG_ERRORS_REG_PIFM_ILLEGAL_ACCESS vxge_mBIT(47) +#define VXGE_HW_CONFIG_ERRORS_REG_PIFM_TIMEOUT vxge_mBIT(51) +#define VXGE_HW_CONFIG_ERRORS_REG_PIFM_FSM_ERR vxge_mBIT(55) +#define VXGE_HW_CONFIG_ERRORS_REG_PIFM_TO_FSM_ERR vxge_mBIT(59) +#define VXGE_HW_CONFIG_ERRORS_REG_RIC_RIC_RD_TIMEOUT vxge_mBIT(63) +/*0x07078*/ u64 config_errors_mask; +/*0x07080*/ u64 config_errors_alarm; + u8 unused07090[0x07090-0x07088]; + +/*0x07090*/ u64 crdt_errors_reg; +#define VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_FSM_ERR vxge_mBIT(11) +#define VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_INTCTL_ILLEGAL_CRD_DEAL \ + vxge_mBIT(15) +#define VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_PDA_ILLEGAL_CRD_DEAL vxge_mBIT(19) +#define VXGE_HW_CRDT_ERRORS_REG_WRCRDTARB_PCI_MSG_ILLEGAL_CRD_DEAL \ + vxge_mBIT(23) +#define VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_FSM_ERR vxge_mBIT(35) +#define VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_RDA_ILLEGAL_CRD_DEAL vxge_mBIT(39) +#define VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_PDA_ILLEGAL_CRD_DEAL vxge_mBIT(43) +#define VXGE_HW_CRDT_ERRORS_REG_RDCRDTARB_DBLGEN_ILLEGAL_CRD_DEAL \ + vxge_mBIT(47) +/*0x07098*/ u64 crdt_errors_mask; +/*0x070a0*/ u64 crdt_errors_alarm; + u8 unused070b0[0x070b0-0x070a8]; + +/*0x070b0*/ u64 mrpcim_general_errors_reg; +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_STATSB_FSM_ERR vxge_mBIT(3) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_XGEN_FSM_ERR vxge_mBIT(7) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_XMEM_FSM_ERR vxge_mBIT(11) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_KDFCCTL_FSM_ERR vxge_mBIT(15) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_MRIOVCTL_FSM_ERR vxge_mBIT(19) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_FLSH_ERR vxge_mBIT(23) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_IIC_ACK_ERR vxge_mBIT(27) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_SPI_IIC_CHKSUM_ERR vxge_mBIT(31) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INI_SERR_DET vxge_mBIT(35) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INTCTL_MSIX_FSM_ERR vxge_mBIT(39) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_INTCTL_MSI_OVERFLOW vxge_mBIT(43) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_PPIF_PCI_NOT_FLUSH_DURING_SW_RESET \ + vxge_mBIT(47) +#define VXGE_HW_MRPCIM_GENERAL_ERRORS_REG_PPIF_SW_RESET_FSM_ERR vxge_mBIT(51) +/*0x070b8*/ u64 mrpcim_general_errors_mask; +/*0x070c0*/ u64 mrpcim_general_errors_alarm; + u8 unused070d0[0x070d0-0x070c8]; + +/*0x070d0*/ u64 pll_errors_reg; +#define VXGE_HW_PLL_ERRORS_REG_CORE_CMG_PLL_OOL vxge_mBIT(3) +#define VXGE_HW_PLL_ERRORS_REG_CORE_FB_PLL_OOL vxge_mBIT(7) +#define VXGE_HW_PLL_ERRORS_REG_CORE_X_PLL_OOL vxge_mBIT(11) +/*0x070d8*/ u64 pll_errors_mask; +/*0x070e0*/ u64 pll_errors_alarm; +/*0x070e8*/ u64 srpcim_to_mrpcim_alarm_reg; +#define VXGE_HW_SRPCIM_TO_MRPCIM_ALARM_REG_PPIF_SRPCIM_TO_MRPCIM_ALARM(val) \ + vxge_vBIT(val, 0, 17) +/*0x070f0*/ u64 srpcim_to_mrpcim_alarm_mask; +/*0x070f8*/ u64 srpcim_to_mrpcim_alarm_alarm; +/*0x07100*/ u64 vpath_to_mrpcim_alarm_reg; +#define VXGE_HW_VPATH_TO_MRPCIM_ALARM_REG_PPIF_VPATH_TO_MRPCIM_ALARM(val) \ + vxge_vBIT(val, 0, 17) +/*0x07108*/ u64 vpath_to_mrpcim_alarm_mask; +/*0x07110*/ u64 vpath_to_mrpcim_alarm_alarm; + u8 unused07128[0x07128-0x07118]; + +/*0x07128*/ u64 crdt_errors_vplane_reg[17]; +#define VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_H_CONSUME_CRDT_ERR \ + vxge_mBIT(3) +#define VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_D_CONSUME_CRDT_ERR \ + vxge_mBIT(7) +#define VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_H_RETURN_CRDT_ERR \ + vxge_mBIT(11) +#define VXGE_HW_CRDT_ERRORS_VPLANE_REG_WRCRDTARB_P_D_RETURN_CRDT_ERR \ + vxge_mBIT(15) +#define VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_NP_H_CONSUME_CRDT_ERR \ + vxge_mBIT(19) +#define VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_NP_H_RETURN_CRDT_ERR \ + vxge_mBIT(23) +#define VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_TAG_CONSUME_TAG_ERR \ + vxge_mBIT(27) +#define VXGE_HW_CRDT_ERRORS_VPLANE_REG_RDCRDTARB_TAG_RETURN_TAG_ERR \ + vxge_mBIT(31) +/*0x07130*/ u64 crdt_errors_vplane_mask[17]; +/*0x07138*/ u64 crdt_errors_vplane_alarm[17]; + u8 unused072f0[0x072f0-0x072c0]; + +/*0x072f0*/ u64 mrpcim_rst_in_prog; +#define VXGE_HW_MRPCIM_RST_IN_PROG_MRPCIM_RST_IN_PROG vxge_mBIT(7) +/*0x072f8*/ u64 mrpcim_reg_modified; +#define VXGE_HW_MRPCIM_REG_MODIFIED_MRPCIM_REG_MODIFIED vxge_mBIT(7) + + u8 unused07378[0x07378-0x07300]; + +/*0x07378*/ u64 write_arb_pending; +#define VXGE_HW_WRITE_ARB_PENDING_WRARB_WRDMA vxge_mBIT(3) +#define VXGE_HW_WRITE_ARB_PENDING_WRARB_RTDMA vxge_mBIT(7) +#define VXGE_HW_WRITE_ARB_PENDING_WRARB_MSG vxge_mBIT(11) +#define VXGE_HW_WRITE_ARB_PENDING_WRARB_STATSB vxge_mBIT(15) +#define VXGE_HW_WRITE_ARB_PENDING_WRARB_INTCTL vxge_mBIT(19) +/*0x07380*/ u64 read_arb_pending; +#define VXGE_HW_READ_ARB_PENDING_RDARB_WRDMA vxge_mBIT(3) +#define VXGE_HW_READ_ARB_PENDING_RDARB_RTDMA vxge_mBIT(7) +#define VXGE_HW_READ_ARB_PENDING_RDARB_DBLGEN vxge_mBIT(11) +/*0x07388*/ u64 dmaif_dmadbl_pending; +#define VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_WRDMA_WR vxge_mBIT(0) +#define VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_WRDMA_RD vxge_mBIT(1) +#define VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_RTDMA_WR vxge_mBIT(2) +#define VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_RTDMA_RD vxge_mBIT(3) +#define VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_MSG_WR vxge_mBIT(4) +#define VXGE_HW_DMAIF_DMADBL_PENDING_DMAIF_STATS_WR vxge_mBIT(5) +#define VXGE_HW_DMAIF_DMADBL_PENDING_DBLGEN_IN_PROG(val) \ + vxge_vBIT(val, 13, 51) +/*0x07390*/ u64 wrcrdtarb_status0_vplane[17]; +#define VXGE_HW_WRCRDTARB_STATUS0_VPLANE_WRCRDTARB_ABS_AVAIL_P_H(val) \ + vxge_vBIT(val, 0, 8) +/*0x07418*/ u64 wrcrdtarb_status1_vplane[17]; +#define VXGE_HW_WRCRDTARB_STATUS1_VPLANE_WRCRDTARB_ABS_AVAIL_P_D(val) \ + vxge_vBIT(val, 4, 12) + u8 unused07500[0x07500-0x074a0]; + +/*0x07500*/ u64 mrpcim_general_cfg1; +#define VXGE_HW_MRPCIM_GENERAL_CFG1_CLEAR_SERR vxge_mBIT(7) +/*0x07508*/ u64 mrpcim_general_cfg2; +#define VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_WR_TD vxge_mBIT(3) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_RD_TD vxge_mBIT(7) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_INS_TX_CPL_TD vxge_mBIT(11) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_INI_TIMEOUT_EN_MWR vxge_mBIT(15) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_INI_TIMEOUT_EN_MRD vxge_mBIT(19) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_IGNORE_VPATH_RST_FOR_MSIX vxge_mBIT(23) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_FLASH_READ_MSB vxge_mBIT(27) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_DIS_HOST_PIPELINE_WR vxge_mBIT(31) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_MRPCIM_STATS_ENABLE vxge_mBIT(43) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_MRPCIM_STATS_MAP_TO_VPATH(val) \ + vxge_vBIT(val, 47, 5) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_EN_BLOCK_MSIX_DUE_TO_SERR vxge_mBIT(55) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_FORCE_SENDING_INTA vxge_mBIT(59) +#define VXGE_HW_MRPCIM_GENERAL_CFG2_DIS_SWIF_PROT_ON_RDS vxge_mBIT(63) +/*0x07510*/ u64 mrpcim_general_cfg3; +#define VXGE_HW_MRPCIM_GENERAL_CFG3_PROTECTION_CA_OR_UNSUPN vxge_mBIT(0) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_ILLEGAL_RD_CA_OR_UNSUPN vxge_mBIT(3) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_RD_BYTE_SWAPEN vxge_mBIT(7) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_RD_BIT_FLIPEN vxge_mBIT(11) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_WR_BYTE_SWAPEN vxge_mBIT(15) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_WR_BIT_FLIPEN vxge_mBIT(19) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_MR_MAX_MVFS(val) vxge_vBIT(val, 20, 16) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_MR_MVF_TBL_SIZE(val) \ + vxge_vBIT(val, 36, 16) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_PF0_SW_RESET_EN vxge_mBIT(55) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_REG_MODIFIED_CFG(val) vxge_vBIT(val, 56, 2) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_CPL_ECC_ENABLE_N vxge_mBIT(59) +#define VXGE_HW_MRPCIM_GENERAL_CFG3_BYPASS_DAISY_CHAIN vxge_mBIT(63) +/*0x07518*/ u64 mrpcim_stats_start_host_addr; +#define VXGE_HW_MRPCIM_STATS_START_HOST_ADDR_MRPCIM_STATS_START_HOST_ADDR(val)\ + vxge_vBIT(val, 0, 57) + + u8 unused07950[0x07950-0x07520]; + +/*0x07950*/ u64 rdcrdtarb_cfg0; +#define VXGE_HW_RDCRDTARB_CFG0_RDA_MAX_OUTSTANDING_RDS(val) \ + vxge_vBIT(val, 18, 6) +#define VXGE_HW_RDCRDTARB_CFG0_PDA_MAX_OUTSTANDING_RDS(val) \ + vxge_vBIT(val, 26, 6) +#define VXGE_HW_RDCRDTARB_CFG0_DBLGEN_MAX_OUTSTANDING_RDS(val) \ + vxge_vBIT(val, 34, 6) +#define VXGE_HW_RDCRDTARB_CFG0_WAIT_CNT(val) vxge_vBIT(val, 48, 4) +#define VXGE_HW_RDCRDTARB_CFG0_MAX_OUTSTANDING_RDS(val) vxge_vBIT(val, 54, 6) +#define VXGE_HW_RDCRDTARB_CFG0_EN_XON vxge_mBIT(63) + u8 unused07be8[0x07be8-0x07958]; + +/*0x07be8*/ u64 bf_sw_reset; +#define VXGE_HW_BF_SW_RESET_BF_SW_RESET(val) vxge_vBIT(val, 0, 8) +/*0x07bf0*/ u64 sw_reset_status; +#define VXGE_HW_SW_RESET_STATUS_RESET_CMPLT vxge_mBIT(7) +#define VXGE_HW_SW_RESET_STATUS_INIT_CMPLT vxge_mBIT(15) + u8 unused07d30[0x07d30-0x07bf8]; + +/*0x07d30*/ u64 mrpcim_debug_stats0; +#define VXGE_HW_MRPCIM_DEBUG_STATS0_INI_WR_DROP(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_MRPCIM_DEBUG_STATS0_INI_RD_DROP(val) vxge_vBIT(val, 32, 32) +/*0x07d38*/ u64 mrpcim_debug_stats1_vplane[17]; +#define VXGE_HW_MRPCIM_DEBUG_STATS1_VPLANE_WRCRDTARB_PH_CRDT_DEPLETED(val) \ + vxge_vBIT(val, 32, 32) +/*0x07dc0*/ u64 mrpcim_debug_stats2_vplane[17]; +#define VXGE_HW_MRPCIM_DEBUG_STATS2_VPLANE_WRCRDTARB_PD_CRDT_DEPLETED(val) \ + vxge_vBIT(val, 32, 32) +/*0x07e48*/ u64 mrpcim_debug_stats3_vplane[17]; +#define VXGE_HW_MRPCIM_DEBUG_STATS3_VPLANE_RDCRDTARB_NPH_CRDT_DEPLETED(val) \ + vxge_vBIT(val, 32, 32) +/*0x07ed0*/ u64 mrpcim_debug_stats4; +#define VXGE_HW_MRPCIM_DEBUG_STATS4_INI_WR_VPIN_DROP(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_MRPCIM_DEBUG_STATS4_INI_RD_VPIN_DROP(val) \ + vxge_vBIT(val, 32, 32) +/*0x07ed8*/ u64 genstats_count01; +#define VXGE_HW_GENSTATS_COUNT01_GENSTATS_COUNT1(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_GENSTATS_COUNT01_GENSTATS_COUNT0(val) vxge_vBIT(val, 32, 32) +/*0x07ee0*/ u64 genstats_count23; +#define VXGE_HW_GENSTATS_COUNT23_GENSTATS_COUNT3(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_GENSTATS_COUNT23_GENSTATS_COUNT2(val) vxge_vBIT(val, 32, 32) +/*0x07ee8*/ u64 genstats_count4; +#define VXGE_HW_GENSTATS_COUNT4_GENSTATS_COUNT4(val) vxge_vBIT(val, 32, 32) +/*0x07ef0*/ u64 genstats_count5; +#define VXGE_HW_GENSTATS_COUNT5_GENSTATS_COUNT5(val) vxge_vBIT(val, 32, 32) + + u8 unused07f08[0x07f08-0x07ef8]; + +/*0x07f08*/ u64 genstats_cfg[6]; +#define VXGE_HW_GENSTATS_CFG_DTYPE_SEL(val) vxge_vBIT(val, 3, 5) +#define VXGE_HW_GENSTATS_CFG_CLIENT_NO_SEL(val) vxge_vBIT(val, 9, 3) +#define VXGE_HW_GENSTATS_CFG_WR_RD_CPL_SEL(val) vxge_vBIT(val, 14, 2) +#define VXGE_HW_GENSTATS_CFG_VPATH_SEL(val) vxge_vBIT(val, 31, 17) +/*0x07f38*/ u64 genstat_64bit_cfg; +#define VXGE_HW_GENSTAT_64BIT_CFG_EN_FOR_GENSTATS0 vxge_mBIT(3) +#define VXGE_HW_GENSTAT_64BIT_CFG_EN_FOR_GENSTATS2 vxge_mBIT(7) + u8 unused08000[0x08000-0x07f40]; +/*0x08000*/ u64 gcmg3_int_status; +#define VXGE_HW_GCMG3_INT_STATUS_GSTC_ERR0_GSTC0_INT vxge_mBIT(0) +#define VXGE_HW_GCMG3_INT_STATUS_GSTC_ERR1_GSTC1_INT vxge_mBIT(1) +#define VXGE_HW_GCMG3_INT_STATUS_GH2L_ERR0_GH2L0_INT vxge_mBIT(2) +#define VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR_GH2L1_INT vxge_mBIT(3) +#define VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR2_GH2L2_INT vxge_mBIT(4) +#define VXGE_HW_GCMG3_INT_STATUS_GH2L_SMERR0_GH2L3_INT vxge_mBIT(5) +#define VXGE_HW_GCMG3_INT_STATUS_GHSQ_ERR3_GH2L4_INT vxge_mBIT(6) +/*0x08008*/ u64 gcmg3_int_mask; + u8 unused09000[0x09000-0x8010]; + +/*0x09000*/ u64 g3ifcmd_fb_int_status; +#define VXGE_HW_G3IFCMD_FB_INT_STATUS_ERR_G3IF_INT vxge_mBIT(0) +/*0x09008*/ u64 g3ifcmd_fb_int_mask; +/*0x09010*/ u64 g3ifcmd_fb_err_reg; +#define VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_CK_DLL_LOCK vxge_mBIT(6) +#define VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_SM_ERR vxge_mBIT(7) +#define VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \ + vxge_vBIT(val, 24, 8) +#define VXGE_HW_G3IFCMD_FB_ERR_REG_G3IF_IOCAL_FAULT vxge_mBIT(55) +/*0x09018*/ u64 g3ifcmd_fb_err_mask; +/*0x09020*/ u64 g3ifcmd_fb_err_alarm; + + u8 unused09400[0x09400-0x09028]; + +/*0x09400*/ u64 g3ifcmd_cmu_int_status; +#define VXGE_HW_G3IFCMD_CMU_INT_STATUS_ERR_G3IF_INT vxge_mBIT(0) +/*0x09408*/ u64 g3ifcmd_cmu_int_mask; +/*0x09410*/ u64 g3ifcmd_cmu_err_reg; +#define VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_CK_DLL_LOCK vxge_mBIT(6) +#define VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_SM_ERR vxge_mBIT(7) +#define VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \ + vxge_vBIT(val, 24, 8) +#define VXGE_HW_G3IFCMD_CMU_ERR_REG_G3IF_IOCAL_FAULT vxge_mBIT(55) +/*0x09418*/ u64 g3ifcmd_cmu_err_mask; +/*0x09420*/ u64 g3ifcmd_cmu_err_alarm; + + u8 unused09800[0x09800-0x09428]; + +/*0x09800*/ u64 g3ifcmd_cml_int_status; +#define VXGE_HW_G3IFCMD_CML_INT_STATUS_ERR_G3IF_INT vxge_mBIT(0) +/*0x09808*/ u64 g3ifcmd_cml_int_mask; +/*0x09810*/ u64 g3ifcmd_cml_err_reg; +#define VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_CK_DLL_LOCK vxge_mBIT(6) +#define VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_SM_ERR vxge_mBIT(7) +#define VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_RWDQS_DLL_LOCK(val) \ + vxge_vBIT(val, 24, 8) +#define VXGE_HW_G3IFCMD_CML_ERR_REG_G3IF_IOCAL_FAULT vxge_mBIT(55) +/*0x09818*/ u64 g3ifcmd_cml_err_mask; +/*0x09820*/ u64 g3ifcmd_cml_err_alarm; + u8 unused09b00[0x09b00-0x09828]; + +/*0x09b00*/ u64 vpath_to_vplane_map[17]; +#define VXGE_HW_VPATH_TO_VPLANE_MAP_VPATH_TO_VPLANE_MAP(val) \ + vxge_vBIT(val, 3, 5) + u8 unused09c30[0x09c30-0x09b88]; + +/*0x09c30*/ u64 xgxs_cfg_port[2]; +#define VXGE_HW_XGXS_CFG_PORT_SIG_DETECT_FORCE_LOS(val) vxge_vBIT(val, 16, 4) +#define VXGE_HW_XGXS_CFG_PORT_SIG_DETECT_FORCE_VALID(val) vxge_vBIT(val, 20, 4) +#define VXGE_HW_XGXS_CFG_PORT_SEL_INFO_0 vxge_mBIT(27) +#define VXGE_HW_XGXS_CFG_PORT_SEL_INFO_1(val) vxge_vBIT(val, 29, 3) +#define VXGE_HW_XGXS_CFG_PORT_TX_LANE0_SKEW(val) vxge_vBIT(val, 32, 4) +#define VXGE_HW_XGXS_CFG_PORT_TX_LANE1_SKEW(val) vxge_vBIT(val, 36, 4) +#define VXGE_HW_XGXS_CFG_PORT_TX_LANE2_SKEW(val) vxge_vBIT(val, 40, 4) +#define VXGE_HW_XGXS_CFG_PORT_TX_LANE3_SKEW(val) vxge_vBIT(val, 44, 4) +/*0x09c40*/ u64 xgxs_rxber_cfg_port[2]; +#define VXGE_HW_XGXS_RXBER_CFG_PORT_INTERVAL_DUR(val) vxge_vBIT(val, 0, 4) +#define VXGE_HW_XGXS_RXBER_CFG_PORT_RXGXS_INTERVAL_CNT(val) \ + vxge_vBIT(val, 16, 48) +/*0x09c50*/ u64 xgxs_rxber_status_port[2]; +#define VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_A_ERR_CNT(val) \ + vxge_vBIT(val, 0, 16) +#define VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_B_ERR_CNT(val) \ + vxge_vBIT(val, 16, 16) +#define VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_C_ERR_CNT(val) \ + vxge_vBIT(val, 32, 16) +#define VXGE_HW_XGXS_RXBER_STATUS_PORT_RXGXS_RXGXS_LANE_D_ERR_CNT(val) \ + vxge_vBIT(val, 48, 16) +/*0x09c60*/ u64 xgxs_status_port[2]; +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_TX_ACTIVITY(val) vxge_vBIT(val, 0, 4) +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_RX_ACTIVITY(val) vxge_vBIT(val, 4, 4) +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_CTC_FIFO_ERR BIT(11) +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_BYTE_SYNC_LOST(val) \ + vxge_vBIT(val, 12, 4) +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_CTC_ERR(val) vxge_vBIT(val, 16, 4) +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_ALIGNMENT_ERR vxge_mBIT(23) +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_DEC_ERR(val) vxge_vBIT(val, 24, 8) +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_SKIP_INS_REQ(val) \ + vxge_vBIT(val, 32, 4) +#define VXGE_HW_XGXS_STATUS_PORT_XMACJ_PCS_SKIP_DEL_REQ(val) \ + vxge_vBIT(val, 36, 4) +/*0x09c70*/ u64 xgxs_pma_reset_port[2]; +#define VXGE_HW_XGXS_PMA_RESET_PORT_SERDES_RESET(val) vxge_vBIT(val, 0, 8) + u8 unused09c90[0x09c90-0x09c80]; + +/*0x09c90*/ u64 xgxs_static_cfg_port[2]; +#define VXGE_HW_XGXS_STATIC_CFG_PORT_FW_CTRL_SERDES vxge_mBIT(3) + u8 unused09d40[0x09d40-0x09ca0]; + +/*0x09d40*/ u64 xgxs_info_port[2]; +#define VXGE_HW_XGXS_INFO_PORT_XMACJ_INFO_0(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_XGXS_INFO_PORT_XMACJ_INFO_1(val) vxge_vBIT(val, 32, 32) +/*0x09d50*/ u64 ratemgmt_cfg_port[2]; +#define VXGE_HW_RATEMGMT_CFG_PORT_MODE(val) vxge_vBIT(val, 2, 2) +#define VXGE_HW_RATEMGMT_CFG_PORT_RATE vxge_mBIT(7) +#define VXGE_HW_RATEMGMT_CFG_PORT_FIXED_USE_FSM vxge_mBIT(11) +#define VXGE_HW_RATEMGMT_CFG_PORT_ANTP_USE_FSM vxge_mBIT(15) +#define VXGE_HW_RATEMGMT_CFG_PORT_ANBE_USE_FSM vxge_mBIT(19) +/*0x09d60*/ u64 ratemgmt_status_port[2]; +#define VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_COMPLETE vxge_mBIT(3) +#define VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_RATE vxge_mBIT(7) +#define VXGE_HW_RATEMGMT_STATUS_PORT_RATEMGMT_MAC_MATCHES_PHY vxge_mBIT(11) + u8 unused09d80[0x09d80-0x09d70]; + +/*0x09d80*/ u64 ratemgmt_fixed_cfg_port[2]; +#define VXGE_HW_RATEMGMT_FIXED_CFG_PORT_RESTART vxge_mBIT(7) +/*0x09d90*/ u64 ratemgmt_antp_cfg_port[2]; +#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_RESTART vxge_mBIT(7) +#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_USE_PREAMBLE_EXT_PHY vxge_mBIT(11) +#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_USE_ACT_SEL vxge_mBIT(15) +#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_RETRY_PHY_QUERY(val) \ + vxge_vBIT(val, 16, 4) +#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_WAIT_MDIO_RESPONSE(val) \ + vxge_vBIT(val, 20, 4) +#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_T_LDOWN_REAUTO_RESPONSE(val) \ + vxge_vBIT(val, 24, 4) +#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_ADVERTISE_10G vxge_mBIT(31) +#define VXGE_HW_RATEMGMT_ANTP_CFG_PORT_ADVERTISE_1G vxge_mBIT(35) +/*0x09da0*/ u64 ratemgmt_anbe_cfg_port[2]; +#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_RESTART vxge_mBIT(7) +#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_PARALLEL_DETECT_10G_KX4_ENABLE \ + vxge_mBIT(11) +#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_PARALLEL_DETECT_1G_KX_ENABLE \ + vxge_mBIT(15) +#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_SYNC_10G_KX4(val) vxge_vBIT(val, 16, 4) +#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_SYNC_1G_KX(val) vxge_vBIT(val, 20, 4) +#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_T_DME_EXCHANGE(val) vxge_vBIT(val, 24, 4) +#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_ADVERTISE_10G_KX4 vxge_mBIT(31) +#define VXGE_HW_RATEMGMT_ANBE_CFG_PORT_ADVERTISE_1G_KX vxge_mBIT(35) +/*0x09db0*/ u64 anbe_cfg_port[2]; +#define VXGE_HW_ANBE_CFG_PORT_RESET_CFG_REGS(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_ANBE_CFG_PORT_ALIGN_10G_KX4_OVERRIDE(val) vxge_vBIT(val, 10, 2) +#define VXGE_HW_ANBE_CFG_PORT_SYNC_1G_KX_OVERRIDE(val) vxge_vBIT(val, 14, 2) +/*0x09dc0*/ u64 anbe_mgr_ctrl_port[2]; +#define VXGE_HW_ANBE_MGR_CTRL_PORT_WE vxge_mBIT(3) +#define VXGE_HW_ANBE_MGR_CTRL_PORT_STROBE vxge_mBIT(7) +#define VXGE_HW_ANBE_MGR_CTRL_PORT_ADDR(val) vxge_vBIT(val, 15, 9) +#define VXGE_HW_ANBE_MGR_CTRL_PORT_DATA(val) vxge_vBIT(val, 32, 32) + u8 unused09de0[0x09de0-0x09dd0]; + +/*0x09de0*/ u64 anbe_fw_mstr_port[2]; +#define VXGE_HW_ANBE_FW_MSTR_PORT_CONNECT_BEAN_TO_SERDES vxge_mBIT(3) +#define VXGE_HW_ANBE_FW_MSTR_PORT_TX_ZEROES_TO_SERDES vxge_mBIT(7) +/*0x09df0*/ u64 anbe_hwfsm_gen_status_port[2]; +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G_KX4_USING_PD \ + vxge_mBIT(3) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G_KX4_USING_DME \ + vxge_mBIT(7) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G_KX_USING_PD \ + vxge_mBIT(11) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G_KX_USING_DME \ + vxge_mBIT(15) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_ANBEFSM_STATE(val) \ + vxge_vBIT(val, 18, 6) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_NEXT_PAGE_RECEIVED \ + vxge_mBIT(27) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_BASE_PAGE_RECEIVED \ + vxge_mBIT(35) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_BEAN_AUTONEG_COMPLETE \ + vxge_mBIT(39) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NP_BEFORE_BP \ + vxge_mBIT(43) +#define \ +VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_AN_COMPLETE_BEFORE_BP \ + vxge_mBIT(47) +#define \ +VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_AN_COMPLETE_BEFORE_NP \ +vxge_mBIT(51) +#define \ +VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_MODE_WHEN_AN_COMPLETE \ + vxge_mBIT(55) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_COUNT_BP(val) \ + vxge_vBIT(val, 56, 4) +#define VXGE_HW_ANBE_HWFSM_GEN_STATUS_PORT_RATEMGMT_COUNT_NP(val) \ + vxge_vBIT(val, 60, 4) +/*0x09e00*/ u64 anbe_hwfsm_bp_status_port[2]; +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_FEC_ENABLE \ + vxge_mBIT(32) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_FEC_ABILITY \ + vxge_mBIT(33) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_10G_KR_CAPABLE \ + vxge_mBIT(40) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_10G_KX4_CAPABLE \ + vxge_mBIT(41) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_1G_KX_CAPABLE \ + vxge_mBIT(42) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_TX_NONCE(val) \ + vxge_vBIT(val, 43, 5) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_NP vxge_mBIT(48) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ACK vxge_mBIT(49) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_REMOTE_FAULT \ + vxge_mBIT(50) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ASM_DIR vxge_mBIT(51) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_PAUSE vxge_mBIT(53) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ECHOED_NONCE(val) \ + vxge_vBIT(val, 54, 5) +#define VXGE_HW_ANBE_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_SELECTOR_FIELD(val) \ + vxge_vBIT(val, 59, 5) +/*0x09e10*/ u64 anbe_hwfsm_np_status_port[2]; +#define VXGE_HW_ANBE_HWFSM_NP_STATUS_PORT_RATEMGMT_NP_BITS_47_TO_32(val) \ + vxge_vBIT(val, 16, 16) +#define VXGE_HW_ANBE_HWFSM_NP_STATUS_PORT_RATEMGMT_NP_BITS_31_TO_0(val) \ + vxge_vBIT(val, 32, 32) + u8 unused09e30[0x09e30-0x09e20]; + +/*0x09e30*/ u64 antp_gen_cfg_port[2]; +/*0x09e40*/ u64 antp_hwfsm_gen_status_port[2]; +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_10G vxge_mBIT(3) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_CHOSE_1G vxge_mBIT(7) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_ANTPFSM_STATE(val) \ + vxge_vBIT(val, 10, 6) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_AUTONEG_COMPLETE \ + vxge_mBIT(23) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NO_LP_XNP \ + vxge_mBIT(27) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_GOT_LP_XNP vxge_mBIT(31) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_MESSAGE_CODE \ + vxge_mBIT(35) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_NO_HCD \ + vxge_mBIT(43) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_FOUND_HCD vxge_mBIT(47) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_UNEXPECTED_INVALID_RATE \ + vxge_mBIT(51) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_VALID_RATE vxge_mBIT(55) +#define VXGE_HW_ANTP_HWFSM_GEN_STATUS_PORT_RATEMGMT_PERSISTENT_LDOWN \ + vxge_mBIT(59) +/*0x09e50*/ u64 antp_hwfsm_bp_status_port[2]; +#define VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_NP vxge_mBIT(0) +#define VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ACK vxge_mBIT(1) +#define VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_RF vxge_mBIT(2) +#define VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_XNP vxge_mBIT(3) +#define VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_ABILITY_FIELD(val) \ + vxge_vBIT(val, 4, 7) +#define VXGE_HW_ANTP_HWFSM_BP_STATUS_PORT_RATEMGMT_BP_SELECTOR_FIELD(val) \ + vxge_vBIT(val, 11, 5) +/*0x09e60*/ u64 antp_hwfsm_xnp_status_port[2]; +#define VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_NP vxge_mBIT(0) +#define VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_ACK vxge_mBIT(1) +#define VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_MP vxge_mBIT(2) +#define VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_ACK2 vxge_mBIT(3) +#define VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_TOGGLE vxge_mBIT(4) +#define VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_MESSAGE_CODE(val) \ + vxge_vBIT(val, 5, 11) +#define VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_UNF_CODE_FIELD1(val) \ + vxge_vBIT(val, 16, 16) +#define VXGE_HW_ANTP_HWFSM_XNP_STATUS_PORT_RATEMGMT_XNP_UNF_CODE_FIELD2(val) \ + vxge_vBIT(val, 32, 16) +/*0x09e70*/ u64 mdio_mgr_access_port[2]; +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_STROBE_ONE BIT(3) +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_OP_TYPE(val) vxge_vBIT(val, 5, 3) +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_DEVAD(val) vxge_vBIT(val, 11, 5) +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_ADDR(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_DATA(val) vxge_vBIT(val, 32, 16) +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_ST_PATTERN(val) vxge_vBIT(val, 49, 2) +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_PREAMBLE vxge_mBIT(51) +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_PRTAD(val) vxge_vBIT(val, 55, 5) +#define VXGE_HW_MDIO_MGR_ACCESS_PORT_STROBE_TWO vxge_mBIT(63) + u8 unused0a200[0x0a200-0x09e80]; +/*0x0a200*/ u64 xmac_vsport_choices_vh[17]; +#define VXGE_HW_XMAC_VSPORT_CHOICES_VH_VSPORT_VECTOR(val) vxge_vBIT(val, 0, 17) + u8 unused0a400[0x0a400-0x0a288]; + +/*0x0a400*/ u64 rx_thresh_cfg_vp[17]; +#define VXGE_HW_RX_THRESH_CFG_VP_PAUSE_LOW_THR(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_RX_THRESH_CFG_VP_PAUSE_HIGH_THR(val) vxge_vBIT(val, 8, 8) +#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_0(val) vxge_vBIT(val, 16, 8) +#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_1(val) vxge_vBIT(val, 24, 8) +#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_2(val) vxge_vBIT(val, 32, 8) +#define VXGE_HW_RX_THRESH_CFG_VP_RED_THR_3(val) vxge_vBIT(val, 40, 8) + u8 unused0ac90[0x0ac90-0x0a488]; +} __packed; + +/*VXGE_HW_SRPCIM_REGS_H*/ +struct vxge_hw_srpcim_reg { + +/*0x00000*/ u64 tim_mr2sr_resource_assignment_vh; +#define VXGE_HW_TIM_MR2SR_RESOURCE_ASSIGNMENT_VH_BMAP_ROOT(val) \ + vxge_vBIT(val, 0, 32) + u8 unused00100[0x00100-0x00008]; + +/*0x00100*/ u64 srpcim_pcipif_int_status; +#define VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_MRPCIM_MSG_MRPCIM_MSG_INT BIT(3) +#define VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_VPATH_MSG_VPATH_MSG_INT BIT(7) +#define VXGE_HW_SRPCIM_PCIPIF_INT_STATUS_SRPCIM_SPARE_R1_SRPCIM_SPARE_R1_INT \ + BIT(11) +/*0x00108*/ u64 srpcim_pcipif_int_mask; +/*0x00110*/ u64 mrpcim_msg_reg; +#define VXGE_HW_MRPCIM_MSG_REG_SWIF_MRPCIM_TO_SRPCIM_RMSG_INT BIT(3) +/*0x00118*/ u64 mrpcim_msg_mask; +/*0x00120*/ u64 mrpcim_msg_alarm; +/*0x00128*/ u64 vpath_msg_reg; +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH0_TO_SRPCIM_RMSG_INT BIT(0) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH1_TO_SRPCIM_RMSG_INT BIT(1) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH2_TO_SRPCIM_RMSG_INT BIT(2) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH3_TO_SRPCIM_RMSG_INT BIT(3) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH4_TO_SRPCIM_RMSG_INT BIT(4) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH5_TO_SRPCIM_RMSG_INT BIT(5) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH6_TO_SRPCIM_RMSG_INT BIT(6) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH7_TO_SRPCIM_RMSG_INT BIT(7) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH8_TO_SRPCIM_RMSG_INT BIT(8) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH9_TO_SRPCIM_RMSG_INT BIT(9) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH10_TO_SRPCIM_RMSG_INT BIT(10) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH11_TO_SRPCIM_RMSG_INT BIT(11) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH12_TO_SRPCIM_RMSG_INT BIT(12) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH13_TO_SRPCIM_RMSG_INT BIT(13) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH14_TO_SRPCIM_RMSG_INT BIT(14) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH15_TO_SRPCIM_RMSG_INT BIT(15) +#define VXGE_HW_VPATH_MSG_REG_SWIF_VPATH16_TO_SRPCIM_RMSG_INT BIT(16) +/*0x00130*/ u64 vpath_msg_mask; +/*0x00138*/ u64 vpath_msg_alarm; + u8 unused00160[0x00160-0x00140]; + +/*0x00160*/ u64 srpcim_to_mrpcim_wmsg; +#define VXGE_HW_SRPCIM_TO_MRPCIM_WMSG_SRPCIM_TO_MRPCIM_WMSG(val) \ + vxge_vBIT(val, 0, 64) +/*0x00168*/ u64 srpcim_to_mrpcim_wmsg_trig; +#define VXGE_HW_SRPCIM_TO_MRPCIM_WMSG_TRIG_SRPCIM_TO_MRPCIM_WMSG_TRIG BIT(0) +/*0x00170*/ u64 mrpcim_to_srpcim_rmsg; +#define VXGE_HW_MRPCIM_TO_SRPCIM_RMSG_SWIF_MRPCIM_TO_SRPCIM_RMSG(val) \ + vxge_vBIT(val, 0, 64) +/*0x00178*/ u64 vpath_to_srpcim_rmsg_sel; +#define VXGE_HW_VPATH_TO_SRPCIM_RMSG_SEL_VPATH_TO_SRPCIM_RMSG_SEL(val) \ + vxge_vBIT(val, 0, 5) +/*0x00180*/ u64 vpath_to_srpcim_rmsg; +#define VXGE_HW_VPATH_TO_SRPCIM_RMSG_SWIF_VPATH_TO_SRPCIM_RMSG(val) \ + vxge_vBIT(val, 0, 64) + u8 unused00200[0x00200-0x00188]; + +/*0x00200*/ u64 srpcim_general_int_status; +#define VXGE_HW_SRPCIM_GENERAL_INT_STATUS_PIC_INT BIT(0) +#define VXGE_HW_SRPCIM_GENERAL_INT_STATUS_PCI_INT BIT(3) +#define VXGE_HW_SRPCIM_GENERAL_INT_STATUS_XMAC_INT BIT(7) + u8 unused00210[0x00210-0x00208]; + +/*0x00210*/ u64 srpcim_general_int_mask; +#define VXGE_HW_SRPCIM_GENERAL_INT_MASK_PIC_INT BIT(0) +#define VXGE_HW_SRPCIM_GENERAL_INT_MASK_PCI_INT BIT(3) +#define VXGE_HW_SRPCIM_GENERAL_INT_MASK_XMAC_INT BIT(7) + u8 unused00220[0x00220-0x00218]; + +/*0x00220*/ u64 srpcim_ppif_int_status; + +/*0x00228*/ u64 srpcim_ppif_int_mask; +/*0x00230*/ u64 srpcim_gen_errors_reg; +#define VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_STATUS_ERR BIT(3) +#define VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_UNCOR_ERR BIT(7) +#define VXGE_HW_SRPCIM_GEN_ERRORS_REG_PCICONFIG_PF_COR_ERR BIT(11) +#define VXGE_HW_SRPCIM_GEN_ERRORS_REG_INTCTRL_SCHED_INT BIT(15) +#define VXGE_HW_SRPCIM_GEN_ERRORS_REG_INI_SERR_DET BIT(19) +#define VXGE_HW_SRPCIM_GEN_ERRORS_REG_TGT_PF_ILLEGAL_ACCESS BIT(23) +/*0x00238*/ u64 srpcim_gen_errors_mask; +/*0x00240*/ u64 srpcim_gen_errors_alarm; +/*0x00248*/ u64 mrpcim_to_srpcim_alarm_reg; +#define VXGE_HW_MRPCIM_TO_SRPCIM_ALARM_REG_PPIF_MRPCIM_TO_SRPCIM_ALARM BIT(3) +/*0x00250*/ u64 mrpcim_to_srpcim_alarm_mask; +/*0x00258*/ u64 mrpcim_to_srpcim_alarm_alarm; +/*0x00260*/ u64 vpath_to_srpcim_alarm_reg; + +/*0x00268*/ u64 vpath_to_srpcim_alarm_mask; +/*0x00270*/ u64 vpath_to_srpcim_alarm_alarm; + u8 unused00280[0x00280-0x00278]; + +/*0x00280*/ u64 pf_sw_reset; +#define VXGE_HW_PF_SW_RESET_PF_SW_RESET(val) vxge_vBIT(val, 0, 8) +/*0x00288*/ u64 srpcim_general_cfg1; +#define VXGE_HW_SRPCIM_GENERAL_CFG1_BOOT_BYTE_SWAPEN BIT(19) +#define VXGE_HW_SRPCIM_GENERAL_CFG1_BOOT_BIT_FLIPEN BIT(23) +#define VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_ADDR_SWAPEN BIT(27) +#define VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_ADDR_FLIPEN BIT(31) +#define VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_DATA_SWAPEN BIT(35) +#define VXGE_HW_SRPCIM_GENERAL_CFG1_MSIX_DATA_FLIPEN BIT(39) +/*0x00290*/ u64 srpcim_interrupt_cfg1; +#define VXGE_HW_SRPCIM_INTERRUPT_CFG1_ALARM_MAP_TO_MSG(val) vxge_vBIT(val, 1, 7) +#define VXGE_HW_SRPCIM_INTERRUPT_CFG1_TRAFFIC_CLASS(val) vxge_vBIT(val, 9, 3) + u8 unused002a8[0x002a8-0x00298]; + +/*0x002a8*/ u64 srpcim_clear_msix_mask; +#define VXGE_HW_SRPCIM_CLEAR_MSIX_MASK_SRPCIM_CLEAR_MSIX_MASK BIT(0) +/*0x002b0*/ u64 srpcim_set_msix_mask; +#define VXGE_HW_SRPCIM_SET_MSIX_MASK_SRPCIM_SET_MSIX_MASK BIT(0) +/*0x002b8*/ u64 srpcim_clr_msix_one_shot; +#define VXGE_HW_SRPCIM_CLR_MSIX_ONE_SHOT_SRPCIM_CLR_MSIX_ONE_SHOT BIT(0) +/*0x002c0*/ u64 srpcim_rst_in_prog; +#define VXGE_HW_SRPCIM_RST_IN_PROG_SRPCIM_RST_IN_PROG BIT(7) +/*0x002c8*/ u64 srpcim_reg_modified; +#define VXGE_HW_SRPCIM_REG_MODIFIED_SRPCIM_REG_MODIFIED BIT(7) +/*0x002d0*/ u64 tgt_pf_illegal_access; +#define VXGE_HW_TGT_PF_ILLEGAL_ACCESS_SWIF_REGION(val) vxge_vBIT(val, 1, 7) +/*0x002d8*/ u64 srpcim_msix_status; +#define VXGE_HW_SRPCIM_MSIX_STATUS_INTCTL_SRPCIM_MSIX_MASK BIT(3) +#define VXGE_HW_SRPCIM_MSIX_STATUS_INTCTL_SRPCIM_MSIX_PENDING_VECTOR BIT(7) + u8 unused00880[0x00880-0x002e0]; + +/*0x00880*/ u64 xgmac_sr_int_status; +#define VXGE_HW_XGMAC_SR_INT_STATUS_ASIC_NTWK_SR_ERR_ASIC_NTWK_SR_INT BIT(3) +/*0x00888*/ u64 xgmac_sr_int_mask; +/*0x00890*/ u64 asic_ntwk_sr_err_reg; +#define VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_FAULT BIT(3) +#define VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_OK BIT(7) +#define VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_FAULT_OCCURRED \ + BIT(11) +#define VXGE_HW_ASIC_NTWK_SR_ERR_REG_XMACJ_NTWK_SUSTAINED_OK_OCCURRED BIT(15) +/*0x00898*/ u64 asic_ntwk_sr_err_mask; +/*0x008a0*/ u64 asic_ntwk_sr_err_alarm; + u8 unused008c0[0x008c0-0x008a8]; + +/*0x008c0*/ u64 xmac_vsport_choices_sr_clone; +#define VXGE_HW_XMAC_VSPORT_CHOICES_SR_CLONE_VSPORT_VECTOR(val) \ + vxge_vBIT(val, 0, 17) + u8 unused00900[0x00900-0x008c8]; + +/*0x00900*/ u64 mr_rqa_top_prty_for_vh; +#define VXGE_HW_MR_RQA_TOP_PRTY_FOR_VH_RQA_TOP_PRTY_FOR_VH(val) \ + vxge_vBIT(val, 59, 5) +/*0x00908*/ u64 umq_vh_data_list_empty; +#define VXGE_HW_UMQ_VH_DATA_LIST_EMPTY_ROCRC_UMQ_VH_DATA_LIST_EMPTY \ + BIT(0) +/*0x00910*/ u64 wde_cfg; +#define VXGE_HW_WDE_CFG_NS0_FORCE_MWB_START BIT(0) +#define VXGE_HW_WDE_CFG_NS0_FORCE_MWB_END BIT(1) +#define VXGE_HW_WDE_CFG_NS0_FORCE_QB_START BIT(2) +#define VXGE_HW_WDE_CFG_NS0_FORCE_QB_END BIT(3) +#define VXGE_HW_WDE_CFG_NS0_FORCE_MPSB_START BIT(4) +#define VXGE_HW_WDE_CFG_NS0_FORCE_MPSB_END BIT(5) +#define VXGE_HW_WDE_CFG_NS0_MWB_OPT_EN BIT(6) +#define VXGE_HW_WDE_CFG_NS0_QB_OPT_EN BIT(7) +#define VXGE_HW_WDE_CFG_NS0_MPSB_OPT_EN BIT(8) +#define VXGE_HW_WDE_CFG_NS1_FORCE_MWB_START BIT(9) +#define VXGE_HW_WDE_CFG_NS1_FORCE_MWB_END BIT(10) +#define VXGE_HW_WDE_CFG_NS1_FORCE_QB_START BIT(11) +#define VXGE_HW_WDE_CFG_NS1_FORCE_QB_END BIT(12) +#define VXGE_HW_WDE_CFG_NS1_FORCE_MPSB_START BIT(13) +#define VXGE_HW_WDE_CFG_NS1_FORCE_MPSB_END BIT(14) +#define VXGE_HW_WDE_CFG_NS1_MWB_OPT_EN BIT(15) +#define VXGE_HW_WDE_CFG_NS1_QB_OPT_EN BIT(16) +#define VXGE_HW_WDE_CFG_NS1_MPSB_OPT_EN BIT(17) +#define VXGE_HW_WDE_CFG_DISABLE_QPAD_FOR_UNALIGNED_ADDR BIT(19) +#define VXGE_HW_WDE_CFG_ALIGNMENT_PREFERENCE(val) vxge_vBIT(val, 30, 2) +#define VXGE_HW_WDE_CFG_MEM_WORD_SIZE(val) vxge_vBIT(val, 46, 2) + +} __packed; + +/*VXGE_HW_VPMGMT_REGS_H*/ +struct vxge_hw_vpmgmt_reg { + + u8 unused00040[0x00040-0x00000]; + +/*0x00040*/ u64 vpath_to_func_map_cfg1; +#define VXGE_HW_VPATH_TO_FUNC_MAP_CFG1_VPATH_TO_FUNC_MAP_CFG1(val) \ + vxge_vBIT(val, 3, 5) +/*0x00048*/ u64 vpath_is_first; +#define VXGE_HW_VPATH_IS_FIRST_VPATH_IS_FIRST vxge_mBIT(3) +/*0x00050*/ u64 srpcim_to_vpath_wmsg; +#define VXGE_HW_SRPCIM_TO_VPATH_WMSG_SRPCIM_TO_VPATH_WMSG(val) \ + vxge_vBIT(val, 0, 64) +/*0x00058*/ u64 srpcim_to_vpath_wmsg_trig; +#define VXGE_HW_SRPCIM_TO_VPATH_WMSG_TRIG_SRPCIM_TO_VPATH_WMSG_TRIG \ + vxge_mBIT(0) + u8 unused00100[0x00100-0x00060]; + +/*0x00100*/ u64 tim_vpath_assignment; +#define VXGE_HW_TIM_VPATH_ASSIGNMENT_BMAP_ROOT(val) vxge_vBIT(val, 0, 32) + u8 unused00140[0x00140-0x00108]; + +/*0x00140*/ u64 rqa_top_prty_for_vp; +#define VXGE_HW_RQA_TOP_PRTY_FOR_VP_RQA_TOP_PRTY_FOR_VP(val) \ + vxge_vBIT(val, 59, 5) + u8 unused001c0[0x001c0-0x00148]; + +/*0x001c0*/ u64 rxmac_rx_pa_cfg0_vpmgmt_clone; +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_IGNORE_FRAME_ERR vxge_mBIT(3) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SUPPORT_SNAP_AB_N vxge_mBIT(7) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SEARCH_FOR_HAO vxge_mBIT(18) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SUPPORT_MOBILE_IPV6_HDRS \ + vxge_mBIT(19) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_IPV6_STOP_SEARCHING \ + vxge_mBIT(23) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_NO_PS_IF_UNKNOWN vxge_mBIT(27) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_SEARCH_FOR_ETYPE vxge_mBIT(35) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_L3_CSUM_ERR \ + vxge_mBIT(39) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_L3_CSUM_ERR \ + vxge_mBIT(43) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_L4_CSUM_ERR \ + vxge_mBIT(47) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_L4_CSUM_ERR \ + vxge_mBIT(51) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_ANY_FRM_IF_RPA_ERR \ + vxge_mBIT(55) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_TOSS_OFFLD_FRM_IF_RPA_ERR \ + vxge_mBIT(59) +#define VXGE_HW_RXMAC_RX_PA_CFG0_VPMGMT_CLONE_JUMBO_SNAP_EN vxge_mBIT(63) +/*0x001c8*/ u64 rts_mgr_cfg0_vpmgmt_clone; +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_RTS_DP_SP_PRIORITY vxge_mBIT(3) +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_FLEX_L4PRTCL_VALUE(val) \ + vxge_vBIT(val, 24, 8) +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_ICMP_TRASH vxge_mBIT(35) +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_TCPSYN_TRASH vxge_mBIT(39) +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_ZL4PYLD_TRASH vxge_mBIT(43) +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_TCP_TRASH vxge_mBIT(47) +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_UDP_TRASH vxge_mBIT(51) +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_L4PRTCL_FLEX_TRASH vxge_mBIT(55) +#define VXGE_HW_RTS_MGR_CFG0_VPMGMT_CLONE_IPFRAG_TRASH vxge_mBIT(59) +/*0x001d0*/ u64 rts_mgr_criteria_priority_vpmgmt_clone; +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ETYPE(val) \ + vxge_vBIT(val, 5, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ICMP_TCPSYN(val) \ + vxge_vBIT(val, 9, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_L4PN(val) \ + vxge_vBIT(val, 13, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_RANGE_L4PN(val) \ + vxge_vBIT(val, 17, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_RTH_IT(val) \ + vxge_vBIT(val, 21, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_DS(val) \ + vxge_vBIT(val, 25, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_QOS(val) \ + vxge_vBIT(val, 29, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_ZL4PYLD(val) \ + vxge_vBIT(val, 33, 3) +#define VXGE_HW_RTS_MGR_CRITERIA_PRIORITY_VPMGMT_CLONE_L4PRTCL(val) \ + vxge_vBIT(val, 37, 3) +/*0x001d8*/ u64 rxmac_cfg0_port_vpmgmt_clone[3]; +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_RMAC_EN vxge_mBIT(3) +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_STRIP_FCS vxge_mBIT(7) +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_DISCARD_PFRM vxge_mBIT(11) +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_FCS_ERR vxge_mBIT(15) +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_LONG_ERR vxge_mBIT(19) +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_USIZED_ERR vxge_mBIT(23) +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_IGNORE_LEN_MISMATCH \ + vxge_mBIT(27) +#define VXGE_HW_RXMAC_CFG0_PORT_VPMGMT_CLONE_MAX_PYLD_LEN(val) \ + vxge_vBIT(val, 50, 14) +/*0x001f0*/ u64 rxmac_pause_cfg_port_vpmgmt_clone[3]; +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_GEN_EN vxge_mBIT(3) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_RCV_EN vxge_mBIT(7) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_ACCEL_SEND(val) \ + vxge_vBIT(val, 9, 3) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_DUAL_THR vxge_mBIT(15) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_HIGH_PTIME(val) \ + vxge_vBIT(val, 20, 16) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_IGNORE_PF_FCS_ERR \ + vxge_mBIT(39) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_IGNORE_PF_LEN_ERR \ + vxge_mBIT(43) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_LIMITER_EN vxge_mBIT(47) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_MAX_LIMIT(val) \ + vxge_vBIT(val, 48, 8) +#define VXGE_HW_RXMAC_PAUSE_CFG_PORT_VPMGMT_CLONE_PERMIT_RATEMGMT_CTRL \ + vxge_mBIT(59) + u8 unused00240[0x00240-0x00208]; + +/*0x00240*/ u64 xmac_vsport_choices_vp; +#define VXGE_HW_XMAC_VSPORT_CHOICES_VP_VSPORT_VECTOR(val) vxge_vBIT(val, 0, 17) + u8 unused00260[0x00260-0x00248]; + +/*0x00260*/ u64 xgmac_gen_status_vpmgmt_clone; +#define VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_OK vxge_mBIT(3) +#define VXGE_HW_XGMAC_GEN_STATUS_VPMGMT_CLONE_XMACJ_NTWK_DATA_RATE \ + vxge_mBIT(11) +/*0x00268*/ u64 xgmac_status_port_vpmgmt_clone[2]; +#define VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_RMAC_REMOTE_FAULT \ + vxge_mBIT(3) +#define VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_RMAC_LOCAL_FAULT vxge_mBIT(7) +#define VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_XMACJ_MAC_PHY_LAYER_AVAIL \ + vxge_mBIT(11) +#define VXGE_HW_XGMAC_STATUS_PORT_VPMGMT_CLONE_XMACJ_PORT_OK vxge_mBIT(15) +/*0x00278*/ u64 xmac_gen_cfg_vpmgmt_clone; +#define VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_RATEMGMT_MAC_RATE_SEL(val) \ + vxge_vBIT(val, 2, 2) +#define VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_TX_HEAD_DROP_WHEN_FAULT \ + vxge_mBIT(7) +#define VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_FAULT_BEHAVIOUR vxge_mBIT(27) +#define VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_PERIOD_NTWK_UP(val) \ + vxge_vBIT(val, 28, 4) +#define VXGE_HW_XMAC_GEN_CFG_VPMGMT_CLONE_PERIOD_NTWK_DOWN(val) \ + vxge_vBIT(val, 32, 4) +/*0x00280*/ u64 xmac_timestamp_vpmgmt_clone; +#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_EN vxge_mBIT(3) +#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_USE_LINK_ID(val) \ + vxge_vBIT(val, 6, 2) +#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_INTERVAL(val) vxge_vBIT(val, 12, 4) +#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_TIMER_RESTART vxge_mBIT(19) +#define VXGE_HW_XMAC_TIMESTAMP_VPMGMT_CLONE_XMACJ_ROLLOVER_CNT(val) \ + vxge_vBIT(val, 32, 16) +/*0x00288*/ u64 xmac_stats_gen_cfg_vpmgmt_clone; +#define VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_PRTAGGR_CUM_TIMER(val) \ + vxge_vBIT(val, 4, 4) +#define VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_VPATH_CUM_TIMER(val) \ + vxge_vBIT(val, 8, 4) +#define VXGE_HW_XMAC_STATS_GEN_CFG_VPMGMT_CLONE_VLAN_HANDLING vxge_mBIT(15) +/*0x00290*/ u64 xmac_cfg_port_vpmgmt_clone[3]; +#define VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_LOOPBACK vxge_mBIT(3) +#define VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_REVERSE_LOOPBACK \ + vxge_mBIT(7) +#define VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_TX_BEHAV vxge_mBIT(11) +#define VXGE_HW_XMAC_CFG_PORT_VPMGMT_CLONE_XGMII_RX_BEHAV vxge_mBIT(15) + u8 unused002c0[0x002c0-0x002a8]; + +/*0x002c0*/ u64 txmac_gen_cfg0_vpmgmt_clone; +#define VXGE_HW_TXMAC_GEN_CFG0_VPMGMT_CLONE_CHOSEN_TX_PORT vxge_mBIT(7) +/*0x002c8*/ u64 txmac_cfg0_port_vpmgmt_clone[3]; +#define VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_TMAC_EN vxge_mBIT(3) +#define VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_APPEND_PAD vxge_mBIT(7) +#define VXGE_HW_TXMAC_CFG0_PORT_VPMGMT_CLONE_PAD_BYTE(val) vxge_vBIT(val, 8, 8) + u8 unused00300[0x00300-0x002e0]; + +/*0x00300*/ u64 wol_mp_crc; +#define VXGE_HW_WOL_MP_CRC_CRC(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_WOL_MP_CRC_RC_EN vxge_mBIT(63) +/*0x00308*/ u64 wol_mp_mask_a; +#define VXGE_HW_WOL_MP_MASK_A_MASK(val) vxge_vBIT(val, 0, 64) +/*0x00310*/ u64 wol_mp_mask_b; +#define VXGE_HW_WOL_MP_MASK_B_MASK(val) vxge_vBIT(val, 0, 64) + u8 unused00360[0x00360-0x00318]; + +/*0x00360*/ u64 fau_pa_cfg_vpmgmt_clone; +#define VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L4_COMP_CSUM vxge_mBIT(3) +#define VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L3_INCL_CF vxge_mBIT(7) +#define VXGE_HW_FAU_PA_CFG_VPMGMT_CLONE_REPL_L3_COMP_CSUM vxge_mBIT(11) +/*0x00368*/ u64 rx_datapath_util_vp_clone; +#define VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_FAU_RX_UTILIZATION(val) \ + vxge_vBIT(val, 7, 9) +#define VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_RX_UTIL_CFG(val) \ + vxge_vBIT(val, 16, 4) +#define VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_FAU_RX_FRAC_UTIL(val) \ + vxge_vBIT(val, 20, 4) +#define VXGE_HW_RX_DATAPATH_UTIL_VP_CLONE_RX_PKT_WEIGHT(val) \ + vxge_vBIT(val, 24, 4) + u8 unused00380[0x00380-0x00370]; + +/*0x00380*/ u64 tx_datapath_util_vp_clone; +#define VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TPA_TX_UTILIZATION(val) \ + vxge_vBIT(val, 7, 9) +#define VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TX_UTIL_CFG(val) \ + vxge_vBIT(val, 16, 4) +#define VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TPA_TX_FRAC_UTIL(val) \ + vxge_vBIT(val, 20, 4) +#define VXGE_HW_TX_DATAPATH_UTIL_VP_CLONE_TX_PKT_WEIGHT(val) \ + vxge_vBIT(val, 24, 4) + +} __packed; + +struct vxge_hw_vpath_reg { + + u8 unused00300[0x00300]; + +/*0x00300*/ u64 usdc_vpath; +#define VXGE_HW_USDC_VPATH_SGRP_ASSIGN(val) vxge_vBIT(val, 0, 32) + u8 unused00a00[0x00a00-0x00308]; + +/*0x00a00*/ u64 wrdma_alarm_status; +#define VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT vxge_mBIT(1) +/*0x00a08*/ u64 wrdma_alarm_mask; + u8 unused00a30[0x00a30-0x00a10]; + +/*0x00a30*/ u64 prc_alarm_reg; +#define VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP vxge_mBIT(0) +#define VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR vxge_mBIT(1) +#define VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT vxge_mBIT(2) +#define VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR vxge_mBIT(3) +/*0x00a38*/ u64 prc_alarm_mask; +/*0x00a40*/ u64 prc_alarm_alarm; +/*0x00a48*/ u64 prc_cfg1; +#define VXGE_HW_PRC_CFG1_RX_TIMER_VAL(val) vxge_vBIT(val, 3, 29) +#define VXGE_HW_PRC_CFG1_TIM_RING_BUMP_INT_ENABLE vxge_mBIT(34) +#define VXGE_HW_PRC_CFG1_RTI_TINT_DISABLE vxge_mBIT(35) +#define VXGE_HW_PRC_CFG1_GREEDY_RETURN vxge_mBIT(36) +#define VXGE_HW_PRC_CFG1_QUICK_SHOT vxge_mBIT(37) +#define VXGE_HW_PRC_CFG1_RX_TIMER_CI vxge_mBIT(39) +#define VXGE_HW_PRC_CFG1_RESET_TIMER_ON_RXD_RET(val) vxge_vBIT(val, 40, 2) + u8 unused00a60[0x00a60-0x00a50]; + +/*0x00a60*/ u64 prc_cfg4; +#define VXGE_HW_PRC_CFG4_IN_SVC vxge_mBIT(7) +#define VXGE_HW_PRC_CFG4_RING_MODE(val) vxge_vBIT(val, 14, 2) +#define VXGE_HW_PRC_CFG4_RXD_NO_SNOOP vxge_mBIT(22) +#define VXGE_HW_PRC_CFG4_FRM_NO_SNOOP vxge_mBIT(23) +#define VXGE_HW_PRC_CFG4_RTH_DISABLE vxge_mBIT(31) +#define VXGE_HW_PRC_CFG4_IGNORE_OWNERSHIP vxge_mBIT(32) +#define VXGE_HW_PRC_CFG4_SIGNAL_BENIGN_OVFLW vxge_mBIT(36) +#define VXGE_HW_PRC_CFG4_BIMODAL_INTERRUPT vxge_mBIT(37) +#define VXGE_HW_PRC_CFG4_BACKOFF_INTERVAL(val) vxge_vBIT(val, 40, 24) +/*0x00a68*/ u64 prc_cfg5; +#define VXGE_HW_PRC_CFG5_RXD0_ADD(val) vxge_vBIT(val, 0, 61) +/*0x00a70*/ u64 prc_cfg6; +#define VXGE_HW_PRC_CFG6_FRM_PAD_EN vxge_mBIT(0) +#define VXGE_HW_PRC_CFG6_QSIZE_ALIGNED_RXD vxge_mBIT(2) +#define VXGE_HW_PRC_CFG6_DOORBELL_MODE_EN vxge_mBIT(5) +#define VXGE_HW_PRC_CFG6_L3_CPC_TRSFR_CODE_EN vxge_mBIT(8) +#define VXGE_HW_PRC_CFG6_L4_CPC_TRSFR_CODE_EN vxge_mBIT(9) +#define VXGE_HW_PRC_CFG6_RXD_CRXDT(val) vxge_vBIT(val, 23, 9) +#define VXGE_HW_PRC_CFG6_RXD_SPAT(val) vxge_vBIT(val, 36, 9) +/*0x00a78*/ u64 prc_cfg7; +#define VXGE_HW_PRC_CFG7_SCATTER_MODE(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_PRC_CFG7_SMART_SCAT_EN vxge_mBIT(11) +#define VXGE_HW_PRC_CFG7_RXD_NS_CHG_EN vxge_mBIT(12) +#define VXGE_HW_PRC_CFG7_NO_HDR_SEPARATION vxge_mBIT(14) +#define VXGE_HW_PRC_CFG7_RXD_BUFF_SIZE_MASK(val) vxge_vBIT(val, 20, 4) +#define VXGE_HW_PRC_CFG7_BUFF_SIZE0_MASK(val) vxge_vBIT(val, 27, 5) +/*0x00a80*/ u64 tim_dest_addr; +#define VXGE_HW_TIM_DEST_ADDR_TIM_DEST_ADDR(val) vxge_vBIT(val, 0, 64) +/*0x00a88*/ u64 prc_rxd_doorbell; +#define VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(val) vxge_vBIT(val, 48, 16) +/*0x00a90*/ u64 rqa_prty_for_vp; +#define VXGE_HW_RQA_PRTY_FOR_VP_RQA_PRTY_FOR_VP(val) vxge_vBIT(val, 59, 5) +/*0x00a98*/ u64 rxdmem_size; +#define VXGE_HW_RXDMEM_SIZE_PRC_RXDMEM_SIZE(val) vxge_vBIT(val, 51, 13) +/*0x00aa0*/ u64 frm_in_progress_cnt; +#define VXGE_HW_FRM_IN_PROGRESS_CNT_PRC_FRM_IN_PROGRESS_CNT(val) \ + vxge_vBIT(val, 59, 5) +/*0x00aa8*/ u64 rx_multi_cast_stats; +#define VXGE_HW_RX_MULTI_CAST_STATS_FRAME_DISCARD(val) vxge_vBIT(val, 48, 16) +/*0x00ab0*/ u64 rx_frm_transferred; +#define VXGE_HW_RX_FRM_TRANSFERRED_RX_FRM_TRANSFERRED(val) \ + vxge_vBIT(val, 32, 32) +/*0x00ab8*/ u64 rxd_returned; +#define VXGE_HW_RXD_RETURNED_RXD_RETURNED(val) vxge_vBIT(val, 48, 16) + u8 unused00c00[0x00c00-0x00ac0]; + +/*0x00c00*/ u64 kdfc_fifo_trpl_partition; +#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_0(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_1(val) vxge_vBIT(val, 33, 15) +#define VXGE_HW_KDFC_FIFO_TRPL_PARTITION_LENGTH_2(val) vxge_vBIT(val, 49, 15) +/*0x00c08*/ u64 kdfc_fifo_trpl_ctrl; +#define VXGE_HW_KDFC_FIFO_TRPL_CTRL_TRIPLET_ENABLE vxge_mBIT(7) +/*0x00c10*/ u64 kdfc_trpl_fifo_0_ctrl; +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_MODE(val) vxge_vBIT(val, 14, 2) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_FLIP_EN vxge_mBIT(22) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SWAP_EN vxge_mBIT(23) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_CTRL_STRUC vxge_mBIT(28) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_ADD_PAD vxge_mBIT(29) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_NO_SNOOP vxge_mBIT(30) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_RLX_ORD vxge_mBIT(31) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_SELECT(val) vxge_vBIT(val, 32, 8) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7) +#define VXGE_HW_KDFC_TRPL_FIFO_0_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16) +/*0x00c18*/ u64 kdfc_trpl_fifo_1_ctrl; +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_MODE(val) vxge_vBIT(val, 14, 2) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_FLIP_EN vxge_mBIT(22) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_SWAP_EN vxge_mBIT(23) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_CTRL_STRUC vxge_mBIT(28) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_ADD_PAD vxge_mBIT(29) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_NO_SNOOP vxge_mBIT(30) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_RLX_ORD vxge_mBIT(31) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_SELECT(val) vxge_vBIT(val, 32, 8) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7) +#define VXGE_HW_KDFC_TRPL_FIFO_1_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16) +/*0x00c20*/ u64 kdfc_trpl_fifo_2_ctrl; +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_FLIP_EN vxge_mBIT(22) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_SWAP_EN vxge_mBIT(23) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_INT_CTRL(val) vxge_vBIT(val, 26, 2) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_CTRL_STRUC vxge_mBIT(28) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_ADD_PAD vxge_mBIT(29) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_NO_SNOOP vxge_mBIT(30) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_RLX_ORD vxge_mBIT(31) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_SELECT(val) vxge_vBIT(val, 32, 8) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_INT_NO(val) vxge_vBIT(val, 41, 7) +#define VXGE_HW_KDFC_TRPL_FIFO_2_CTRL_BIT_MAP(val) vxge_vBIT(val, 48, 16) +/*0x00c28*/ u64 kdfc_trpl_fifo_0_wb_address; +#define VXGE_HW_KDFC_TRPL_FIFO_0_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64) +/*0x00c30*/ u64 kdfc_trpl_fifo_1_wb_address; +#define VXGE_HW_KDFC_TRPL_FIFO_1_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64) +/*0x00c38*/ u64 kdfc_trpl_fifo_2_wb_address; +#define VXGE_HW_KDFC_TRPL_FIFO_2_WB_ADDRESS_ADD(val) vxge_vBIT(val, 0, 64) +/*0x00c40*/ u64 kdfc_trpl_fifo_offset; +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR0(val) vxge_vBIT(val, 1, 15) +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR1(val) vxge_vBIT(val, 17, 15) +#define VXGE_HW_KDFC_TRPL_FIFO_OFFSET_KDFC_RCTR2(val) vxge_vBIT(val, 33, 15) +/*0x00c48*/ u64 kdfc_drbl_triplet_total; +#define VXGE_HW_KDFC_DRBL_TRIPLET_TOTAL_KDFC_MAX_SIZE(val) \ + vxge_vBIT(val, 17, 15) + u8 unused00c60[0x00c60-0x00c50]; + +/*0x00c60*/ u64 usdc_drbl_ctrl; +#define VXGE_HW_USDC_DRBL_CTRL_FLIP_EN vxge_mBIT(22) +#define VXGE_HW_USDC_DRBL_CTRL_SWAP_EN vxge_mBIT(23) +/*0x00c68*/ u64 usdc_vp_ready; +#define VXGE_HW_USDC_VP_READY_USDC_HTN_READY vxge_mBIT(7) +#define VXGE_HW_USDC_VP_READY_USDC_SRQ_READY vxge_mBIT(15) +#define VXGE_HW_USDC_VP_READY_USDC_CQRQ_READY vxge_mBIT(23) +/*0x00c70*/ u64 kdfc_status; +#define VXGE_HW_KDFC_STATUS_KDFC_WRR_0_READY vxge_mBIT(0) +#define VXGE_HW_KDFC_STATUS_KDFC_WRR_1_READY vxge_mBIT(1) +#define VXGE_HW_KDFC_STATUS_KDFC_WRR_2_READY vxge_mBIT(2) + u8 unused00c80[0x00c80-0x00c78]; + +/*0x00c80*/ u64 xmac_rpa_vcfg; +#define VXGE_HW_XMAC_RPA_VCFG_IPV4_TCP_INCL_PH vxge_mBIT(3) +#define VXGE_HW_XMAC_RPA_VCFG_IPV6_TCP_INCL_PH vxge_mBIT(7) +#define VXGE_HW_XMAC_RPA_VCFG_IPV4_UDP_INCL_PH vxge_mBIT(11) +#define VXGE_HW_XMAC_RPA_VCFG_IPV6_UDP_INCL_PH vxge_mBIT(15) +#define VXGE_HW_XMAC_RPA_VCFG_L4_INCL_CF vxge_mBIT(19) +#define VXGE_HW_XMAC_RPA_VCFG_STRIP_VLAN_TAG vxge_mBIT(23) +/*0x00c88*/ u64 rxmac_vcfg0; +#define VXGE_HW_RXMAC_VCFG0_RTS_MAX_FRM_LEN(val) vxge_vBIT(val, 2, 14) +#define VXGE_HW_RXMAC_VCFG0_RTS_USE_MIN_LEN vxge_mBIT(19) +#define VXGE_HW_RXMAC_VCFG0_RTS_MIN_FRM_LEN(val) vxge_vBIT(val, 26, 14) +#define VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN vxge_mBIT(43) +#define VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN vxge_mBIT(47) +#define VXGE_HW_RXMAC_VCFG0_BCAST_EN vxge_mBIT(51) +#define VXGE_HW_RXMAC_VCFG0_ALL_VID_EN vxge_mBIT(55) +/*0x00c90*/ u64 rxmac_vcfg1; +#define VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_BD_MODE(val) vxge_vBIT(val, 42, 2) +#define VXGE_HW_RXMAC_VCFG1_RTS_RTH_MULTI_IT_EN_MODE vxge_mBIT(47) +#define VXGE_HW_RXMAC_VCFG1_CONTRIB_L2_FLOW vxge_mBIT(51) +/*0x00c98*/ u64 rts_access_steer_ctrl; +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION(val) vxge_vBIT(val, 1, 7) +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL(val) vxge_vBIT(val, 8, 4) +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_STROBE vxge_mBIT(15) +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_BEHAV_TBL_SEL vxge_mBIT(23) +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_TABLE_SEL vxge_mBIT(27) +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_RMACJ_STATUS vxge_mBIT(0) +#define VXGE_HW_RTS_ACCESS_STEER_CTRL_OFFSET(val) vxge_vBIT(val, 40, 8) +/*0x00ca0*/ u64 rts_access_steer_data0; +#define VXGE_HW_RTS_ACCESS_STEER_DATA0_DATA(val) vxge_vBIT(val, 0, 64) +/*0x00ca8*/ u64 rts_access_steer_data1; +#define VXGE_HW_RTS_ACCESS_STEER_DATA1_DATA(val) vxge_vBIT(val, 0, 64) + u8 unused00d00[0x00d00-0x00cb0]; + +/*0x00d00*/ u64 xmac_vsport_choice; +#define VXGE_HW_XMAC_VSPORT_CHOICE_VSPORT_NUMBER(val) vxge_vBIT(val, 3, 5) +/*0x00d08*/ u64 xmac_stats_cfg; +/*0x00d10*/ u64 xmac_stats_access_cmd; +#define VXGE_HW_XMAC_STATS_ACCESS_CMD_OP(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_XMAC_STATS_ACCESS_CMD_STROBE vxge_mBIT(15) +#define VXGE_HW_XMAC_STATS_ACCESS_CMD_OFFSET_SEL(val) vxge_vBIT(val, 32, 8) +/*0x00d18*/ u64 xmac_stats_access_data; +#define VXGE_HW_XMAC_STATS_ACCESS_DATA_XSMGR_DATA(val) vxge_vBIT(val, 0, 64) +/*0x00d20*/ u64 asic_ntwk_vp_ctrl; +#define VXGE_HW_ASIC_NTWK_VP_CTRL_REQ_TEST_NTWK vxge_mBIT(3) +#define VXGE_HW_ASIC_NTWK_VP_CTRL_XMACJ_SHOW_PORT_INFO vxge_mBIT(55) +#define VXGE_HW_ASIC_NTWK_VP_CTRL_XMACJ_PORT_NUM vxge_mBIT(63) + u8 unused00d30[0x00d30-0x00d28]; + +/*0x00d30*/ u64 xgmac_vp_int_status; +#define VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT \ + vxge_mBIT(3) +/*0x00d38*/ u64 xgmac_vp_int_mask; +/*0x00d40*/ u64 asic_ntwk_vp_err_reg; +#define VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT vxge_mBIT(3) +#define VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK vxge_mBIT(7) +#define VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR \ + vxge_mBIT(11) +#define VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR \ + vxge_mBIT(15) +#define VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT \ + vxge_mBIT(19) +#define VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK vxge_mBIT(23) +/*0x00d48*/ u64 asic_ntwk_vp_err_mask; +/*0x00d50*/ u64 asic_ntwk_vp_err_alarm; + u8 unused00d80[0x00d80-0x00d58]; + +/*0x00d80*/ u64 rtdma_bw_ctrl; +#define VXGE_HW_RTDMA_BW_CTRL_BW_CTRL_EN vxge_mBIT(39) +#define VXGE_HW_RTDMA_BW_CTRL_DESIRED_BW(val) vxge_vBIT(val, 46, 18) +/*0x00d88*/ u64 rtdma_rd_optimization_ctrl; +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_GEN_INT_AFTER_ABORT vxge_mBIT(3) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_PAD_MODE(val) vxge_vBIT(val, 6, 2) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_PAD_PATTERN(val) vxge_vBIT(val, 8, 8) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_WAIT_FOR_SPACE vxge_mBIT(19) +#define VXGE_HW_PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_FILL_THRESH(val) \ + vxge_vBIT(val, 21, 3) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_PYLD_WMARK_EN vxge_mBIT(28) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_PYLD_WMARK(val) \ + vxge_vBIT(val, 29, 3) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY_EN vxge_mBIT(35) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_FB_ADDR_BDRY(val) \ + vxge_vBIT(val, 37, 3) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_WAIT_FOR_SPACE vxge_mBIT(43) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_FILL_THRESH(val) \ + vxge_vBIT(val, 51, 5) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_ADDR_BDRY_EN vxge_mBIT(59) +#define VXGE_HW_RTDMA_RD_OPTIMIZATION_CTRL_TXD_ADDR_BDRY(val) \ + vxge_vBIT(val, 61, 3) +/*0x00d90*/ u64 pda_pcc_job_monitor; +#define VXGE_HW_PDA_PCC_JOB_MONITOR_PDA_PCC_JOB_STATUS vxge_mBIT(7) +/*0x00d98*/ u64 tx_protocol_assist_cfg; +#define VXGE_HW_TX_PROTOCOL_ASSIST_CFG_LSOV2_EN vxge_mBIT(6) +#define VXGE_HW_TX_PROTOCOL_ASSIST_CFG_IPV6_KEEP_SEARCHING vxge_mBIT(7) + u8 unused01000[0x01000-0x00da0]; + +/*0x01000*/ u64 tim_cfg1_int_num[4]; +#define VXGE_HW_TIM_CFG1_INT_NUM_BTIMER_VAL(val) vxge_vBIT(val, 6, 26) +#define VXGE_HW_TIM_CFG1_INT_NUM_BITMP_EN vxge_mBIT(35) +#define VXGE_HW_TIM_CFG1_INT_NUM_TXFRM_CNT_EN vxge_mBIT(36) +#define VXGE_HW_TIM_CFG1_INT_NUM_TXD_CNT_EN vxge_mBIT(37) +#define VXGE_HW_TIM_CFG1_INT_NUM_TIMER_AC vxge_mBIT(38) +#define VXGE_HW_TIM_CFG1_INT_NUM_TIMER_CI vxge_mBIT(39) +#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_A(val) vxge_vBIT(val, 41, 7) +#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_B(val) vxge_vBIT(val, 49, 7) +#define VXGE_HW_TIM_CFG1_INT_NUM_URNG_C(val) vxge_vBIT(val, 57, 7) +/*0x01020*/ u64 tim_cfg2_int_num[4]; +#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_A(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_B(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_C(val) vxge_vBIT(val, 32, 16) +#define VXGE_HW_TIM_CFG2_INT_NUM_UEC_D(val) vxge_vBIT(val, 48, 16) +/*0x01040*/ u64 tim_cfg3_int_num[4]; +#define VXGE_HW_TIM_CFG3_INT_NUM_TIMER_RI vxge_mBIT(0) +#define VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_EVENT_SF(val) vxge_vBIT(val, 1, 4) +#define VXGE_HW_TIM_CFG3_INT_NUM_RTIMER_VAL(val) vxge_vBIT(val, 6, 26) +#define VXGE_HW_TIM_CFG3_INT_NUM_UTIL_SEL(val) vxge_vBIT(val, 32, 6) +#define VXGE_HW_TIM_CFG3_INT_NUM_LTIMER_VAL(val) vxge_vBIT(val, 38, 26) +/*0x01060*/ u64 tim_wrkld_clc; +#define VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_PRD(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_TIM_WRKLD_CLC_WRKLD_EVAL_DIV(val) vxge_vBIT(val, 35, 5) +#define VXGE_HW_TIM_WRKLD_CLC_CNT_FRM_BYTE vxge_mBIT(40) +#define VXGE_HW_TIM_WRKLD_CLC_CNT_RX_TX(val) vxge_vBIT(val, 41, 2) +#define VXGE_HW_TIM_WRKLD_CLC_CNT_LNK_EN vxge_mBIT(43) +#define VXGE_HW_TIM_WRKLD_CLC_HOST_UTIL(val) vxge_vBIT(val, 57, 7) +/*0x01068*/ u64 tim_bitmap; +#define VXGE_HW_TIM_BITMAP_MASK(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_TIM_BITMAP_LLROOT_RXD_EN vxge_mBIT(32) +#define VXGE_HW_TIM_BITMAP_LLROOT_TXD_EN vxge_mBIT(33) +/*0x01070*/ u64 tim_ring_assn; +#define VXGE_HW_TIM_RING_ASSN_INT_NUM(val) vxge_vBIT(val, 6, 2) +/*0x01078*/ u64 tim_remap; +#define VXGE_HW_TIM_REMAP_TX_EN vxge_mBIT(5) +#define VXGE_HW_TIM_REMAP_RX_EN vxge_mBIT(6) +#define VXGE_HW_TIM_REMAP_OFFLOAD_EN vxge_mBIT(7) +#define VXGE_HW_TIM_REMAP_TO_VPATH_NUM(val) vxge_vBIT(val, 11, 5) +/*0x01080*/ u64 tim_vpath_map; +#define VXGE_HW_TIM_VPATH_MAP_BMAP_ROOT(val) vxge_vBIT(val, 0, 32) +/*0x01088*/ u64 tim_pci_cfg; +#define VXGE_HW_TIM_PCI_CFG_ADD_PAD vxge_mBIT(7) +#define VXGE_HW_TIM_PCI_CFG_NO_SNOOP vxge_mBIT(15) +#define VXGE_HW_TIM_PCI_CFG_RELAXED vxge_mBIT(23) +#define VXGE_HW_TIM_PCI_CFG_CTL_STR vxge_mBIT(31) + u8 unused01100[0x01100-0x01090]; + +/*0x01100*/ u64 sgrp_assign; +#define VXGE_HW_SGRP_ASSIGN_SGRP_ASSIGN(val) vxge_vBIT(val, 0, 64) +/*0x01108*/ u64 sgrp_aoa_and_result; +#define VXGE_HW_SGRP_AOA_AND_RESULT_PET_SGRP_AOA_AND_RESULT(val) \ + vxge_vBIT(val, 0, 64) +/*0x01110*/ u64 rpe_pci_cfg; +#define VXGE_HW_RPE_PCI_CFG_PAD_LRO_DATA_ENABLE vxge_mBIT(7) +#define VXGE_HW_RPE_PCI_CFG_PAD_LRO_HDR_ENABLE vxge_mBIT(8) +#define VXGE_HW_RPE_PCI_CFG_PAD_LRO_CQE_ENABLE vxge_mBIT(9) +#define VXGE_HW_RPE_PCI_CFG_PAD_NONLL_CQE_ENABLE vxge_mBIT(10) +#define VXGE_HW_RPE_PCI_CFG_PAD_BASE_LL_CQE_ENABLE vxge_mBIT(11) +#define VXGE_HW_RPE_PCI_CFG_PAD_LL_CQE_IDATA_ENABLE vxge_mBIT(12) +#define VXGE_HW_RPE_PCI_CFG_PAD_CQRQ_IR_ENABLE vxge_mBIT(13) +#define VXGE_HW_RPE_PCI_CFG_PAD_CQSQ_IR_ENABLE vxge_mBIT(14) +#define VXGE_HW_RPE_PCI_CFG_PAD_CQRR_IR_ENABLE vxge_mBIT(15) +#define VXGE_HW_RPE_PCI_CFG_NOSNOOP_DATA vxge_mBIT(18) +#define VXGE_HW_RPE_PCI_CFG_NOSNOOP_NONLL_CQE vxge_mBIT(19) +#define VXGE_HW_RPE_PCI_CFG_NOSNOOP_LL_CQE vxge_mBIT(20) +#define VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQRQ_IR vxge_mBIT(21) +#define VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQSQ_IR vxge_mBIT(22) +#define VXGE_HW_RPE_PCI_CFG_NOSNOOP_CQRR_IR vxge_mBIT(23) +#define VXGE_HW_RPE_PCI_CFG_RELAXED_DATA vxge_mBIT(26) +#define VXGE_HW_RPE_PCI_CFG_RELAXED_NONLL_CQE vxge_mBIT(27) +#define VXGE_HW_RPE_PCI_CFG_RELAXED_LL_CQE vxge_mBIT(28) +#define VXGE_HW_RPE_PCI_CFG_RELAXED_CQRQ_IR vxge_mBIT(29) +#define VXGE_HW_RPE_PCI_CFG_RELAXED_CQSQ_IR vxge_mBIT(30) +#define VXGE_HW_RPE_PCI_CFG_RELAXED_CQRR_IR vxge_mBIT(31) +/*0x01118*/ u64 rpe_lro_cfg; +#define VXGE_HW_RPE_LRO_CFG_SUPPRESS_LRO_ETH_TRLR vxge_mBIT(7) +#define VXGE_HW_RPE_LRO_CFG_ALLOW_LRO_SNAP_SNAPJUMBO_MRG vxge_mBIT(11) +#define VXGE_HW_RPE_LRO_CFG_ALLOW_LRO_LLC_LLCJUMBO_MRG vxge_mBIT(15) +#define VXGE_HW_RPE_LRO_CFG_INCL_ACK_CNT_IN_CQE vxge_mBIT(23) +/*0x01120*/ u64 pe_mr2vp_ack_blk_limit; +#define VXGE_HW_PE_MR2VP_ACK_BLK_LIMIT_BLK_LIMIT(val) vxge_vBIT(val, 32, 32) +/*0x01128*/ u64 pe_mr2vp_rirr_lirr_blk_limit; +#define VXGE_HW_PE_MR2VP_RIRR_LIRR_BLK_LIMIT_RIRR_BLK_LIMIT(val) \ + vxge_vBIT(val, 0, 32) +#define VXGE_HW_PE_MR2VP_RIRR_LIRR_BLK_LIMIT_LIRR_BLK_LIMIT(val) \ + vxge_vBIT(val, 32, 32) +/*0x01130*/ u64 txpe_pci_nce_cfg; +#define VXGE_HW_TXPE_PCI_NCE_CFG_NCE_THRESH(val) vxge_vBIT(val, 0, 32) +#define VXGE_HW_TXPE_PCI_NCE_CFG_PAD_TOWI_ENABLE vxge_mBIT(55) +#define VXGE_HW_TXPE_PCI_NCE_CFG_NOSNOOP_TOWI vxge_mBIT(63) + u8 unused01180[0x01180-0x01138]; + +/*0x01180*/ u64 msg_qpad_en_cfg; +#define VXGE_HW_MSG_QPAD_EN_CFG_UMQ_BWR_READ vxge_mBIT(3) +#define VXGE_HW_MSG_QPAD_EN_CFG_DMQ_BWR_READ vxge_mBIT(7) +#define VXGE_HW_MSG_QPAD_EN_CFG_MXP_GENDMA_READ vxge_mBIT(11) +#define VXGE_HW_MSG_QPAD_EN_CFG_UXP_GENDMA_READ vxge_mBIT(15) +#define VXGE_HW_MSG_QPAD_EN_CFG_UMQ_MSG_WRITE vxge_mBIT(19) +#define VXGE_HW_MSG_QPAD_EN_CFG_UMQDMQ_IR_WRITE vxge_mBIT(23) +#define VXGE_HW_MSG_QPAD_EN_CFG_MXP_GENDMA_WRITE vxge_mBIT(27) +#define VXGE_HW_MSG_QPAD_EN_CFG_UXP_GENDMA_WRITE vxge_mBIT(31) +/*0x01188*/ u64 msg_pci_cfg; +#define VXGE_HW_MSG_PCI_CFG_GENDMA_NO_SNOOP vxge_mBIT(3) +#define VXGE_HW_MSG_PCI_CFG_UMQDMQ_IR_NO_SNOOP vxge_mBIT(7) +#define VXGE_HW_MSG_PCI_CFG_UMQ_NO_SNOOP vxge_mBIT(11) +#define VXGE_HW_MSG_PCI_CFG_DMQ_NO_SNOOP vxge_mBIT(15) +/*0x01190*/ u64 umqdmq_ir_init; +#define VXGE_HW_UMQDMQ_IR_INIT_HOST_WRITE_ADD(val) vxge_vBIT(val, 0, 64) +/*0x01198*/ u64 dmq_ir_int; +#define VXGE_HW_DMQ_IR_INT_IMMED_ENABLE vxge_mBIT(6) +#define VXGE_HW_DMQ_IR_INT_EVENT_ENABLE vxge_mBIT(7) +#define VXGE_HW_DMQ_IR_INT_NUMBER(val) vxge_vBIT(val, 9, 7) +#define VXGE_HW_DMQ_IR_INT_BITMAP(val) vxge_vBIT(val, 16, 16) +/*0x011a0*/ u64 dmq_bwr_init_add; +#define VXGE_HW_DMQ_BWR_INIT_ADD_HOST(val) vxge_vBIT(val, 0, 64) +/*0x011a8*/ u64 dmq_bwr_init_byte; +#define VXGE_HW_DMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32) +/*0x011b0*/ u64 dmq_ir; +#define VXGE_HW_DMQ_IR_POLICY(val) vxge_vBIT(val, 0, 8) +/*0x011b8*/ u64 umq_int; +#define VXGE_HW_UMQ_INT_IMMED_ENABLE vxge_mBIT(6) +#define VXGE_HW_UMQ_INT_EVENT_ENABLE vxge_mBIT(7) +#define VXGE_HW_UMQ_INT_NUMBER(val) vxge_vBIT(val, 9, 7) +#define VXGE_HW_UMQ_INT_BITMAP(val) vxge_vBIT(val, 16, 16) +/*0x011c0*/ u64 umq_mr2vp_bwr_pfch_init; +#define VXGE_HW_UMQ_MR2VP_BWR_PFCH_INIT_NUMBER(val) vxge_vBIT(val, 0, 8) +/*0x011c8*/ u64 umq_bwr_pfch_ctrl; +#define VXGE_HW_UMQ_BWR_PFCH_CTRL_POLL_EN vxge_mBIT(3) +/*0x011d0*/ u64 umq_mr2vp_bwr_eol; +#define VXGE_HW_UMQ_MR2VP_BWR_EOL_POLL_LATENCY(val) vxge_vBIT(val, 32, 32) +/*0x011d8*/ u64 umq_bwr_init_add; +#define VXGE_HW_UMQ_BWR_INIT_ADD_HOST(val) vxge_vBIT(val, 0, 64) +/*0x011e0*/ u64 umq_bwr_init_byte; +#define VXGE_HW_UMQ_BWR_INIT_BYTE_COUNT(val) vxge_vBIT(val, 0, 32) +/*0x011e8*/ u64 gendma_int; +#define VXGE_HW_GENDMA_INT_IMMED_ENABLE vxge_mBIT(6) +#define VXGE_HW_GENDMA_INT_EVENT_ENABLE vxge_mBIT(7) +#define VXGE_HW_GENDMA_INT_NUMBER(val) vxge_vBIT(val, 9, 7) +#define VXGE_HW_GENDMA_INT_BITMAP(val) vxge_vBIT(val, 16, 16) +/*0x011f0*/ u64 umqdmq_ir_init_notify; +#define VXGE_HW_UMQDMQ_IR_INIT_NOTIFY_PULSE vxge_mBIT(3) +/*0x011f8*/ u64 dmq_init_notify; +#define VXGE_HW_DMQ_INIT_NOTIFY_PULSE vxge_mBIT(3) +/*0x01200*/ u64 umq_init_notify; +#define VXGE_HW_UMQ_INIT_NOTIFY_PULSE vxge_mBIT(3) + u8 unused01380[0x01380-0x01208]; + +/*0x01380*/ u64 tpa_cfg; +#define VXGE_HW_TPA_CFG_IGNORE_FRAME_ERR vxge_mBIT(3) +#define VXGE_HW_TPA_CFG_IPV6_STOP_SEARCHING vxge_mBIT(7) +#define VXGE_HW_TPA_CFG_L4_PSHDR_PRESENT vxge_mBIT(11) +#define VXGE_HW_TPA_CFG_SUPPORT_MOBILE_IPV6_HDRS vxge_mBIT(15) + u8 unused01400[0x01400-0x01388]; + +/*0x01400*/ u64 tx_vp_reset_discarded_frms; +#define VXGE_HW_TX_VP_RESET_DISCARDED_FRMS_TX_VP_RESET_DISCARDED_FRMS(val) \ + vxge_vBIT(val, 48, 16) + u8 unused01480[0x01480-0x01408]; + +/*0x01480*/ u64 fau_rpa_vcfg; +#define VXGE_HW_FAU_RPA_VCFG_L4_COMP_CSUM vxge_mBIT(7) +#define VXGE_HW_FAU_RPA_VCFG_L3_INCL_CF vxge_mBIT(11) +#define VXGE_HW_FAU_RPA_VCFG_L3_COMP_CSUM vxge_mBIT(15) + u8 unused014d0[0x014d0-0x01488]; + +/*0x014d0*/ u64 dbg_stats_rx_mpa; +#define VXGE_HW_DBG_STATS_RX_MPA_CRC_FAIL_FRMS(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_DBG_STATS_RX_MPA_MRK_FAIL_FRMS(val) vxge_vBIT(val, 16, 16) +#define VXGE_HW_DBG_STATS_RX_MPA_LEN_FAIL_FRMS(val) vxge_vBIT(val, 32, 16) +/*0x014d8*/ u64 dbg_stats_rx_fau; +#define VXGE_HW_DBG_STATS_RX_FAU_RX_WOL_FRMS(val) vxge_vBIT(val, 0, 16) +#define VXGE_HW_DBG_STATS_RX_FAU_RX_VP_RESET_DISCARDED_FRMS(val) \ + vxge_vBIT(val, 16, 16) +#define VXGE_HW_DBG_STATS_RX_FAU_RX_PERMITTED_FRMS(val) \ + vxge_vBIT(val, 32, 32) + u8 unused014f0[0x014f0-0x014e0]; + +/*0x014f0*/ u64 fbmc_vp_rdy; +#define VXGE_HW_FBMC_VP_RDY_QUEUE_SPAV_FM vxge_mBIT(0) + u8 unused01e00[0x01e00-0x014f8]; + +/*0x01e00*/ u64 vpath_pcipif_int_status; +#define \ +VXGE_HW_VPATH_PCIPIF_INT_STATUS_SRPCIM_MSG_TO_VPATH_SRPCIM_MSG_TO_VPATH_INT \ + vxge_mBIT(3) +#define VXGE_HW_VPATH_PCIPIF_INT_STATUS_VPATH_SPARE_R1_VPATH_SPARE_R1_INT \ + vxge_mBIT(7) +/*0x01e08*/ u64 vpath_pcipif_int_mask; + u8 unused01e20[0x01e20-0x01e10]; + +/*0x01e20*/ u64 srpcim_msg_to_vpath_reg; +#define VXGE_HW_SRPCIM_MSG_TO_VPATH_REG_SWIF_SRPCIM_TO_VPATH_RMSG_INT \ + vxge_mBIT(3) +/*0x01e28*/ u64 srpcim_msg_to_vpath_mask; +/*0x01e30*/ u64 srpcim_msg_to_vpath_alarm; + u8 unused01ea0[0x01ea0-0x01e38]; + +/*0x01ea0*/ u64 vpath_to_srpcim_wmsg; +#define VXGE_HW_VPATH_TO_SRPCIM_WMSG_VPATH_TO_SRPCIM_WMSG(val) \ + vxge_vBIT(val, 0, 64) +/*0x01ea8*/ u64 vpath_to_srpcim_wmsg_trig; +#define VXGE_HW_VPATH_TO_SRPCIM_WMSG_TRIG_VPATH_TO_SRPCIM_WMSG_TRIG \ + vxge_mBIT(0) + u8 unused02000[0x02000-0x01eb0]; + +/*0x02000*/ u64 vpath_general_int_status; +#define VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT vxge_mBIT(3) +#define VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT vxge_mBIT(7) +#define VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT vxge_mBIT(15) +#define VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT vxge_mBIT(19) +/*0x02008*/ u64 vpath_general_int_mask; +#define VXGE_HW_VPATH_GENERAL_INT_MASK_PIC_INT vxge_mBIT(3) +#define VXGE_HW_VPATH_GENERAL_INT_MASK_PCI_INT vxge_mBIT(7) +#define VXGE_HW_VPATH_GENERAL_INT_MASK_WRDMA_INT vxge_mBIT(15) +#define VXGE_HW_VPATH_GENERAL_INT_MASK_XMAC_INT vxge_mBIT(19) +/*0x02010*/ u64 vpath_ppif_int_status; +#define VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT \ + vxge_mBIT(3) +#define VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT \ + vxge_mBIT(7) +#define VXGE_HW_VPATH_PPIF_INT_STATUS_PCI_CONFIG_ERRORS_PCI_CONFIG_INT \ + vxge_mBIT(11) +#define \ +VXGE_HW_VPATH_PPIF_INT_STATUS_MRPCIM_TO_VPATH_ALARM_MRPCIM_TO_VPATH_ALARM_INT \ + vxge_mBIT(15) +#define \ +VXGE_HW_VPATH_PPIF_INT_STATUS_SRPCIM_TO_VPATH_ALARM_SRPCIM_TO_VPATH_ALARM_INT \ + vxge_mBIT(19) +/*0x02018*/ u64 vpath_ppif_int_mask; +/*0x02020*/ u64 kdfcctl_errors_reg; +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR vxge_mBIT(3) +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_OVRWR vxge_mBIT(7) +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_OVRWR vxge_mBIT(11) +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON vxge_mBIT(15) +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_POISON vxge_mBIT(19) +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_POISON vxge_mBIT(23) +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR vxge_mBIT(31) +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR vxge_mBIT(35) +#define VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_DMA_ERR vxge_mBIT(39) +/*0x02028*/ u64 kdfcctl_errors_mask; +/*0x02030*/ u64 kdfcctl_errors_alarm; + u8 unused02040[0x02040-0x02038]; + +/*0x02040*/ u64 general_errors_reg; +#define VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW vxge_mBIT(3) +#define VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO1_OVRFLOW vxge_mBIT(7) +#define VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO2_OVRFLOW vxge_mBIT(11) +#define VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR vxge_mBIT(15) +#define VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ vxge_mBIT(19) +#define VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS vxge_mBIT(27) +#define VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET vxge_mBIT(31) +/*0x02048*/ u64 general_errors_mask; +/*0x02050*/ u64 general_errors_alarm; +/*0x02058*/ u64 pci_config_errors_reg; +#define VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_STATUS_ERR vxge_mBIT(3) +#define VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_UNCOR_ERR vxge_mBIT(7) +#define VXGE_HW_PCI_CONFIG_ERRORS_REG_PCICONFIG_COR_ERR vxge_mBIT(11) +/*0x02060*/ u64 pci_config_errors_mask; +/*0x02068*/ u64 pci_config_errors_alarm; +/*0x02070*/ u64 mrpcim_to_vpath_alarm_reg; +#define VXGE_HW_MRPCIM_TO_VPATH_ALARM_REG_PPIF_MRPCIM_TO_VPATH_ALARM \ + vxge_mBIT(3) +/*0x02078*/ u64 mrpcim_to_vpath_alarm_mask; +/*0x02080*/ u64 mrpcim_to_vpath_alarm_alarm; +/*0x02088*/ u64 srpcim_to_vpath_alarm_reg; +#define VXGE_HW_SRPCIM_TO_VPATH_ALARM_REG_PPIF_SRPCIM_TO_VPATH_ALARM(val) \ + vxge_vBIT(val, 0, 17) +/*0x02090*/ u64 srpcim_to_vpath_alarm_mask; +/*0x02098*/ u64 srpcim_to_vpath_alarm_alarm; + u8 unused02108[0x02108-0x020a0]; + +/*0x02108*/ u64 kdfcctl_status; +#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO0_PRES(val) vxge_vBIT(val, 0, 8) +#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO1_PRES(val) vxge_vBIT(val, 8, 8) +#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO2_PRES(val) vxge_vBIT(val, 16, 8) +#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO0_OVRWR(val) vxge_vBIT(val, 24, 8) +#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO1_OVRWR(val) vxge_vBIT(val, 32, 8) +#define VXGE_HW_KDFCCTL_STATUS_KDFCCTL_FIFO2_OVRWR(val) vxge_vBIT(val, 40, 8) +/*0x02110*/ u64 rsthdlr_status; +#define VXGE_HW_RSTHDLR_STATUS_RSTHDLR_CURRENT_RESET vxge_mBIT(3) +#define VXGE_HW_RSTHDLR_STATUS_RSTHDLR_CURRENT_VPIN(val) vxge_vBIT(val, 6, 2) +/*0x02118*/ u64 fifo0_status; +#define VXGE_HW_FIFO0_STATUS_DBLGEN_FIFO0_RDIDX(val) vxge_vBIT(val, 0, 12) +/*0x02120*/ u64 fifo1_status; +#define VXGE_HW_FIFO1_STATUS_DBLGEN_FIFO1_RDIDX(val) vxge_vBIT(val, 0, 12) +/*0x02128*/ u64 fifo2_status; +#define VXGE_HW_FIFO2_STATUS_DBLGEN_FIFO2_RDIDX(val) vxge_vBIT(val, 0, 12) + u8 unused02158[0x02158-0x02130]; + +/*0x02158*/ u64 tgt_illegal_access; +#define VXGE_HW_TGT_ILLEGAL_ACCESS_SWIF_REGION(val) vxge_vBIT(val, 1, 7) + u8 unused02200[0x02200-0x02160]; + +/*0x02200*/ u64 vpath_general_cfg1; +#define VXGE_HW_VPATH_GENERAL_CFG1_TC_VALUE(val) vxge_vBIT(val, 1, 3) +#define VXGE_HW_VPATH_GENERAL_CFG1_DATA_BYTE_SWAPEN vxge_mBIT(7) +#define VXGE_HW_VPATH_GENERAL_CFG1_DATA_FLIPEN vxge_mBIT(11) +#define VXGE_HW_VPATH_GENERAL_CFG1_CTL_BYTE_SWAPEN vxge_mBIT(15) +#define VXGE_HW_VPATH_GENERAL_CFG1_CTL_FLIPEN vxge_mBIT(23) +#define VXGE_HW_VPATH_GENERAL_CFG1_MSIX_ADDR_SWAPEN vxge_mBIT(51) +#define VXGE_HW_VPATH_GENERAL_CFG1_MSIX_ADDR_FLIPEN vxge_mBIT(55) +#define VXGE_HW_VPATH_GENERAL_CFG1_MSIX_DATA_SWAPEN vxge_mBIT(59) +#define VXGE_HW_VPATH_GENERAL_CFG1_MSIX_DATA_FLIPEN vxge_mBIT(63) +/*0x02208*/ u64 vpath_general_cfg2; +#define VXGE_HW_VPATH_GENERAL_CFG2_SIZE_QUANTUM(val) vxge_vBIT(val, 1, 3) +/*0x02210*/ u64 vpath_general_cfg3; +#define VXGE_HW_VPATH_GENERAL_CFG3_IGNORE_VPATH_RST_FOR_INTA vxge_mBIT(3) + u8 unused02220[0x02220-0x02218]; + +/*0x02220*/ u64 kdfcctl_cfg0; +#define VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO0 vxge_mBIT(1) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO1 vxge_mBIT(2) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_SWAPEN_FIFO2 vxge_mBIT(3) +#define VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO0 vxge_mBIT(5) +#define VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO1 vxge_mBIT(6) +#define VXGE_HW_KDFCCTL_CFG0_BIT_FLIPEN_FIFO2 vxge_mBIT(7) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO0 vxge_mBIT(9) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO1 vxge_mBIT(10) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE0_FIFO2 vxge_mBIT(11) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO0 vxge_mBIT(13) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO1 vxge_mBIT(14) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE1_FIFO2 vxge_mBIT(15) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO0 vxge_mBIT(17) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO1 vxge_mBIT(18) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE2_FIFO2 vxge_mBIT(19) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO0 vxge_mBIT(21) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO1 vxge_mBIT(22) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE3_FIFO2 vxge_mBIT(23) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO0 vxge_mBIT(25) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO1 vxge_mBIT(26) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE4_FIFO2 vxge_mBIT(27) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO0 vxge_mBIT(29) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO1 vxge_mBIT(30) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE5_FIFO2 vxge_mBIT(31) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO0 vxge_mBIT(33) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO1 vxge_mBIT(34) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE6_FIFO2 vxge_mBIT(35) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO0 vxge_mBIT(37) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO1 vxge_mBIT(38) +#define VXGE_HW_KDFCCTL_CFG0_BYTE_MASK_BYTE7_FIFO2 vxge_mBIT(39) + + u8 unused02268[0x02268-0x02228]; + +/*0x02268*/ u64 stats_cfg; +#define VXGE_HW_STATS_CFG_START_HOST_ADDR(val) vxge_vBIT(val, 0, 57) +/*0x02270*/ u64 interrupt_cfg0; +#define VXGE_HW_INTERRUPT_CFG0_MSIX_FOR_RXTI(val) vxge_vBIT(val, 1, 7) +#define VXGE_HW_INTERRUPT_CFG0_GROUP0_MSIX_FOR_TXTI(val) vxge_vBIT(val, 9, 7) +#define VXGE_HW_INTERRUPT_CFG0_GROUP1_MSIX_FOR_TXTI(val) vxge_vBIT(val, 17, 7) +#define VXGE_HW_INTERRUPT_CFG0_GROUP2_MSIX_FOR_TXTI(val) vxge_vBIT(val, 25, 7) +#define VXGE_HW_INTERRUPT_CFG0_GROUP3_MSIX_FOR_TXTI(val) vxge_vBIT(val, 33, 7) + u8 unused02280[0x02280-0x02278]; + +/*0x02280*/ u64 interrupt_cfg2; +#define VXGE_HW_INTERRUPT_CFG2_ALARM_MAP_TO_MSG(val) vxge_vBIT(val, 1, 7) +/*0x02288*/ u64 one_shot_vect0_en; +#define VXGE_HW_ONE_SHOT_VECT0_EN_ONE_SHOT_VECT0_EN vxge_mBIT(3) +/*0x02290*/ u64 one_shot_vect1_en; +#define VXGE_HW_ONE_SHOT_VECT1_EN_ONE_SHOT_VECT1_EN vxge_mBIT(3) +/*0x02298*/ u64 one_shot_vect2_en; +#define VXGE_HW_ONE_SHOT_VECT2_EN_ONE_SHOT_VECT2_EN vxge_mBIT(3) +/*0x022a0*/ u64 one_shot_vect3_en; +#define VXGE_HW_ONE_SHOT_VECT3_EN_ONE_SHOT_VECT3_EN vxge_mBIT(3) + u8 unused022b0[0x022b0-0x022a8]; + +/*0x022b0*/ u64 pci_config_access_cfg1; +#define VXGE_HW_PCI_CONFIG_ACCESS_CFG1_ADDRESS(val) vxge_vBIT(val, 0, 12) +#define VXGE_HW_PCI_CONFIG_ACCESS_CFG1_SEL_FUNC0 vxge_mBIT(15) +/*0x022b8*/ u64 pci_config_access_cfg2; +#define VXGE_HW_PCI_CONFIG_ACCESS_CFG2_REQ vxge_mBIT(0) +/*0x022c0*/ u64 pci_config_access_status; +#define VXGE_HW_PCI_CONFIG_ACCESS_STATUS_ACCESS_ERR vxge_mBIT(0) +#define VXGE_HW_PCI_CONFIG_ACCESS_STATUS_DATA(val) vxge_vBIT(val, 32, 32) + u8 unused02300[0x02300-0x022c8]; + +/*0x02300*/ u64 vpath_debug_stats0; +#define VXGE_HW_VPATH_DEBUG_STATS0_INI_NUM_MWR_SENT(val) vxge_vBIT(val, 0, 32) +/*0x02308*/ u64 vpath_debug_stats1; +#define VXGE_HW_VPATH_DEBUG_STATS1_INI_NUM_MRD_SENT(val) vxge_vBIT(val, 0, 32) +/*0x02310*/ u64 vpath_debug_stats2; +#define VXGE_HW_VPATH_DEBUG_STATS2_INI_NUM_CPL_RCVD(val) vxge_vBIT(val, 0, 32) +/*0x02318*/ u64 vpath_debug_stats3; +#define VXGE_HW_VPATH_DEBUG_STATS3_INI_NUM_MWR_BYTE_SENT(val) \ + vxge_vBIT(val, 0, 64) +/*0x02320*/ u64 vpath_debug_stats4; +#define VXGE_HW_VPATH_DEBUG_STATS4_INI_NUM_CPL_BYTE_RCVD(val) \ + vxge_vBIT(val, 0, 64) +/*0x02328*/ u64 vpath_debug_stats5; +#define VXGE_HW_VPATH_DEBUG_STATS5_WRCRDTARB_XOFF(val) vxge_vBIT(val, 32, 32) +/*0x02330*/ u64 vpath_debug_stats6; +#define VXGE_HW_VPATH_DEBUG_STATS6_RDCRDTARB_XOFF(val) vxge_vBIT(val, 32, 32) +/*0x02338*/ u64 vpath_genstats_count01; +#define VXGE_HW_VPATH_GENSTATS_COUNT01_PPIF_VPATH_GENSTATS_COUNT1(val) \ + vxge_vBIT(val, 0, 32) +#define VXGE_HW_VPATH_GENSTATS_COUNT01_PPIF_VPATH_GENSTATS_COUNT0(val) \ + vxge_vBIT(val, 32, 32) +/*0x02340*/ u64 vpath_genstats_count23; +#define VXGE_HW_VPATH_GENSTATS_COUNT23_PPIF_VPATH_GENSTATS_COUNT3(val) \ + vxge_vBIT(val, 0, 32) +#define VXGE_HW_VPATH_GENSTATS_COUNT23_PPIF_VPATH_GENSTATS_COUNT2(val) \ + vxge_vBIT(val, 32, 32) +/*0x02348*/ u64 vpath_genstats_count4; +#define VXGE_HW_VPATH_GENSTATS_COUNT4_PPIF_VPATH_GENSTATS_COUNT4(val) \ + vxge_vBIT(val, 32, 32) +/*0x02350*/ u64 vpath_genstats_count5; +#define VXGE_HW_VPATH_GENSTATS_COUNT5_PPIF_VPATH_GENSTATS_COUNT5(val) \ + vxge_vBIT(val, 32, 32) + u8 unused02648[0x02648-0x02358]; +} __packed; + +#define VXGE_HW_EEPROM_SIZE (0x01 << 11) + +/* Capability lists */ +#define VXGE_HW_PCI_EXP_LNKCAP_LNK_SPEED 0xf /* Supported Link speeds */ +#define VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH 0x3f0 /* Supported Link speeds. */ +#define VXGE_HW_PCI_EXP_LNKCAP_LW_RES 0x0 /* Reserved. */ + +#endif diff --git a/trunk/drivers/net/vxge/vxge-traffic.c b/trunk/drivers/net/vxge/vxge-traffic.c new file mode 100644 index 000000000000..7be0ae10d69b --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-traffic.c @@ -0,0 +1,2528 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-traffic.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#include + +#include "vxge-traffic.h" +#include "vxge-config.h" +#include "vxge-main.h" + +/* + * vxge_hw_vpath_intr_enable - Enable vpath interrupts. + * @vp: Virtual Path handle. + * + * Enable vpath interrupts. The function is to be executed the last in + * vpath initialization sequence. + * + * See also: vxge_hw_vpath_intr_disable() + */ +enum vxge_hw_status vxge_hw_vpath_intr_enable(struct __vxge_hw_vpath_handle *vp) +{ + u64 val64; + + struct __vxge_hw_virtualpath *vpath; + struct vxge_hw_vpath_reg __iomem *vp_reg; + enum vxge_hw_status status = VXGE_HW_OK; + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto exit; + } + + vp_reg = vpath->vp_reg; + + writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_reg); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->general_errors_reg); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->pci_config_errors_reg); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->mrpcim_to_vpath_alarm_reg); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->srpcim_to_vpath_alarm_reg); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->vpath_ppif_int_status); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->srpcim_msg_to_vpath_reg); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->vpath_pcipif_int_status); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->prc_alarm_reg); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->wrdma_alarm_status); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->asic_ntwk_vp_err_reg); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->xgmac_vp_int_status); + + val64 = readq(&vp_reg->vpath_general_int_status); + + /* Mask unwanted interrupts */ + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->vpath_pcipif_int_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->srpcim_msg_to_vpath_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->srpcim_to_vpath_alarm_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->mrpcim_to_vpath_alarm_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->pci_config_errors_mask); + + /* Unmask the individual interrupts */ + + writeq((u32)vxge_bVALn((VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO1_OVRFLOW| + VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO2_OVRFLOW| + VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ| + VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR), 0, 32), + &vp_reg->general_errors_mask); + + __vxge_hw_pio_mem_write32_upper( + (u32)vxge_bVALn((VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_OVRWR| + VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_OVRWR| + VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_POISON| + VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO2_POISON| + VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR| + VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO1_DMA_ERR), 0, 32), + &vp_reg->kdfcctl_errors_mask); + + __vxge_hw_pio_mem_write32_upper(0, &vp_reg->vpath_ppif_int_mask); + + __vxge_hw_pio_mem_write32_upper( + (u32)vxge_bVALn(VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP, 0, 32), + &vp_reg->prc_alarm_mask); + + __vxge_hw_pio_mem_write32_upper(0, &vp_reg->wrdma_alarm_mask); + __vxge_hw_pio_mem_write32_upper(0, &vp_reg->xgmac_vp_int_mask); + + if (vpath->hldev->first_vp_id != vpath->vp_id) + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->asic_ntwk_vp_err_mask); + else + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(( + VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_FAULT | + VXGE_HW_ASIC_NTWK_VP_ERR_REG_XMACJ_NTWK_REAFFIRMED_OK), 0, 32), + &vp_reg->asic_ntwk_vp_err_mask); + + __vxge_hw_pio_mem_write32_upper(0, + &vp_reg->vpath_general_int_mask); +exit: + return status; + +} + +/* + * vxge_hw_vpath_intr_disable - Disable vpath interrupts. + * @vp: Virtual Path handle. + * + * Disable vpath interrupts. The function is to be executed the last in + * vpath initialization sequence. + * + * See also: vxge_hw_vpath_intr_enable() + */ +enum vxge_hw_status vxge_hw_vpath_intr_disable( + struct __vxge_hw_vpath_handle *vp) +{ + u64 val64; + + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status = VXGE_HW_OK; + struct vxge_hw_vpath_reg __iomem *vp_reg; + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + + if (vpath->vp_open == VXGE_HW_VP_NOT_OPEN) { + status = VXGE_HW_ERR_VPATH_NOT_OPEN; + goto exit; + } + vp_reg = vpath->vp_reg; + + __vxge_hw_pio_mem_write32_upper( + (u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->vpath_general_int_mask); + + val64 = VXGE_HW_TIM_CLR_INT_EN_VP(1 << (16 - vpath->vp_id)); + + writeq(VXGE_HW_INTR_MASK_ALL, &vp_reg->kdfcctl_errors_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->general_errors_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->pci_config_errors_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->mrpcim_to_vpath_alarm_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->srpcim_to_vpath_alarm_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->vpath_ppif_int_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->srpcim_msg_to_vpath_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->vpath_pcipif_int_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->wrdma_alarm_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->prc_alarm_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->xgmac_vp_int_mask); + + __vxge_hw_pio_mem_write32_upper((u32)VXGE_HW_INTR_MASK_ALL, + &vp_reg->asic_ntwk_vp_err_mask); + +exit: + return status; +} + +/** + * vxge_hw_channel_msix_mask - Mask MSIX Vector. + * @channeh: Channel for rx or tx handle + * @msix_id: MSIX ID + * + * The function masks the msix interrupt for the given msix_id + * + * Returns: 0 + */ +void vxge_hw_channel_msix_mask(struct __vxge_hw_channel *channel, int msix_id) +{ + + __vxge_hw_pio_mem_write32_upper( + (u32)vxge_bVALn(vxge_mBIT(channel->first_vp_id+(msix_id/4)), + 0, 32), + &channel->common_reg->set_msix_mask_vect[msix_id%4]); + + return; +} + +/** + * vxge_hw_channel_msix_unmask - Unmask the MSIX Vector. + * @channeh: Channel for rx or tx handle + * @msix_id: MSI ID + * + * The function unmasks the msix interrupt for the given msix_id + * + * Returns: 0 + */ +void +vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channel, int msix_id) +{ + + __vxge_hw_pio_mem_write32_upper( + (u32)vxge_bVALn(vxge_mBIT(channel->first_vp_id+(msix_id/4)), + 0, 32), + &channel->common_reg->clear_msix_mask_vect[msix_id%4]); + + return; +} + +/** + * vxge_hw_device_set_intr_type - Updates the configuration + * with new interrupt type. + * @hldev: HW device handle. + * @intr_mode: New interrupt type + */ +u32 vxge_hw_device_set_intr_type(struct __vxge_hw_device *hldev, u32 intr_mode) +{ + + if ((intr_mode != VXGE_HW_INTR_MODE_IRQLINE) && + (intr_mode != VXGE_HW_INTR_MODE_MSIX) && + (intr_mode != VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) && + (intr_mode != VXGE_HW_INTR_MODE_DEF)) + intr_mode = VXGE_HW_INTR_MODE_IRQLINE; + + hldev->config.intr_mode = intr_mode; + return intr_mode; +} + +/** + * vxge_hw_device_intr_enable - Enable interrupts. + * @hldev: HW device handle. + * @op: One of the enum vxge_hw_device_intr enumerated values specifying + * the type(s) of interrupts to enable. + * + * Enable Titan interrupts. The function is to be executed the last in + * Titan initialization sequence. + * + * See also: vxge_hw_device_intr_disable() + */ +void vxge_hw_device_intr_enable(struct __vxge_hw_device *hldev) +{ + u32 i; + u64 val64; + u32 val32; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpaths_deployed & vxge_mBIT(i))) + continue; + + vxge_hw_vpath_intr_enable( + VXGE_HW_VIRTUAL_PATH_HANDLE(&hldev->virtual_paths[i])); + } + + if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_IRQLINE) { + val64 = hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] | + hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX]; + + if (val64 != 0) { + writeq(val64, &hldev->common_reg->tim_int_status0); + + writeq(~val64, &hldev->common_reg->tim_int_mask0); + } + + val32 = hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] | + hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX]; + + if (val32 != 0) { + __vxge_hw_pio_mem_write32_upper(val32, + &hldev->common_reg->tim_int_status1); + + __vxge_hw_pio_mem_write32_upper(~val32, + &hldev->common_reg->tim_int_mask1); + } + } + + val64 = readq(&hldev->common_reg->titan_general_int_status); + + vxge_hw_device_unmask_all(hldev); + + return; +} + +/** + * vxge_hw_device_intr_disable - Disable Titan interrupts. + * @hldev: HW device handle. + * @op: One of the enum vxge_hw_device_intr enumerated values specifying + * the type(s) of interrupts to disable. + * + * Disable Titan interrupts. + * + * See also: vxge_hw_device_intr_enable() + */ +void vxge_hw_device_intr_disable(struct __vxge_hw_device *hldev) +{ + u32 i; + + vxge_hw_device_mask_all(hldev); + + /* mask all the tim interrupts */ + writeq(VXGE_HW_INTR_MASK_ALL, &hldev->common_reg->tim_int_mask0); + __vxge_hw_pio_mem_write32_upper(VXGE_HW_DEFAULT_32, + &hldev->common_reg->tim_int_mask1); + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpaths_deployed & vxge_mBIT(i))) + continue; + + vxge_hw_vpath_intr_disable( + VXGE_HW_VIRTUAL_PATH_HANDLE(&hldev->virtual_paths[i])); + } + + return; +} + +/** + * vxge_hw_device_mask_all - Mask all device interrupts. + * @hldev: HW device handle. + * + * Mask all device interrupts. + * + * See also: vxge_hw_device_unmask_all() + */ +void vxge_hw_device_mask_all(struct __vxge_hw_device *hldev) +{ + u64 val64; + + val64 = VXGE_HW_TITAN_MASK_ALL_INT_ALARM | + VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC; + + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), + &hldev->common_reg->titan_mask_all_int); + + return; +} + +/** + * vxge_hw_device_unmask_all - Unmask all device interrupts. + * @hldev: HW device handle. + * + * Unmask all device interrupts. + * + * See also: vxge_hw_device_mask_all() + */ +void vxge_hw_device_unmask_all(struct __vxge_hw_device *hldev) +{ + u64 val64 = 0; + + if (hldev->config.intr_mode == VXGE_HW_INTR_MODE_IRQLINE) + val64 = VXGE_HW_TITAN_MASK_ALL_INT_TRAFFIC; + + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn(val64, 0, 32), + &hldev->common_reg->titan_mask_all_int); + + return; +} + +/** + * vxge_hw_device_flush_io - Flush io writes. + * @hldev: HW device handle. + * + * The function performs a read operation to flush io writes. + * + * Returns: void + */ +void vxge_hw_device_flush_io(struct __vxge_hw_device *hldev) +{ + u32 val32; + + val32 = readl(&hldev->common_reg->titan_general_int_status); +} + +/** + * vxge_hw_device_begin_irq - Begin IRQ processing. + * @hldev: HW device handle. + * @skip_alarms: Do not clear the alarms + * @reason: "Reason" for the interrupt, the value of Titan's + * general_int_status register. + * + * The function performs two actions, It first checks whether (shared IRQ) the + * interrupt was raised by the device. Next, it masks the device interrupts. + * + * Note: + * vxge_hw_device_begin_irq() does not flush MMIO writes through the + * bridge. Therefore, two back-to-back interrupts are potentially possible. + * + * Returns: 0, if the interrupt is not "ours" (note that in this case the + * device remain enabled). + * Otherwise, vxge_hw_device_begin_irq() returns 64bit general adapter + * status. + */ +enum vxge_hw_status vxge_hw_device_begin_irq(struct __vxge_hw_device *hldev, + u32 skip_alarms, u64 *reason) +{ + u32 i; + u64 val64; + u64 adapter_status; + u64 vpath_mask; + enum vxge_hw_status ret = VXGE_HW_OK; + + val64 = readq(&hldev->common_reg->titan_general_int_status); + + if (unlikely(!val64)) { + /* not Titan interrupt */ + *reason = 0; + ret = VXGE_HW_ERR_WRONG_IRQ; + goto exit; + } + + if (unlikely(val64 == VXGE_HW_ALL_FOXES)) { + + adapter_status = readq(&hldev->common_reg->adapter_status); + + if (adapter_status == VXGE_HW_ALL_FOXES) { + + __vxge_hw_device_handle_error(hldev, + NULL_VPID, VXGE_HW_EVENT_SLOT_FREEZE); + *reason = 0; + ret = VXGE_HW_ERR_SLOT_FREEZE; + goto exit; + } + } + + hldev->stats.sw_dev_info_stats.total_intr_cnt++; + + *reason = val64; + + vpath_mask = hldev->vpaths_deployed >> + (64 - VXGE_HW_MAX_VIRTUAL_PATHS); + + if (val64 & + VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_TRAFFIC_INT(vpath_mask)) { + hldev->stats.sw_dev_info_stats.traffic_intr_cnt++; + + return VXGE_HW_OK; + } + + hldev->stats.sw_dev_info_stats.not_traffic_intr_cnt++; + + if (unlikely(val64 & + VXGE_HW_TITAN_GENERAL_INT_STATUS_VPATH_ALARM_INT)) { + + enum vxge_hw_status error_level = VXGE_HW_OK; + + hldev->stats.sw_dev_err_stats.vpath_alarms++; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpaths_deployed & vxge_mBIT(i))) + continue; + + ret = __vxge_hw_vpath_alarm_process( + &hldev->virtual_paths[i], skip_alarms); + + error_level = VXGE_HW_SET_LEVEL(ret, error_level); + + if (unlikely((ret == VXGE_HW_ERR_CRITICAL) || + (ret == VXGE_HW_ERR_SLOT_FREEZE))) + break; + } + + ret = error_level; + } +exit: + return ret; +} + +/* + * __vxge_hw_device_handle_link_up_ind + * @hldev: HW device handle. + * + * Link up indication handler. The function is invoked by HW when + * Titan indicates that the link is up for programmable amount of time. + */ +enum vxge_hw_status +__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev) +{ + /* + * If the previous link state is not down, return. + */ + if (hldev->link_state == VXGE_HW_LINK_UP) + goto exit; + + hldev->link_state = VXGE_HW_LINK_UP; + + /* notify driver */ + if (hldev->uld_callbacks.link_up) + hldev->uld_callbacks.link_up(hldev); +exit: + return VXGE_HW_OK; +} + +/* + * __vxge_hw_device_handle_link_down_ind + * @hldev: HW device handle. + * + * Link down indication handler. The function is invoked by HW when + * Titan indicates that the link is down. + */ +enum vxge_hw_status +__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev) +{ + /* + * If the previous link state is not down, return. + */ + if (hldev->link_state == VXGE_HW_LINK_DOWN) + goto exit; + + hldev->link_state = VXGE_HW_LINK_DOWN; + + /* notify driver */ + if (hldev->uld_callbacks.link_down) + hldev->uld_callbacks.link_down(hldev); +exit: + return VXGE_HW_OK; +} + +/** + * __vxge_hw_device_handle_error - Handle error + * @hldev: HW device + * @vp_id: Vpath Id + * @type: Error type. Please see enum vxge_hw_event{} + * + * Handle error. + */ +enum vxge_hw_status +__vxge_hw_device_handle_error( + struct __vxge_hw_device *hldev, + u32 vp_id, + enum vxge_hw_event type) +{ + switch (type) { + case VXGE_HW_EVENT_UNKNOWN: + break; + case VXGE_HW_EVENT_RESET_START: + case VXGE_HW_EVENT_RESET_COMPLETE: + case VXGE_HW_EVENT_LINK_DOWN: + case VXGE_HW_EVENT_LINK_UP: + goto out; + case VXGE_HW_EVENT_ALARM_CLEARED: + goto out; + case VXGE_HW_EVENT_ECCERR: + case VXGE_HW_EVENT_MRPCIM_ECCERR: + goto out; + case VXGE_HW_EVENT_FIFO_ERR: + case VXGE_HW_EVENT_VPATH_ERR: + case VXGE_HW_EVENT_CRITICAL_ERR: + case VXGE_HW_EVENT_SERR: + break; + case VXGE_HW_EVENT_SRPCIM_SERR: + case VXGE_HW_EVENT_MRPCIM_SERR: + goto out; + case VXGE_HW_EVENT_SLOT_FREEZE: + break; + default: + vxge_assert(0); + goto out; + } + + /* notify driver */ + if (hldev->uld_callbacks.crit_err) + hldev->uld_callbacks.crit_err( + (struct __vxge_hw_device *)hldev, + type, vp_id); +out: + + return VXGE_HW_OK; +} + +/** + * vxge_hw_device_clear_tx_rx - Acknowledge (that is, clear) the + * condition that has caused the Tx and RX interrupt. + * @hldev: HW device. + * + * Acknowledge (that is, clear) the condition that has caused + * the Tx and Rx interrupt. + * See also: vxge_hw_device_begin_irq(), + * vxge_hw_device_mask_tx_rx(), vxge_hw_device_unmask_tx_rx(). + */ +void vxge_hw_device_clear_tx_rx(struct __vxge_hw_device *hldev) +{ + + if ((hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) || + (hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) { + writeq((hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_TX] | + hldev->tim_int_mask0[VXGE_HW_VPATH_INTR_RX]), + &hldev->common_reg->tim_int_status0); + } + + if ((hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) || + (hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) { + __vxge_hw_pio_mem_write32_upper( + (hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_TX] | + hldev->tim_int_mask1[VXGE_HW_VPATH_INTR_RX]), + &hldev->common_reg->tim_int_status1); + } + + return; +} + +/* + * vxge_hw_channel_dtr_alloc - Allocate a dtr from the channel + * @channel: Channel + * @dtrh: Buffer to return the DTR pointer + * + * Allocates a dtr from the reserve array. If the reserve array is empty, + * it swaps the reserve and free arrays. + * + */ +enum vxge_hw_status +vxge_hw_channel_dtr_alloc(struct __vxge_hw_channel *channel, void **dtrh) +{ + void **tmp_arr; + + if (channel->reserve_ptr - channel->reserve_top > 0) { +_alloc_after_swap: + *dtrh = channel->reserve_arr[--channel->reserve_ptr]; + + return VXGE_HW_OK; + } + + /* switch between empty and full arrays */ + + /* the idea behind such a design is that by having free and reserved + * arrays separated we basically separated irq and non-irq parts. + * i.e. no additional lock need to be done when we free a resource */ + + if (channel->length - channel->free_ptr > 0) { + + tmp_arr = channel->reserve_arr; + channel->reserve_arr = channel->free_arr; + channel->free_arr = tmp_arr; + channel->reserve_ptr = channel->length; + channel->reserve_top = channel->free_ptr; + channel->free_ptr = channel->length; + + channel->stats->reserve_free_swaps_cnt++; + + goto _alloc_after_swap; + } + + channel->stats->full_cnt++; + + *dtrh = NULL; + return VXGE_HW_INF_OUT_OF_DESCRIPTORS; +} + +/* + * vxge_hw_channel_dtr_post - Post a dtr to the channel + * @channelh: Channel + * @dtrh: DTR pointer + * + * Posts a dtr to work array. + * + */ +void vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel, void *dtrh) +{ + vxge_assert(channel->work_arr[channel->post_index] == NULL); + + channel->work_arr[channel->post_index++] = dtrh; + + /* wrap-around */ + if (channel->post_index == channel->length) + channel->post_index = 0; +} + +/* + * vxge_hw_channel_dtr_try_complete - Returns next completed dtr + * @channel: Channel + * @dtr: Buffer to return the next completed DTR pointer + * + * Returns the next completed dtr with out removing it from work array + * + */ +void +vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel, void **dtrh) +{ + vxge_assert(channel->compl_index < channel->length); + + *dtrh = channel->work_arr[channel->compl_index]; +} + +/* + * vxge_hw_channel_dtr_complete - Removes next completed dtr from the work array + * @channel: Channel handle + * + * Removes the next completed dtr from work array + * + */ +void vxge_hw_channel_dtr_complete(struct __vxge_hw_channel *channel) +{ + channel->work_arr[channel->compl_index] = NULL; + + /* wrap-around */ + if (++channel->compl_index == channel->length) + channel->compl_index = 0; + + channel->stats->total_compl_cnt++; +} + +/* + * vxge_hw_channel_dtr_free - Frees a dtr + * @channel: Channel handle + * @dtr: DTR pointer + * + * Returns the dtr to free array + * + */ +void vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh) +{ + channel->free_arr[--channel->free_ptr] = dtrh; +} + +/* + * vxge_hw_channel_dtr_count + * @channel: Channel handle. Obtained via vxge_hw_channel_open(). + * + * Retreive number of DTRs available. This function can not be called + * from data path. ring_initial_replenishi() is the only user. + */ +int vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel) +{ + return (channel->reserve_ptr - channel->reserve_top) + + (channel->length - channel->free_ptr); +} + +/** + * vxge_hw_ring_rxd_reserve - Reserve ring descriptor. + * @ring: Handle to the ring object used for receive + * @rxdh: Reserved descriptor. On success HW fills this "out" parameter + * with a valid handle. + * + * Reserve Rx descriptor for the subsequent filling-in driver + * and posting on the corresponding channel (@channelh) + * via vxge_hw_ring_rxd_post(). + * + * Returns: VXGE_HW_OK - success. + * VXGE_HW_INF_OUT_OF_DESCRIPTORS - Currently no descriptors available. + * + */ +enum vxge_hw_status vxge_hw_ring_rxd_reserve(struct __vxge_hw_ring *ring, + void **rxdh) +{ + enum vxge_hw_status status; + struct __vxge_hw_channel *channel; + + channel = &ring->channel; + + status = vxge_hw_channel_dtr_alloc(channel, rxdh); + + if (status == VXGE_HW_OK) { + struct vxge_hw_ring_rxd_1 *rxdp = + (struct vxge_hw_ring_rxd_1 *)*rxdh; + + rxdp->control_0 = rxdp->control_1 = 0; + } + + return status; +} + +/** + * vxge_hw_ring_rxd_free - Free descriptor. + * @ring: Handle to the ring object used for receive + * @rxdh: Descriptor handle. + * + * Free the reserved descriptor. This operation is "symmetrical" to + * vxge_hw_ring_rxd_reserve. The "free-ing" completes the descriptor's + * lifecycle. + * + * After free-ing (see vxge_hw_ring_rxd_free()) the descriptor again can + * be: + * + * - reserved (vxge_hw_ring_rxd_reserve); + * + * - posted (vxge_hw_ring_rxd_post); + * + * - completed (vxge_hw_ring_rxd_next_completed); + * + * - and recycled again (vxge_hw_ring_rxd_free). + * + * For alternative state transitions and more details please refer to + * the design doc. + * + */ +void vxge_hw_ring_rxd_free(struct __vxge_hw_ring *ring, void *rxdh) +{ + struct __vxge_hw_channel *channel; + + channel = &ring->channel; + + vxge_hw_channel_dtr_free(channel, rxdh); + +} + +/** + * vxge_hw_ring_rxd_pre_post - Prepare rxd and post + * @ring: Handle to the ring object used for receive + * @rxdh: Descriptor handle. + * + * This routine prepares a rxd and posts + */ +void vxge_hw_ring_rxd_pre_post(struct __vxge_hw_ring *ring, void *rxdh) +{ + struct __vxge_hw_channel *channel; + + channel = &ring->channel; + + vxge_hw_channel_dtr_post(channel, rxdh); +} + +/** + * vxge_hw_ring_rxd_post_post - Process rxd after post. + * @ring: Handle to the ring object used for receive + * @rxdh: Descriptor handle. + * + * Processes rxd after post + */ +void vxge_hw_ring_rxd_post_post(struct __vxge_hw_ring *ring, void *rxdh) +{ + struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh; + struct __vxge_hw_channel *channel; + + channel = &ring->channel; + + rxdp->control_0 |= VXGE_HW_RING_RXD_LIST_OWN_ADAPTER; + + if (ring->stats->common_stats.usage_cnt > 0) + ring->stats->common_stats.usage_cnt--; +} + +/** + * vxge_hw_ring_rxd_post - Post descriptor on the ring. + * @ring: Handle to the ring object used for receive + * @rxdh: Descriptor obtained via vxge_hw_ring_rxd_reserve(). + * + * Post descriptor on the ring. + * Prior to posting the descriptor should be filled in accordance with + * Host/Titan interface specification for a given service (LL, etc.). + * + */ +void vxge_hw_ring_rxd_post(struct __vxge_hw_ring *ring, void *rxdh) +{ + struct vxge_hw_ring_rxd_1 *rxdp = (struct vxge_hw_ring_rxd_1 *)rxdh; + struct __vxge_hw_channel *channel; + + channel = &ring->channel; + + wmb(); + rxdp->control_0 |= VXGE_HW_RING_RXD_LIST_OWN_ADAPTER; + + vxge_hw_channel_dtr_post(channel, rxdh); + + if (ring->stats->common_stats.usage_cnt > 0) + ring->stats->common_stats.usage_cnt--; +} + +/** + * vxge_hw_ring_rxd_post_post_wmb - Process rxd after post with memory barrier. + * @ring: Handle to the ring object used for receive + * @rxdh: Descriptor handle. + * + * Processes rxd after post with memory barrier. + */ +void vxge_hw_ring_rxd_post_post_wmb(struct __vxge_hw_ring *ring, void *rxdh) +{ + struct __vxge_hw_channel *channel; + + channel = &ring->channel; + + wmb(); + vxge_hw_ring_rxd_post_post(ring, rxdh); +} + +/** + * vxge_hw_ring_rxd_next_completed - Get the _next_ completed descriptor. + * @ring: Handle to the ring object used for receive + * @rxdh: Descriptor handle. Returned by HW. + * @t_code: Transfer code, as per Titan User Guide, + * Receive Descriptor Format. Returned by HW. + * + * Retrieve the _next_ completed descriptor. + * HW uses ring callback (*vxge_hw_ring_callback_f) to notifiy + * driver of new completed descriptors. After that + * the driver can use vxge_hw_ring_rxd_next_completed to retrieve the rest + * completions (the very first completion is passed by HW via + * vxge_hw_ring_callback_f). + * + * Implementation-wise, the driver is free to call + * vxge_hw_ring_rxd_next_completed either immediately from inside the + * ring callback, or in a deferred fashion and separate (from HW) + * context. + * + * Non-zero @t_code means failure to fill-in receive buffer(s) + * of the descriptor. + * For instance, parity error detected during the data transfer. + * In this case Titan will complete the descriptor and indicate + * for the host that the received data is not to be used. + * For details please refer to Titan User Guide. + * + * Returns: VXGE_HW_OK - success. + * VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS - No completed descriptors + * are currently available for processing. + * + * See also: vxge_hw_ring_callback_f{}, + * vxge_hw_fifo_rxd_next_completed(), enum vxge_hw_status{}. + */ +enum vxge_hw_status vxge_hw_ring_rxd_next_completed( + struct __vxge_hw_ring *ring, void **rxdh, u8 *t_code) +{ + struct __vxge_hw_channel *channel; + struct vxge_hw_ring_rxd_1 *rxdp; + enum vxge_hw_status status = VXGE_HW_OK; + + channel = &ring->channel; + + vxge_hw_channel_dtr_try_complete(channel, rxdh); + + rxdp = (struct vxge_hw_ring_rxd_1 *)*rxdh; + if (rxdp == NULL) { + status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS; + goto exit; + } + + /* check whether it is not the end */ + if (!(rxdp->control_0 & VXGE_HW_RING_RXD_LIST_OWN_ADAPTER)) { + + vxge_assert(((struct vxge_hw_ring_rxd_1 *)rxdp)->host_control != + 0); + + ++ring->cmpl_cnt; + vxge_hw_channel_dtr_complete(channel); + + *t_code = (u8)VXGE_HW_RING_RXD_T_CODE_GET(rxdp->control_0); + + vxge_assert(*t_code != VXGE_HW_RING_RXD_T_CODE_UNUSED); + + ring->stats->common_stats.usage_cnt++; + if (ring->stats->common_stats.usage_max < + ring->stats->common_stats.usage_cnt) + ring->stats->common_stats.usage_max = + ring->stats->common_stats.usage_cnt; + + status = VXGE_HW_OK; + goto exit; + } + + /* reset it. since we don't want to return + * garbage to the driver */ + *rxdh = NULL; + status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS; +exit: + return status; +} + +/** + * vxge_hw_ring_handle_tcode - Handle transfer code. + * @ring: Handle to the ring object used for receive + * @rxdh: Descriptor handle. + * @t_code: One of the enumerated (and documented in the Titan user guide) + * "transfer codes". + * + * Handle descriptor's transfer code. The latter comes with each completed + * descriptor. + * + * Returns: one of the enum vxge_hw_status{} enumerated types. + * VXGE_HW_OK - for success. + * VXGE_HW_ERR_CRITICAL - when encounters critical error. + */ +enum vxge_hw_status vxge_hw_ring_handle_tcode( + struct __vxge_hw_ring *ring, void *rxdh, u8 t_code) +{ + struct __vxge_hw_channel *channel; + enum vxge_hw_status status = VXGE_HW_OK; + + channel = &ring->channel; + + /* If the t_code is not supported and if the + * t_code is other than 0x5 (unparseable packet + * such as unknown UPV6 header), Drop it !!! + */ + + if (t_code == 0 || t_code == 5) { + status = VXGE_HW_OK; + goto exit; + } + + if (t_code > 0xF) { + status = VXGE_HW_ERR_INVALID_TCODE; + goto exit; + } + + ring->stats->rxd_t_code_err_cnt[t_code]++; +exit: + return status; +} + +/** + * __vxge_hw_non_offload_db_post - Post non offload doorbell + * + * @fifo: fifohandle + * @txdl_ptr: The starting location of the TxDL in host memory + * @num_txds: The highest TxD in this TxDL (0 to 255 means 1 to 256) + * @no_snoop: No snoop flags + * + * This function posts a non-offload doorbell to doorbell FIFO + * + */ +static void __vxge_hw_non_offload_db_post(struct __vxge_hw_fifo *fifo, + u64 txdl_ptr, u32 num_txds, u32 no_snoop) +{ + struct __vxge_hw_channel *channel; + + channel = &fifo->channel; + + writeq(VXGE_HW_NODBW_TYPE(VXGE_HW_NODBW_TYPE_NODBW) | + VXGE_HW_NODBW_LAST_TXD_NUMBER(num_txds) | + VXGE_HW_NODBW_GET_NO_SNOOP(no_snoop), + &fifo->nofl_db->control_0); + + wmb(); + + writeq(txdl_ptr, &fifo->nofl_db->txdl_ptr); + wmb(); + +} + +/** + * vxge_hw_fifo_free_txdl_count_get - returns the number of txdls available in + * the fifo + * @fifoh: Handle to the fifo object used for non offload send + */ +u32 vxge_hw_fifo_free_txdl_count_get(struct __vxge_hw_fifo *fifoh) +{ + return vxge_hw_channel_dtr_count(&fifoh->channel); +} + +/** + * vxge_hw_fifo_txdl_reserve - Reserve fifo descriptor. + * @fifoh: Handle to the fifo object used for non offload send + * @txdlh: Reserved descriptor. On success HW fills this "out" parameter + * with a valid handle. + * @txdl_priv: Buffer to return the pointer to per txdl space + * + * Reserve a single TxDL (that is, fifo descriptor) + * for the subsequent filling-in by driver) + * and posting on the corresponding channel (@channelh) + * via vxge_hw_fifo_txdl_post(). + * + * Note: it is the responsibility of driver to reserve multiple descriptors + * for lengthy (e.g., LSO) transmit operation. A single fifo descriptor + * carries up to configured number (fifo.max_frags) of contiguous buffers. + * + * Returns: VXGE_HW_OK - success; + * VXGE_HW_INF_OUT_OF_DESCRIPTORS - Currently no descriptors available + * + */ +enum vxge_hw_status vxge_hw_fifo_txdl_reserve( + struct __vxge_hw_fifo *fifo, + void **txdlh, void **txdl_priv) +{ + struct __vxge_hw_channel *channel; + enum vxge_hw_status status; + int i; + + channel = &fifo->channel; + + status = vxge_hw_channel_dtr_alloc(channel, txdlh); + + if (status == VXGE_HW_OK) { + struct vxge_hw_fifo_txd *txdp = + (struct vxge_hw_fifo_txd *)*txdlh; + struct __vxge_hw_fifo_txdl_priv *priv; + + priv = __vxge_hw_fifo_txdl_priv(fifo, txdp); + + /* reset the TxDL's private */ + priv->align_dma_offset = 0; + priv->align_vaddr_start = priv->align_vaddr; + priv->align_used_frags = 0; + priv->frags = 0; + priv->alloc_frags = fifo->config->max_frags; + priv->next_txdl_priv = NULL; + + *txdl_priv = (void *)(size_t)txdp->host_control; + + for (i = 0; i < fifo->config->max_frags; i++) { + txdp = ((struct vxge_hw_fifo_txd *)*txdlh) + i; + txdp->control_0 = txdp->control_1 = 0; + } + } + + return status; +} + +/** + * vxge_hw_fifo_txdl_buffer_set - Set transmit buffer pointer in the + * descriptor. + * @fifo: Handle to the fifo object used for non offload send + * @txdlh: Descriptor handle. + * @frag_idx: Index of the data buffer in the caller's scatter-gather list + * (of buffers). + * @dma_pointer: DMA address of the data buffer referenced by @frag_idx. + * @size: Size of the data buffer (in bytes). + * + * This API is part of the preparation of the transmit descriptor for posting + * (via vxge_hw_fifo_txdl_post()). The related "preparation" APIs include + * vxge_hw_fifo_txdl_mss_set() and vxge_hw_fifo_txdl_cksum_set_bits(). + * All three APIs fill in the fields of the fifo descriptor, + * in accordance with the Titan specification. + * + */ +void vxge_hw_fifo_txdl_buffer_set(struct __vxge_hw_fifo *fifo, + void *txdlh, u32 frag_idx, + dma_addr_t dma_pointer, u32 size) +{ + struct __vxge_hw_fifo_txdl_priv *txdl_priv; + struct vxge_hw_fifo_txd *txdp, *txdp_last; + struct __vxge_hw_channel *channel; + + channel = &fifo->channel; + + txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdlh); + txdp = (struct vxge_hw_fifo_txd *)txdlh + txdl_priv->frags; + + if (frag_idx != 0) + txdp->control_0 = txdp->control_1 = 0; + else { + txdp->control_0 |= VXGE_HW_FIFO_TXD_GATHER_CODE( + VXGE_HW_FIFO_TXD_GATHER_CODE_FIRST); + txdp->control_1 |= fifo->interrupt_type; + txdp->control_1 |= VXGE_HW_FIFO_TXD_INT_NUMBER( + fifo->tx_intr_num); + if (txdl_priv->frags) { + txdp_last = (struct vxge_hw_fifo_txd *)txdlh + + (txdl_priv->frags - 1); + txdp_last->control_0 |= VXGE_HW_FIFO_TXD_GATHER_CODE( + VXGE_HW_FIFO_TXD_GATHER_CODE_LAST); + } + } + + vxge_assert(frag_idx < txdl_priv->alloc_frags); + + txdp->buffer_pointer = (u64)dma_pointer; + txdp->control_0 |= VXGE_HW_FIFO_TXD_BUFFER_SIZE(size); + fifo->stats->total_buffers++; + txdl_priv->frags++; +} + +/** + * vxge_hw_fifo_txdl_post - Post descriptor on the fifo channel. + * @fifo: Handle to the fifo object used for non offload send + * @txdlh: Descriptor obtained via vxge_hw_fifo_txdl_reserve() + * @frags: Number of contiguous buffers that are part of a single + * transmit operation. + * + * Post descriptor on the 'fifo' type channel for transmission. + * Prior to posting the descriptor should be filled in accordance with + * Host/Titan interface specification for a given service (LL, etc.). + * + */ +void vxge_hw_fifo_txdl_post(struct __vxge_hw_fifo *fifo, void *txdlh) +{ + struct __vxge_hw_fifo_txdl_priv *txdl_priv; + struct vxge_hw_fifo_txd *txdp_last; + struct vxge_hw_fifo_txd *txdp_first; + struct __vxge_hw_channel *channel; + + channel = &fifo->channel; + + txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, txdlh); + txdp_first = (struct vxge_hw_fifo_txd *)txdlh; + + txdp_last = (struct vxge_hw_fifo_txd *)txdlh + (txdl_priv->frags - 1); + txdp_last->control_0 |= + VXGE_HW_FIFO_TXD_GATHER_CODE(VXGE_HW_FIFO_TXD_GATHER_CODE_LAST); + txdp_first->control_0 |= VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER; + + vxge_hw_channel_dtr_post(&fifo->channel, txdlh); + + __vxge_hw_non_offload_db_post(fifo, + (u64)(size_t)txdl_priv->dma_addr, + txdl_priv->frags - 1, + fifo->no_snoop_bits); + + fifo->stats->total_posts++; + fifo->stats->common_stats.usage_cnt++; + if (fifo->stats->common_stats.usage_max < + fifo->stats->common_stats.usage_cnt) + fifo->stats->common_stats.usage_max = + fifo->stats->common_stats.usage_cnt; +} + +/** + * vxge_hw_fifo_txdl_next_completed - Retrieve next completed descriptor. + * @fifo: Handle to the fifo object used for non offload send + * @txdlh: Descriptor handle. Returned by HW. + * @t_code: Transfer code, as per Titan User Guide, + * Transmit Descriptor Format. + * Returned by HW. + * + * Retrieve the _next_ completed descriptor. + * HW uses channel callback (*vxge_hw_channel_callback_f) to notifiy + * driver of new completed descriptors. After that + * the driver can use vxge_hw_fifo_txdl_next_completed to retrieve the rest + * completions (the very first completion is passed by HW via + * vxge_hw_channel_callback_f). + * + * Implementation-wise, the driver is free to call + * vxge_hw_fifo_txdl_next_completed either immediately from inside the + * channel callback, or in a deferred fashion and separate (from HW) + * context. + * + * Non-zero @t_code means failure to process the descriptor. + * The failure could happen, for instance, when the link is + * down, in which case Titan completes the descriptor because it + * is not able to send the data out. + * + * For details please refer to Titan User Guide. + * + * Returns: VXGE_HW_OK - success. + * VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS - No completed descriptors + * are currently available for processing. + * + */ +enum vxge_hw_status vxge_hw_fifo_txdl_next_completed( + struct __vxge_hw_fifo *fifo, void **txdlh, + enum vxge_hw_fifo_tcode *t_code) +{ + struct __vxge_hw_channel *channel; + struct vxge_hw_fifo_txd *txdp; + enum vxge_hw_status status = VXGE_HW_OK; + + channel = &fifo->channel; + + vxge_hw_channel_dtr_try_complete(channel, txdlh); + + txdp = (struct vxge_hw_fifo_txd *)*txdlh; + if (txdp == NULL) { + status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS; + goto exit; + } + + /* check whether host owns it */ + if (!(txdp->control_0 & VXGE_HW_FIFO_TXD_LIST_OWN_ADAPTER)) { + + vxge_assert(txdp->host_control != 0); + + vxge_hw_channel_dtr_complete(channel); + + *t_code = (u8)VXGE_HW_FIFO_TXD_T_CODE_GET(txdp->control_0); + + if (fifo->stats->common_stats.usage_cnt > 0) + fifo->stats->common_stats.usage_cnt--; + + status = VXGE_HW_OK; + goto exit; + } + + /* no more completions */ + *txdlh = NULL; + status = VXGE_HW_INF_NO_MORE_COMPLETED_DESCRIPTORS; +exit: + return status; +} + +/** + * vxge_hw_fifo_handle_tcode - Handle transfer code. + * @fifo: Handle to the fifo object used for non offload send + * @txdlh: Descriptor handle. + * @t_code: One of the enumerated (and documented in the Titan user guide) + * "transfer codes". + * + * Handle descriptor's transfer code. The latter comes with each completed + * descriptor. + * + * Returns: one of the enum vxge_hw_status{} enumerated types. + * VXGE_HW_OK - for success. + * VXGE_HW_ERR_CRITICAL - when encounters critical error. + */ +enum vxge_hw_status vxge_hw_fifo_handle_tcode(struct __vxge_hw_fifo *fifo, + void *txdlh, + enum vxge_hw_fifo_tcode t_code) +{ + struct __vxge_hw_channel *channel; + + enum vxge_hw_status status = VXGE_HW_OK; + channel = &fifo->channel; + + if (((t_code & 0x7) < 0) || ((t_code & 0x7) > 0x4)) { + status = VXGE_HW_ERR_INVALID_TCODE; + goto exit; + } + + fifo->stats->txd_t_code_err_cnt[t_code]++; +exit: + return status; +} + +/** + * vxge_hw_fifo_txdl_free - Free descriptor. + * @fifo: Handle to the fifo object used for non offload send + * @txdlh: Descriptor handle. + * + * Free the reserved descriptor. This operation is "symmetrical" to + * vxge_hw_fifo_txdl_reserve. The "free-ing" completes the descriptor's + * lifecycle. + * + * After free-ing (see vxge_hw_fifo_txdl_free()) the descriptor again can + * be: + * + * - reserved (vxge_hw_fifo_txdl_reserve); + * + * - posted (vxge_hw_fifo_txdl_post); + * + * - completed (vxge_hw_fifo_txdl_next_completed); + * + * - and recycled again (vxge_hw_fifo_txdl_free). + * + * For alternative state transitions and more details please refer to + * the design doc. + * + */ +void vxge_hw_fifo_txdl_free(struct __vxge_hw_fifo *fifo, void *txdlh) +{ + struct __vxge_hw_fifo_txdl_priv *txdl_priv; + u32 max_frags; + struct __vxge_hw_channel *channel; + + channel = &fifo->channel; + + txdl_priv = __vxge_hw_fifo_txdl_priv(fifo, + (struct vxge_hw_fifo_txd *)txdlh); + + max_frags = fifo->config->max_frags; + + vxge_hw_channel_dtr_free(channel, txdlh); +} + +/** + * vxge_hw_vpath_mac_addr_add - Add the mac address entry for this vpath + * to MAC address table. + * @vp: Vpath handle. + * @macaddr: MAC address to be added for this vpath into the list + * @macaddr_mask: MAC address mask for macaddr + * @duplicate_mode: Duplicate MAC address add mode. Please see + * enum vxge_hw_vpath_mac_addr_add_mode{} + * + * Adds the given mac address and mac address mask into the list for this + * vpath. + * see also: vxge_hw_vpath_mac_addr_delete, vxge_hw_vpath_mac_addr_get and + * vxge_hw_vpath_mac_addr_get_next + * + */ +enum vxge_hw_status +vxge_hw_vpath_mac_addr_add( + struct __vxge_hw_vpath_handle *vp, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN], + enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode) +{ + u32 i; + u64 data1 = 0ULL; + u64 data2 = 0ULL; + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + for (i = 0; i < ETH_ALEN; i++) { + data1 <<= 8; + data1 |= (u8)macaddr[i]; + + data2 <<= 8; + data2 |= (u8)macaddr_mask[i]; + } + + switch (duplicate_mode) { + case VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE: + i = 0; + break; + case VXGE_HW_VPATH_MAC_ADDR_DISCARD_DUPLICATE: + i = 1; + break; + case VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE: + i = 2; + break; + default: + i = 0; + break; + } + + status = __vxge_hw_vpath_rts_table_set(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA, + 0, + VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(data1), + VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(data2)| + VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MODE(i)); +exit: + return status; +} + +/** + * vxge_hw_vpath_mac_addr_get - Get the first mac address entry for this vpath + * from MAC address table. + * @vp: Vpath handle. + * @macaddr: First MAC address entry for this vpath in the list + * @macaddr_mask: MAC address mask for macaddr + * + * Returns the first mac address and mac address mask in the list for this + * vpath. + * see also: vxge_hw_vpath_mac_addr_get_next + * + */ +enum vxge_hw_status +vxge_hw_vpath_mac_addr_get( + struct __vxge_hw_vpath_handle *vp, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN]) +{ + u32 i; + u64 data1 = 0ULL; + u64 data2 = 0ULL; + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + status = __vxge_hw_vpath_rts_table_get(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA, + 0, &data1, &data2); + + if (status != VXGE_HW_OK) + goto exit; + + data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1); + + data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(data2); + + for (i = ETH_ALEN; i > 0; i--) { + macaddr[i-1] = (u8)(data1 & 0xFF); + data1 >>= 8; + + macaddr_mask[i-1] = (u8)(data2 & 0xFF); + data2 >>= 8; + } +exit: + return status; +} + +/** + * vxge_hw_vpath_mac_addr_get_next - Get the next mac address entry for this + * vpath + * from MAC address table. + * @vp: Vpath handle. + * @macaddr: Next MAC address entry for this vpath in the list + * @macaddr_mask: MAC address mask for macaddr + * + * Returns the next mac address and mac address mask in the list for this + * vpath. + * see also: vxge_hw_vpath_mac_addr_get + * + */ +enum vxge_hw_status +vxge_hw_vpath_mac_addr_get_next( + struct __vxge_hw_vpath_handle *vp, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN]) +{ + u32 i; + u64 data1 = 0ULL; + u64 data2 = 0ULL; + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + status = __vxge_hw_vpath_rts_table_get(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA, + 0, &data1, &data2); + + if (status != VXGE_HW_OK) + goto exit; + + data1 = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_DA_MAC_ADDR(data1); + + data2 = VXGE_HW_RTS_ACCESS_STEER_DATA1_GET_DA_MAC_ADDR_MASK(data2); + + for (i = ETH_ALEN; i > 0; i--) { + macaddr[i-1] = (u8)(data1 & 0xFF); + data1 >>= 8; + + macaddr_mask[i-1] = (u8)(data2 & 0xFF); + data2 >>= 8; + } + +exit: + return status; +} + +/** + * vxge_hw_vpath_mac_addr_delete - Delete the mac address entry for this vpath + * to MAC address table. + * @vp: Vpath handle. + * @macaddr: MAC address to be added for this vpath into the list + * @macaddr_mask: MAC address mask for macaddr + * + * Delete the given mac address and mac address mask into the list for this + * vpath. + * see also: vxge_hw_vpath_mac_addr_add, vxge_hw_vpath_mac_addr_get and + * vxge_hw_vpath_mac_addr_get_next + * + */ +enum vxge_hw_status +vxge_hw_vpath_mac_addr_delete( + struct __vxge_hw_vpath_handle *vp, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN]) +{ + u32 i; + u64 data1 = 0ULL; + u64 data2 = 0ULL; + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + for (i = 0; i < ETH_ALEN; i++) { + data1 <<= 8; + data1 |= (u8)macaddr[i]; + + data2 <<= 8; + data2 |= (u8)macaddr_mask[i]; + } + + status = __vxge_hw_vpath_rts_table_set(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_DA, + 0, + VXGE_HW_RTS_ACCESS_STEER_DATA0_DA_MAC_ADDR(data1), + VXGE_HW_RTS_ACCESS_STEER_DATA1_DA_MAC_ADDR_MASK(data2)); +exit: + return status; +} + +/** + * vxge_hw_vpath_vid_add - Add the vlan id entry for this vpath + * to vlan id table. + * @vp: Vpath handle. + * @vid: vlan id to be added for this vpath into the list + * + * Adds the given vlan id into the list for this vpath. + * see also: vxge_hw_vpath_vid_delete, vxge_hw_vpath_vid_get and + * vxge_hw_vpath_vid_get_next + * + */ +enum vxge_hw_status +vxge_hw_vpath_vid_add(struct __vxge_hw_vpath_handle *vp, u64 vid) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + status = __vxge_hw_vpath_rts_table_set(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_ADD_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID, + 0, VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(vid), 0); +exit: + return status; +} + +/** + * vxge_hw_vpath_vid_get - Get the first vid entry for this vpath + * from vlan id table. + * @vp: Vpath handle. + * @vid: Buffer to return vlan id + * + * Returns the first vlan id in the list for this vpath. + * see also: vxge_hw_vpath_vid_get_next + * + */ +enum vxge_hw_status +vxge_hw_vpath_vid_get(struct __vxge_hw_vpath_handle *vp, u64 *vid) +{ + u64 data; + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + status = __vxge_hw_vpath_rts_table_get(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_FIRST_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID, + 0, vid, &data); + + *vid = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(*vid); +exit: + return status; +} + +/** + * vxge_hw_vpath_vid_get_next - Get the next vid entry for this vpath + * from vlan id table. + * @vp: Vpath handle. + * @vid: Buffer to return vlan id + * + * Returns the next vlan id in the list for this vpath. + * see also: vxge_hw_vpath_vid_get + * + */ +enum vxge_hw_status +vxge_hw_vpath_vid_get_next(struct __vxge_hw_vpath_handle *vp, u64 *vid) +{ + u64 data; + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + status = __vxge_hw_vpath_rts_table_get(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_LIST_NEXT_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID, + 0, vid, &data); + + *vid = VXGE_HW_RTS_ACCESS_STEER_DATA0_GET_VLAN_ID(*vid); +exit: + return status; +} + +/** + * vxge_hw_vpath_vid_delete - Delete the vlan id entry for this vpath + * to vlan id table. + * @vp: Vpath handle. + * @vid: vlan id to be added for this vpath into the list + * + * Adds the given vlan id into the list for this vpath. + * see also: vxge_hw_vpath_vid_add, vxge_hw_vpath_vid_get and + * vxge_hw_vpath_vid_get_next + * + */ +enum vxge_hw_status +vxge_hw_vpath_vid_delete(struct __vxge_hw_vpath_handle *vp, u64 vid) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + status = __vxge_hw_vpath_rts_table_set(vp, + VXGE_HW_RTS_ACCESS_STEER_CTRL_ACTION_DELETE_ENTRY, + VXGE_HW_RTS_ACCESS_STEER_CTRL_DATA_STRUCT_SEL_VID, + 0, VXGE_HW_RTS_ACCESS_STEER_DATA0_VLAN_ID(vid), 0); +exit: + return status; +} + +/** + * vxge_hw_vpath_promisc_enable - Enable promiscuous mode. + * @vp: Vpath handle. + * + * Enable promiscuous mode of Titan-e operation. + * + * See also: vxge_hw_vpath_promisc_disable(). + */ +enum vxge_hw_status vxge_hw_vpath_promisc_enable( + struct __vxge_hw_vpath_handle *vp) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status = VXGE_HW_OK; + + if ((vp == NULL) || (vp->vpath->ringh == NULL)) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + + /* Enable promiscous mode for function 0 only */ + if (!(vpath->hldev->access_rights & + VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) + return VXGE_HW_OK; + + val64 = readq(&vpath->vp_reg->rxmac_vcfg0); + + if (!(val64 & VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN)) { + + val64 |= VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN | + VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN | + VXGE_HW_RXMAC_VCFG0_BCAST_EN | + VXGE_HW_RXMAC_VCFG0_ALL_VID_EN; + + writeq(val64, &vpath->vp_reg->rxmac_vcfg0); + } +exit: + return status; +} + +/** + * vxge_hw_vpath_promisc_disable - Disable promiscuous mode. + * @vp: Vpath handle. + * + * Disable promiscuous mode of Titan-e operation. + * + * See also: vxge_hw_vpath_promisc_enable(). + */ +enum vxge_hw_status vxge_hw_vpath_promisc_disable( + struct __vxge_hw_vpath_handle *vp) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status = VXGE_HW_OK; + + if ((vp == NULL) || (vp->vpath->ringh == NULL)) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + + val64 = readq(&vpath->vp_reg->rxmac_vcfg0); + + if (val64 & VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN) { + + val64 &= ~(VXGE_HW_RXMAC_VCFG0_UCAST_ALL_ADDR_EN | + VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN | + VXGE_HW_RXMAC_VCFG0_ALL_VID_EN); + + writeq(val64, &vpath->vp_reg->rxmac_vcfg0); + } +exit: + return status; +} + +/* + * vxge_hw_vpath_bcast_enable - Enable broadcast + * @vp: Vpath handle. + * + * Enable receiving broadcasts. + */ +enum vxge_hw_status vxge_hw_vpath_bcast_enable( + struct __vxge_hw_vpath_handle *vp) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status = VXGE_HW_OK; + + if ((vp == NULL) || (vp->vpath->ringh == NULL)) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + + val64 = readq(&vpath->vp_reg->rxmac_vcfg0); + + if (!(val64 & VXGE_HW_RXMAC_VCFG0_BCAST_EN)) { + val64 |= VXGE_HW_RXMAC_VCFG0_BCAST_EN; + writeq(val64, &vpath->vp_reg->rxmac_vcfg0); + } +exit: + return status; +} + +/** + * vxge_hw_vpath_mcast_enable - Enable multicast addresses. + * @vp: Vpath handle. + * + * Enable Titan-e multicast addresses. + * Returns: VXGE_HW_OK on success. + * + */ +enum vxge_hw_status vxge_hw_vpath_mcast_enable( + struct __vxge_hw_vpath_handle *vp) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status = VXGE_HW_OK; + + if ((vp == NULL) || (vp->vpath->ringh == NULL)) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + + val64 = readq(&vpath->vp_reg->rxmac_vcfg0); + + if (!(val64 & VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN)) { + val64 |= VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN; + writeq(val64, &vpath->vp_reg->rxmac_vcfg0); + } +exit: + return status; +} + +/** + * vxge_hw_vpath_mcast_disable - Disable multicast addresses. + * @vp: Vpath handle. + * + * Disable Titan-e multicast addresses. + * Returns: VXGE_HW_OK - success. + * VXGE_HW_ERR_INVALID_HANDLE - Invalid handle + * + */ +enum vxge_hw_status +vxge_hw_vpath_mcast_disable(struct __vxge_hw_vpath_handle *vp) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath; + enum vxge_hw_status status = VXGE_HW_OK; + + if ((vp == NULL) || (vp->vpath->ringh == NULL)) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + vpath = vp->vpath; + + val64 = readq(&vpath->vp_reg->rxmac_vcfg0); + + if (val64 & VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN) { + val64 &= ~VXGE_HW_RXMAC_VCFG0_MCAST_ALL_ADDR_EN; + writeq(val64, &vpath->vp_reg->rxmac_vcfg0); + } +exit: + return status; +} + +/* + * __vxge_hw_vpath_alarm_process - Process Alarms. + * @vpath: Virtual Path. + * @skip_alarms: Do not clear the alarms + * + * Process vpath alarms. + * + */ +enum vxge_hw_status __vxge_hw_vpath_alarm_process( + struct __vxge_hw_virtualpath *vpath, + u32 skip_alarms) +{ + u64 val64; + u64 alarm_status; + u64 pic_status; + struct __vxge_hw_device *hldev = NULL; + enum vxge_hw_event alarm_event = VXGE_HW_EVENT_UNKNOWN; + u64 mask64; + struct vxge_hw_vpath_stats_sw_info *sw_stats; + struct vxge_hw_vpath_reg __iomem *vp_reg; + + if (vpath == NULL) { + alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN, + alarm_event); + goto out; + } + + hldev = vpath->hldev; + vp_reg = vpath->vp_reg; + alarm_status = readq(&vp_reg->vpath_general_int_status); + + if (alarm_status == VXGE_HW_ALL_FOXES) { + alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_SLOT_FREEZE, + alarm_event); + goto out; + } + + sw_stats = vpath->sw_stats; + + if (alarm_status & ~( + VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT | + VXGE_HW_VPATH_GENERAL_INT_STATUS_PCI_INT | + VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT | + VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT)) { + sw_stats->error_stats.unknown_alarms++; + + alarm_event = VXGE_HW_SET_LEVEL(VXGE_HW_EVENT_UNKNOWN, + alarm_event); + goto out; + } + + if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_XMAC_INT) { + + val64 = readq(&vp_reg->xgmac_vp_int_status); + + if (val64 & + VXGE_HW_XGMAC_VP_INT_STATUS_ASIC_NTWK_VP_ERR_ASIC_NTWK_VP_INT) { + + val64 = readq(&vp_reg->asic_ntwk_vp_err_reg); + + if (((val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT) && + (!(val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK))) || + ((val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR) + && (!(val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR) + ))) { + sw_stats->error_stats.network_sustained_fault++; + + writeq( + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT, + &vp_reg->asic_ntwk_vp_err_mask); + + __vxge_hw_device_handle_link_down_ind(hldev); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_LINK_DOWN, alarm_event); + } + + if (((val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK) && + (!(val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT))) || + ((val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR) + && (!(val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR) + ))) { + + sw_stats->error_stats.network_sustained_ok++; + + writeq( + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK, + &vp_reg->asic_ntwk_vp_err_mask); + + __vxge_hw_device_handle_link_up_ind(hldev); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_LINK_UP, alarm_event); + } + + writeq(VXGE_HW_INTR_MASK_ALL, + &vp_reg->asic_ntwk_vp_err_reg); + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_ALARM_CLEARED, alarm_event); + + if (skip_alarms) + return VXGE_HW_OK; + } + } + + if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_PIC_INT) { + + pic_status = readq(&vp_reg->vpath_ppif_int_status); + + if (pic_status & + VXGE_HW_VPATH_PPIF_INT_STATUS_GENERAL_ERRORS_GENERAL_INT) { + + val64 = readq(&vp_reg->general_errors_reg); + mask64 = readq(&vp_reg->general_errors_mask); + + if ((val64 & + VXGE_HW_GENERAL_ERRORS_REG_INI_SERR_DET) & + ~mask64) { + sw_stats->error_stats.ini_serr_det++; + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_SERR, alarm_event); + } + + if ((val64 & + VXGE_HW_GENERAL_ERRORS_REG_DBLGEN_FIFO0_OVRFLOW) & + ~mask64) { + sw_stats->error_stats.dblgen_fifo0_overflow++; + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_FIFO_ERR, alarm_event); + } + + if ((val64 & + VXGE_HW_GENERAL_ERRORS_REG_STATSB_PIF_CHAIN_ERR) & + ~mask64) + sw_stats->error_stats.statsb_pif_chain_error++; + + if ((val64 & + VXGE_HW_GENERAL_ERRORS_REG_STATSB_DROP_TIMEOUT_REQ) & + ~mask64) + sw_stats->error_stats.statsb_drop_timeout++; + + if ((val64 & + VXGE_HW_GENERAL_ERRORS_REG_TGT_ILLEGAL_ACCESS) & + ~mask64) + sw_stats->error_stats.target_illegal_access++; + + if (!skip_alarms) { + writeq(VXGE_HW_INTR_MASK_ALL, + &vp_reg->general_errors_reg); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event); + } + } + + if (pic_status & + VXGE_HW_VPATH_PPIF_INT_STATUS_KDFCCTL_ERRORS_KDFCCTL_INT) { + + val64 = readq(&vp_reg->kdfcctl_errors_reg); + mask64 = readq(&vp_reg->kdfcctl_errors_mask); + + if ((val64 & + VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_OVRWR) & + ~mask64) { + sw_stats->error_stats.kdfcctl_fifo0_overwrite++; + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_FIFO_ERR, + alarm_event); + } + + if ((val64 & + VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_POISON) & + ~mask64) { + sw_stats->error_stats.kdfcctl_fifo0_poison++; + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_FIFO_ERR, + alarm_event); + } + + if ((val64 & + VXGE_HW_KDFCCTL_ERRORS_REG_KDFCCTL_FIFO0_DMA_ERR) & + ~mask64) { + sw_stats->error_stats.kdfcctl_fifo0_dma_error++; + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_FIFO_ERR, + alarm_event); + } + + if (!skip_alarms) { + writeq(VXGE_HW_INTR_MASK_ALL, + &vp_reg->kdfcctl_errors_reg); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event); + } + } + + } + + if (alarm_status & VXGE_HW_VPATH_GENERAL_INT_STATUS_WRDMA_INT) { + + val64 = readq(&vp_reg->wrdma_alarm_status); + + if (val64 & VXGE_HW_WRDMA_ALARM_STATUS_PRC_ALARM_PRC_INT) { + + val64 = readq(&vp_reg->prc_alarm_reg); + mask64 = readq(&vp_reg->prc_alarm_mask); + + if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RING_BUMP)& + ~mask64) + sw_stats->error_stats.prc_ring_bumps++; + + if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ERR) & + ~mask64) { + sw_stats->error_stats.prc_rxdcm_sc_err++; + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_VPATH_ERR, + alarm_event); + } + + if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_RXDCM_SC_ABORT) + & ~mask64) { + sw_stats->error_stats.prc_rxdcm_sc_abort++; + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_VPATH_ERR, + alarm_event); + } + + if ((val64 & VXGE_HW_PRC_ALARM_REG_PRC_QUANTA_SIZE_ERR) + & ~mask64) { + sw_stats->error_stats.prc_quanta_size_err++; + + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_VPATH_ERR, + alarm_event); + } + + if (!skip_alarms) { + writeq(VXGE_HW_INTR_MASK_ALL, + &vp_reg->prc_alarm_reg); + alarm_event = VXGE_HW_SET_LEVEL( + VXGE_HW_EVENT_ALARM_CLEARED, + alarm_event); + } + } + } +out: + hldev->stats.sw_dev_err_stats.vpath_alarms++; + + if ((alarm_event == VXGE_HW_EVENT_ALARM_CLEARED) || + (alarm_event == VXGE_HW_EVENT_UNKNOWN)) + return VXGE_HW_OK; + + __vxge_hw_device_handle_error(hldev, vpath->vp_id, alarm_event); + + if (alarm_event == VXGE_HW_EVENT_SERR) + return VXGE_HW_ERR_CRITICAL; + + return (alarm_event == VXGE_HW_EVENT_SLOT_FREEZE) ? + VXGE_HW_ERR_SLOT_FREEZE : + (alarm_event == VXGE_HW_EVENT_FIFO_ERR) ? VXGE_HW_ERR_FIFO : + VXGE_HW_ERR_VPATH; +} + +/* + * vxge_hw_vpath_alarm_process - Process Alarms. + * @vpath: Virtual Path. + * @skip_alarms: Do not clear the alarms + * + * Process vpath alarms. + * + */ +enum vxge_hw_status vxge_hw_vpath_alarm_process( + struct __vxge_hw_vpath_handle *vp, + u32 skip_alarms) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + if (vp == NULL) { + status = VXGE_HW_ERR_INVALID_HANDLE; + goto exit; + } + + status = __vxge_hw_vpath_alarm_process(vp->vpath, skip_alarms); +exit: + return status; +} + +/** + * vxge_hw_vpath_msix_set - Associate MSIX vectors with TIM interrupts and + * alrms + * @vp: Virtual Path handle. + * @tim_msix_id: MSIX vectors associated with VXGE_HW_MAX_INTR_PER_VP number of + * interrupts(Can be repeated). If fifo or ring are not enabled + * the MSIX vector for that should be set to 0 + * @alarm_msix_id: MSIX vector for alarm. + * + * This API will associate a given MSIX vector numbers with the four TIM + * interrupts and alarm interrupt. + */ +enum vxge_hw_status +vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vp, int *tim_msix_id, + int alarm_msix_id) +{ + u64 val64; + struct __vxge_hw_virtualpath *vpath = vp->vpath; + struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg; + u32 first_vp_id = vpath->hldev->first_vp_id; + + val64 = VXGE_HW_INTERRUPT_CFG0_GROUP0_MSIX_FOR_TXTI( + (first_vp_id * 4) + tim_msix_id[0]) | + VXGE_HW_INTERRUPT_CFG0_GROUP1_MSIX_FOR_TXTI( + (first_vp_id * 4) + tim_msix_id[1]) | + VXGE_HW_INTERRUPT_CFG0_GROUP2_MSIX_FOR_TXTI( + (first_vp_id * 4) + tim_msix_id[2]); + + val64 |= VXGE_HW_INTERRUPT_CFG0_GROUP3_MSIX_FOR_TXTI( + (first_vp_id * 4) + tim_msix_id[3]); + + writeq(val64, &vp_reg->interrupt_cfg0); + + writeq(VXGE_HW_INTERRUPT_CFG2_ALARM_MAP_TO_MSG( + (first_vp_id * 4) + alarm_msix_id), + &vp_reg->interrupt_cfg2); + + if (vpath->hldev->config.intr_mode == + VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) { + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn( + VXGE_HW_ONE_SHOT_VECT1_EN_ONE_SHOT_VECT1_EN, + 0, 32), &vp_reg->one_shot_vect1_en); + } + + if (vpath->hldev->config.intr_mode == + VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) { + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn( + VXGE_HW_ONE_SHOT_VECT2_EN_ONE_SHOT_VECT2_EN, + 0, 32), &vp_reg->one_shot_vect2_en); + + __vxge_hw_pio_mem_write32_upper((u32)vxge_bVALn( + VXGE_HW_ONE_SHOT_VECT3_EN_ONE_SHOT_VECT3_EN, + 0, 32), &vp_reg->one_shot_vect3_en); + } + + return VXGE_HW_OK; +} + +/** + * vxge_hw_vpath_msix_mask - Mask MSIX Vector. + * @vp: Virtual Path handle. + * @msix_id: MSIX ID + * + * The function masks the msix interrupt for the given msix_id + * + * Returns: 0, + * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range + * status. + * See also: + */ +void +vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vp, int msix_id) +{ + struct __vxge_hw_device *hldev = vp->vpath->hldev; + __vxge_hw_pio_mem_write32_upper( + (u32) vxge_bVALn(vxge_mBIT(hldev->first_vp_id + + (msix_id / 4)), 0, 32), + &hldev->common_reg->set_msix_mask_vect[msix_id % 4]); + + return; +} + +/** + * vxge_hw_vpath_msix_clear - Clear MSIX Vector. + * @vp: Virtual Path handle. + * @msix_id: MSI ID + * + * The function clears the msix interrupt for the given msix_id + * + * Returns: 0, + * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range + * status. + * See also: + */ +void +vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vp, int msix_id) +{ + struct __vxge_hw_device *hldev = vp->vpath->hldev; + if (hldev->config.intr_mode == + VXGE_HW_INTR_MODE_MSIX_ONE_SHOT) { + __vxge_hw_pio_mem_write32_upper( + (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id + + (msix_id/4)), 0, 32), + &hldev->common_reg-> + clr_msix_one_shot_vec[msix_id%4]); + } else { + __vxge_hw_pio_mem_write32_upper( + (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id + + (msix_id/4)), 0, 32), + &hldev->common_reg-> + clear_msix_mask_vect[msix_id%4]); + } + + return; +} + +/** + * vxge_hw_vpath_msix_unmask - Unmask the MSIX Vector. + * @vp: Virtual Path handle. + * @msix_id: MSI ID + * + * The function unmasks the msix interrupt for the given msix_id + * + * Returns: 0, + * Otherwise, VXGE_HW_ERR_WRONG_IRQ if the msix index is out of range + * status. + * See also: + */ +void +vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vp, int msix_id) +{ + struct __vxge_hw_device *hldev = vp->vpath->hldev; + __vxge_hw_pio_mem_write32_upper( + (u32)vxge_bVALn(vxge_mBIT(hldev->first_vp_id + + (msix_id/4)), 0, 32), + &hldev->common_reg->clear_msix_mask_vect[msix_id%4]); + + return; +} + +/** + * vxge_hw_vpath_msix_mask_all - Mask all MSIX vectors for the vpath. + * @vp: Virtual Path handle. + * + * The function masks all msix interrupt for the given vpath + * + */ +void +vxge_hw_vpath_msix_mask_all(struct __vxge_hw_vpath_handle *vp) +{ + + __vxge_hw_pio_mem_write32_upper( + (u32)vxge_bVALn(vxge_mBIT(vp->vpath->vp_id), 0, 32), + &vp->vpath->hldev->common_reg->set_msix_mask_all_vect); + + return; +} + +/** + * vxge_hw_vpath_inta_mask_tx_rx - Mask Tx and Rx interrupts. + * @vp: Virtual Path handle. + * + * Mask Tx and Rx vpath interrupts. + * + * See also: vxge_hw_vpath_inta_mask_tx_rx() + */ +void vxge_hw_vpath_inta_mask_tx_rx(struct __vxge_hw_vpath_handle *vp) +{ + u64 tim_int_mask0[4] = {[0 ...3] = 0}; + u32 tim_int_mask1[4] = {[0 ...3] = 0}; + u64 val64; + struct __vxge_hw_device *hldev = vp->vpath->hldev; + + VXGE_HW_DEVICE_TIM_INT_MASK_SET(tim_int_mask0, + tim_int_mask1, vp->vpath->vp_id); + + val64 = readq(&hldev->common_reg->tim_int_mask0); + + if ((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) || + (tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) { + writeq((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] | + tim_int_mask0[VXGE_HW_VPATH_INTR_RX] | val64), + &hldev->common_reg->tim_int_mask0); + } + + val64 = readl(&hldev->common_reg->tim_int_mask1); + + if ((tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) || + (tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) { + __vxge_hw_pio_mem_write32_upper( + (tim_int_mask1[VXGE_HW_VPATH_INTR_TX] | + tim_int_mask1[VXGE_HW_VPATH_INTR_RX] | val64), + &hldev->common_reg->tim_int_mask1); + } + + return; +} + +/** + * vxge_hw_vpath_inta_unmask_tx_rx - Unmask Tx and Rx interrupts. + * @vp: Virtual Path handle. + * + * Unmask Tx and Rx vpath interrupts. + * + * See also: vxge_hw_vpath_inta_mask_tx_rx() + */ +void vxge_hw_vpath_inta_unmask_tx_rx(struct __vxge_hw_vpath_handle *vp) +{ + u64 tim_int_mask0[4] = {[0 ...3] = 0}; + u32 tim_int_mask1[4] = {[0 ...3] = 0}; + u64 val64; + struct __vxge_hw_device *hldev = vp->vpath->hldev; + + VXGE_HW_DEVICE_TIM_INT_MASK_SET(tim_int_mask0, + tim_int_mask1, vp->vpath->vp_id); + + val64 = readq(&hldev->common_reg->tim_int_mask0); + + if ((tim_int_mask0[VXGE_HW_VPATH_INTR_TX] != 0) || + (tim_int_mask0[VXGE_HW_VPATH_INTR_RX] != 0)) { + writeq((~(tim_int_mask0[VXGE_HW_VPATH_INTR_TX] | + tim_int_mask0[VXGE_HW_VPATH_INTR_RX])) & val64, + &hldev->common_reg->tim_int_mask0); + } + + if ((tim_int_mask1[VXGE_HW_VPATH_INTR_TX] != 0) || + (tim_int_mask1[VXGE_HW_VPATH_INTR_RX] != 0)) { + __vxge_hw_pio_mem_write32_upper( + (~(tim_int_mask1[VXGE_HW_VPATH_INTR_TX] | + tim_int_mask1[VXGE_HW_VPATH_INTR_RX])) & val64, + &hldev->common_reg->tim_int_mask1); + } + + return; +} + +/** + * vxge_hw_vpath_poll_rx - Poll Rx Virtual Path for completed + * descriptors and process the same. + * @ring: Handle to the ring object used for receive + * + * The function polls the Rx for the completed descriptors and calls + * the driver via supplied completion callback. + * + * Returns: VXGE_HW_OK, if the polling is completed successful. + * VXGE_HW_COMPLETIONS_REMAIN: There are still more completed + * descriptors available which are yet to be processed. + * + * See also: vxge_hw_vpath_poll_rx() + */ +enum vxge_hw_status vxge_hw_vpath_poll_rx(struct __vxge_hw_ring *ring) +{ + u8 t_code; + enum vxge_hw_status status = VXGE_HW_OK; + void *first_rxdh; + u64 val64 = 0; + int new_count = 0; + + ring->cmpl_cnt = 0; + + status = vxge_hw_ring_rxd_next_completed(ring, &first_rxdh, &t_code); + if (status == VXGE_HW_OK) + ring->callback(ring, first_rxdh, + t_code, ring->channel.userdata); + + if (ring->cmpl_cnt != 0) { + ring->doorbell_cnt += ring->cmpl_cnt; + if (ring->doorbell_cnt >= ring->rxds_limit) { + /* + * Each RxD is of 4 qwords, update the number of + * qwords replenished + */ + new_count = (ring->doorbell_cnt * 4); + + /* For each block add 4 more qwords */ + ring->total_db_cnt += ring->doorbell_cnt; + if (ring->total_db_cnt >= ring->rxds_per_block) { + new_count += 4; + /* Reset total count */ + ring->total_db_cnt %= ring->rxds_per_block; + } + writeq(VXGE_HW_PRC_RXD_DOORBELL_NEW_QW_CNT(new_count), + &ring->vp_reg->prc_rxd_doorbell); + val64 = + readl(&ring->common_reg->titan_general_int_status); + ring->doorbell_cnt = 0; + } + } + + return status; +} + +/** + * vxge_hw_vpath_poll_tx - Poll Tx for completed descriptors and process + * the same. + * @fifo: Handle to the fifo object used for non offload send + * + * The function polls the Tx for the completed descriptors and calls + * the driver via supplied completion callback. + * + * Returns: VXGE_HW_OK, if the polling is completed successful. + * VXGE_HW_COMPLETIONS_REMAIN: There are still more completed + * descriptors available which are yet to be processed. + * + * See also: vxge_hw_vpath_poll_tx(). + */ +enum vxge_hw_status vxge_hw_vpath_poll_tx(struct __vxge_hw_fifo *fifo, + void **skb_ptr) +{ + enum vxge_hw_fifo_tcode t_code; + void *first_txdlh; + enum vxge_hw_status status = VXGE_HW_OK; + struct __vxge_hw_channel *channel; + + channel = &fifo->channel; + + status = vxge_hw_fifo_txdl_next_completed(fifo, + &first_txdlh, &t_code); + if (status == VXGE_HW_OK) + if (fifo->callback(fifo, first_txdlh, + t_code, channel->userdata, skb_ptr) != VXGE_HW_OK) + status = VXGE_HW_COMPLETIONS_REMAIN; + + return status; +} diff --git a/trunk/drivers/net/vxge/vxge-traffic.h b/trunk/drivers/net/vxge/vxge-traffic.h new file mode 100644 index 000000000000..7567a1140d07 --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-traffic.h @@ -0,0 +1,2409 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-traffic.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#ifndef VXGE_TRAFFIC_H +#define VXGE_TRAFFIC_H + +#include "vxge-reg.h" +#include "vxge-version.h" + +#define VXGE_HW_DTR_MAX_T_CODE 16 +#define VXGE_HW_ALL_FOXES 0xFFFFFFFFFFFFFFFFULL +#define VXGE_HW_INTR_MASK_ALL 0xFFFFFFFFFFFFFFFFULL +#define VXGE_HW_MAX_VIRTUAL_PATHS 17 + +#define VXGE_HW_MAC_MAX_MAC_PORT_ID 2 + +#define VXGE_HW_DEFAULT_32 0xffffffff +/* frames sizes */ +#define VXGE_HW_HEADER_802_2_SIZE 3 +#define VXGE_HW_HEADER_SNAP_SIZE 5 +#define VXGE_HW_HEADER_VLAN_SIZE 4 +#define VXGE_HW_MAC_HEADER_MAX_SIZE \ + (ETH_HLEN + \ + VXGE_HW_HEADER_802_2_SIZE + \ + VXGE_HW_HEADER_VLAN_SIZE + \ + VXGE_HW_HEADER_SNAP_SIZE) + +#define VXGE_HW_TCPIP_HEADER_MAX_SIZE (64 + 64) + +/* 32bit alignments */ +#define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN 2 +#define VXGE_HW_HEADER_802_2_SNAP_ALIGN 2 +#define VXGE_HW_HEADER_802_2_ALIGN 3 +#define VXGE_HW_HEADER_SNAP_ALIGN 1 + +#define VXGE_HW_L3_CKSUM_OK 0xFFFF +#define VXGE_HW_L4_CKSUM_OK 0xFFFF + +/* Forward declarations */ +struct __vxge_hw_device; +struct __vxge_hw_vpath_handle; +struct vxge_hw_vp_config; +struct __vxge_hw_virtualpath; +struct __vxge_hw_channel; +struct __vxge_hw_fifo; +struct __vxge_hw_ring; +struct vxge_hw_ring_attr; +struct vxge_hw_mempool; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/*VXGE_HW_STATUS_H*/ + +#define VXGE_HW_EVENT_BASE 0 +#define VXGE_LL_EVENT_BASE 100 + +/** + * enum vxge_hw_event- Enumerates slow-path HW events. + * @VXGE_HW_EVENT_UNKNOWN: Unknown (and invalid) event. + * @VXGE_HW_EVENT_SERR: Serious vpath hardware error event. + * @VXGE_HW_EVENT_ECCERR: vpath ECC error event. + * @VXGE_HW_EVENT_VPATH_ERR: Error local to the respective vpath + * @VXGE_HW_EVENT_FIFO_ERR: FIFO Doorbell fifo error. + * @VXGE_HW_EVENT_SRPCIM_SERR: srpcim hardware error event. + * @VXGE_HW_EVENT_MRPCIM_SERR: mrpcim hardware error event. + * @VXGE_HW_EVENT_MRPCIM_ECCERR: mrpcim ecc error event. + * @VXGE_HW_EVENT_RESET_START: Privileged entity is starting device reset + * @VXGE_HW_EVENT_RESET_COMPLETE: Device reset has been completed + * @VXGE_HW_EVENT_SLOT_FREEZE: Slot-freeze event. Driver tries to distinguish + * slot-freeze from the rest critical events (e.g. ECC) when it is + * impossible to PIO read "through" the bus, i.e. when getting all-foxes. + * + * enum vxge_hw_event enumerates slow-path HW eventis. + * + * See also: struct vxge_hw_uld_cbs{}, vxge_uld_link_up_f{}, + * vxge_uld_link_down_f{}. + */ +enum vxge_hw_event { + VXGE_HW_EVENT_UNKNOWN = 0, + /* HW events */ + VXGE_HW_EVENT_RESET_START = VXGE_HW_EVENT_BASE + 1, + VXGE_HW_EVENT_RESET_COMPLETE = VXGE_HW_EVENT_BASE + 2, + VXGE_HW_EVENT_LINK_DOWN = VXGE_HW_EVENT_BASE + 3, + VXGE_HW_EVENT_LINK_UP = VXGE_HW_EVENT_BASE + 4, + VXGE_HW_EVENT_ALARM_CLEARED = VXGE_HW_EVENT_BASE + 5, + VXGE_HW_EVENT_ECCERR = VXGE_HW_EVENT_BASE + 6, + VXGE_HW_EVENT_MRPCIM_ECCERR = VXGE_HW_EVENT_BASE + 7, + VXGE_HW_EVENT_FIFO_ERR = VXGE_HW_EVENT_BASE + 8, + VXGE_HW_EVENT_VPATH_ERR = VXGE_HW_EVENT_BASE + 9, + VXGE_HW_EVENT_CRITICAL_ERR = VXGE_HW_EVENT_BASE + 10, + VXGE_HW_EVENT_SERR = VXGE_HW_EVENT_BASE + 11, + VXGE_HW_EVENT_SRPCIM_SERR = VXGE_HW_EVENT_BASE + 12, + VXGE_HW_EVENT_MRPCIM_SERR = VXGE_HW_EVENT_BASE + 13, + VXGE_HW_EVENT_SLOT_FREEZE = VXGE_HW_EVENT_BASE + 14, +}; + +#define VXGE_HW_SET_LEVEL(a, b) (((a) > (b)) ? (a) : (b)) + +/* + * struct vxge_hw_mempool_dma - Represents DMA objects passed to the + caller. + */ +struct vxge_hw_mempool_dma { + dma_addr_t addr; + struct pci_dev *handle; + struct pci_dev *acc_handle; +}; + +/* + * vxge_hw_mempool_item_f - Mempool item alloc/free callback + * @mempoolh: Memory pool handle. + * @memblock: Address of memory block + * @memblock_index: Index of memory block + * @item: Item that gets allocated or freed. + * @index: Item's index in the memory pool. + * @is_last: True, if this item is the last one in the pool; false - otherwise. + * userdata: Per-pool user context. + * + * Memory pool allocation/deallocation callback. + */ + +/* + * struct vxge_hw_mempool - Memory pool. + */ +struct vxge_hw_mempool { + + void (*item_func_alloc)( + struct vxge_hw_mempool *mempoolh, + u32 memblock_index, + struct vxge_hw_mempool_dma *dma_object, + u32 index, + u32 is_last); + + void *userdata; + void **memblocks_arr; + void **memblocks_priv_arr; + struct vxge_hw_mempool_dma *memblocks_dma_arr; + struct __vxge_hw_device *devh; + u32 memblock_size; + u32 memblocks_max; + u32 memblocks_allocated; + u32 item_size; + u32 items_max; + u32 items_initial; + u32 items_current; + u32 items_per_memblock; + void **items_arr; + u32 items_priv_size; +}; + +#define VXGE_HW_MAX_INTR_PER_VP 4 +#define VXGE_HW_VPATH_INTR_TX 0 +#define VXGE_HW_VPATH_INTR_RX 1 +#define VXGE_HW_VPATH_INTR_EINTA 2 +#define VXGE_HW_VPATH_INTR_BMAP 3 + +#define VXGE_HW_BLOCK_SIZE 4096 + +/** + * struct vxge_hw_tim_intr_config - Titan Tim interrupt configuration. + * @intr_enable: Set to 1, if interrupt is enabled. + * @btimer_val: Boundary Timer Initialization value in units of 272 ns. + * @timer_ac_en: Timer Automatic Cancel. 1 : Automatic Canceling Enable: when + * asserted, other interrupt-generating entities will cancel the + * scheduled timer interrupt. + * @timer_ci_en: Timer Continuous Interrupt. 1 : Continuous Interrupting Enable: + * When asserted, an interrupt will be generated every time the + * boundary timer expires, even if no traffic has been transmitted + * on this interrupt. + * @timer_ri_en: Timer Consecutive (Re-) Interrupt 1 : Consecutive + * (Re-) Interrupt Enable: When asserted, an interrupt will be + * generated the next time the timer expires, even if no traffic has + * been transmitted on this interrupt. (This will only happen once + * each time that this value is written to the TIM.) This bit is + * cleared by H/W at the end of the current-timer-interval when + * the interrupt is triggered. + * @rtimer_val: Restriction Timer Initialization value in units of 272 ns. + * @util_sel: Utilization Selector. Selects which of the workload approximations + * to use (e.g. legacy Tx utilization, Tx/Rx utilization, host + * specified utilization etc.), selects one of + * the 17 host configured values. + * 0-Virtual Path 0 + * 1-Virtual Path 1 + * ... + * 16-Virtual Path 17 + * 17-Legacy Tx network utilization, provided by TPA + * 18-Legacy Rx network utilization, provided by FAU + * 19-Average of legacy Rx and Tx utilization calculated from link + * utilization values. + * 20-31-Invalid configurations + * 32-Host utilization for Virtual Path 0 + * 33-Host utilization for Virtual Path 1 + * ... + * 48-Host utilization for Virtual Path 17 + * 49-Legacy Tx network utilization, provided by TPA + * 50-Legacy Rx network utilization, provided by FAU + * 51-Average of legacy Rx and Tx utilization calculated from + * link utilization values. + * 52-63-Invalid configurations + * @ltimer_val: Latency Timer Initialization Value in units of 272 ns. + * @txd_cnt_en: TxD Return Event Count Enable. This configuration bit when set + * to 1 enables counting of TxD0 returns (signalled by PCC's), + * towards utilization event count values. + * @urange_a: Defines the upper limit (in percent) for this utilization range + * to be active. This range is considered active + * if 0 = UTIL = URNG_A + * and the UEC_A field (below) is non-zero. + * @uec_a: Utilization Event Count A. If this range is active, the adapter will + * wait until UEC_A events have occurred on the interrupt before + * generating an interrupt. + * @urange_b: Link utilization range B. + * @uec_b: Utilization Event Count B. + * @urange_c: Link utilization range C. + * @uec_c: Utilization Event Count C. + * @urange_d: Link utilization range D. + * @uec_d: Utilization Event Count D. + * Traffic Interrupt Controller Module interrupt configuration. + */ +struct vxge_hw_tim_intr_config { + + u32 intr_enable; +#define VXGE_HW_TIM_INTR_ENABLE 1 +#define VXGE_HW_TIM_INTR_DISABLE 0 +#define VXGE_HW_TIM_INTR_DEFAULT 0 + + u32 btimer_val; +#define VXGE_HW_MIN_TIM_BTIMER_VAL 0 +#define VXGE_HW_MAX_TIM_BTIMER_VAL 67108864 +#define VXGE_HW_USE_FLASH_DEFAULT 0xffffffff + + u32 timer_ac_en; +#define VXGE_HW_TIM_TIMER_AC_ENABLE 1 +#define VXGE_HW_TIM_TIMER_AC_DISABLE 0 + + u32 timer_ci_en; +#define VXGE_HW_TIM_TIMER_CI_ENABLE 1 +#define VXGE_HW_TIM_TIMER_CI_DISABLE 0 + + u32 timer_ri_en; +#define VXGE_HW_TIM_TIMER_RI_ENABLE 1 +#define VXGE_HW_TIM_TIMER_RI_DISABLE 0 + + u32 rtimer_val; +#define VXGE_HW_MIN_TIM_RTIMER_VAL 0 +#define VXGE_HW_MAX_TIM_RTIMER_VAL 67108864 + + u32 util_sel; +#define VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_NET_UTIL 17 +#define VXGE_HW_TIM_UTIL_SEL_LEGACY_RX_NET_UTIL 18 +#define VXGE_HW_TIM_UTIL_SEL_LEGACY_TX_RX_AVE_NET_UTIL 19 +#define VXGE_HW_TIM_UTIL_SEL_PER_VPATH 63 + + u32 ltimer_val; +#define VXGE_HW_MIN_TIM_LTIMER_VAL 0 +#define VXGE_HW_MAX_TIM_LTIMER_VAL 67108864 + + /* Line utilization interrupts */ + u32 urange_a; +#define VXGE_HW_MIN_TIM_URANGE_A 0 +#define VXGE_HW_MAX_TIM_URANGE_A 100 + + u32 uec_a; +#define VXGE_HW_MIN_TIM_UEC_A 0 +#define VXGE_HW_MAX_TIM_UEC_A 65535 + + u32 urange_b; +#define VXGE_HW_MIN_TIM_URANGE_B 0 +#define VXGE_HW_MAX_TIM_URANGE_B 100 + + u32 uec_b; +#define VXGE_HW_MIN_TIM_UEC_B 0 +#define VXGE_HW_MAX_TIM_UEC_B 65535 + + u32 urange_c; +#define VXGE_HW_MIN_TIM_URANGE_C 0 +#define VXGE_HW_MAX_TIM_URANGE_C 100 + + u32 uec_c; +#define VXGE_HW_MIN_TIM_UEC_C 0 +#define VXGE_HW_MAX_TIM_UEC_C 65535 + + u32 uec_d; +#define VXGE_HW_MIN_TIM_UEC_D 0 +#define VXGE_HW_MAX_TIM_UEC_D 65535 +}; + +#define VXGE_HW_STATS_OP_READ 0 +#define VXGE_HW_STATS_OP_CLEAR_STAT 1 +#define VXGE_HW_STATS_OP_CLEAR_ALL_VPATH_STATS 2 +#define VXGE_HW_STATS_OP_CLEAR_ALL_STATS_OF_LOC 2 +#define VXGE_HW_STATS_OP_CLEAR_ALL_STATS 3 + +#define VXGE_HW_STATS_LOC_AGGR 17 +#define VXGE_HW_STATS_AGGRn_OFFSET 0x00720 + +#define VXGE_HW_STATS_VPATH_TX_OFFSET 0x0 +#define VXGE_HW_STATS_VPATH_RX_OFFSET 0x00090 + +#define VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM0_OFFSET (0x001d0 >> 3) +#define VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM0(bits) \ + vxge_bVALn(bits, 0, 32) + +#define VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM1(bits) \ + vxge_bVALn(bits, 32, 32) + +#define VXGE_HW_STATS_VPATH_PROG_EVENT_VNUM2_OFFSET (0x001d8 >> 3) +#define VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM2(bits) \ + vxge_bVALn(bits, 0, 32) + +#define VXGE_HW_STATS_GET_VPATH_PROG_EVENT_VNUM3(bits) \ + vxge_bVALn(bits, 32, 32) + +/** + * struct vxge_hw_xmac_aggr_stats - Per-Aggregator XMAC Statistics + * + * @tx_frms: Count of data frames transmitted on this Aggregator on all + * its Aggregation ports. Does not include LACPDUs or Marker PDUs. + * However, does include frames discarded by the Distribution + * function. + * @tx_data_octets: Count of data and padding octets of frames transmitted + * on this Aggregator on all its Aggregation ports. Does not include + * octets of LACPDUs or Marker PDUs. However, does include octets of + * frames discarded by the Distribution function. + * @tx_mcast_frms: Count of data frames transmitted (to a group destination + * address other than the broadcast address) on this Aggregator on + * all its Aggregation ports. Does not include LACPDUs or Marker + * PDUs. However, does include frames discarded by the Distribution + * function. + * @tx_bcast_frms: Count of broadcast data frames transmitted on this Aggregator + * on all its Aggregation ports. Does not include LACPDUs or Marker + * PDUs. However, does include frames discarded by the Distribution + * function. + * @tx_discarded_frms: Count of data frames to be transmitted on this Aggregator + * that are discarded by the Distribution function. This occurs when + * conversation are allocated to different ports and have to be + * flushed on old ports + * @tx_errored_frms: Count of data frames transmitted on this Aggregator that + * experience transmission errors on its Aggregation ports. + * @rx_frms: Count of data frames received on this Aggregator on all its + * Aggregation ports. Does not include LACPDUs or Marker PDUs. + * Also, does not include frames discarded by the Collection + * function. + * @rx_data_octets: Count of data and padding octets of frames received on this + * Aggregator on all its Aggregation ports. Does not include octets + * of LACPDUs or Marker PDUs. Also, does not include + * octets of frames + * discarded by the Collection function. + * @rx_mcast_frms: Count of data frames received (from a group destination + * address other than the broadcast address) on this Aggregator on + * all its Aggregation ports. Does not include LACPDUs or Marker + * PDUs. Also, does not include frames discarded by the Collection + * function. + * @rx_bcast_frms: Count of broadcast data frames received on this Aggregator on + * all its Aggregation ports. Does not include LACPDUs or Marker + * PDUs. Also, does not include frames discarded by the Collection + * function. + * @rx_discarded_frms: Count of data frames received on this Aggregator that are + * discarded by the Collection function because the Collection + * function was disabled on the port which the frames are received. + * @rx_errored_frms: Count of data frames received on this Aggregator that are + * discarded by its Aggregation ports, or are discarded by the + * Collection function of the Aggregator, or that are discarded by + * the Aggregator due to detection of an illegal Slow Protocols PDU. + * @rx_unknown_slow_proto_frms: Count of data frames received on this Aggregator + * that are discarded by its Aggregation ports due to detection of + * an unknown Slow Protocols PDU. + * + * Per aggregator XMAC RX statistics. + */ +struct vxge_hw_xmac_aggr_stats { +/*0x000*/ u64 tx_frms; +/*0x008*/ u64 tx_data_octets; +/*0x010*/ u64 tx_mcast_frms; +/*0x018*/ u64 tx_bcast_frms; +/*0x020*/ u64 tx_discarded_frms; +/*0x028*/ u64 tx_errored_frms; +/*0x030*/ u64 rx_frms; +/*0x038*/ u64 rx_data_octets; +/*0x040*/ u64 rx_mcast_frms; +/*0x048*/ u64 rx_bcast_frms; +/*0x050*/ u64 rx_discarded_frms; +/*0x058*/ u64 rx_errored_frms; +/*0x060*/ u64 rx_unknown_slow_proto_frms; +} __packed; + +/** + * struct vxge_hw_xmac_port_stats - XMAC Port Statistics + * + * @tx_ttl_frms: Count of successfully transmitted MAC frames + * @tx_ttl_octets: Count of total octets of transmitted frames, not including + * framing characters (i.e. less framing bits). To determine the + * total octets of transmitted frames, including framing characters, + * multiply PORTn_TX_TTL_FRMS by 8 and add it to this stat (unless + * otherwise configured, this stat only counts frames that have + * 8 bytes of preamble for each frame). This stat can be configured + * (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count everything + * including the preamble octets. + * @tx_data_octets: Count of data and padding octets of successfully transmitted + * frames. + * @tx_mcast_frms: Count of successfully transmitted frames to a group address + * other than the broadcast address. + * @tx_bcast_frms: Count of successfully transmitted frames to the broadcast + * group address. + * @tx_ucast_frms: Count of transmitted frames containing a unicast address. + * Includes discarded frames that are not sent to the network. + * @tx_tagged_frms: Count of transmitted frames containing a VLAN tag. + * @tx_vld_ip: Count of transmitted IP datagrams that are passed to the network. + * @tx_vld_ip_octets: Count of total octets of transmitted IP datagrams that + * are passed to the network. + * @tx_icmp: Count of transmitted ICMP messages. Includes messages not sent + * due to problems within ICMP. + * @tx_tcp: Count of transmitted TCP segments. Does not include segments + * containing retransmitted octets. + * @tx_rst_tcp: Count of transmitted TCP segments containing the RST flag. + * @tx_udp: Count of transmitted UDP datagrams. + * @tx_parse_error: Increments when the TPA is unable to parse a packet. This + * generally occurs when a packet is corrupt somehow, including + * packets that have IP version mismatches, invalid Layer 2 control + * fields, etc. L3/L4 checksums are not offloaded, but the packet + * is still be transmitted. + * @tx_unknown_protocol: Increments when the TPA encounters an unknown + * protocol, such as a new IPv6 extension header, or an unsupported + * Routing Type. The packet still has a checksum calculated but it + * may be incorrect. + * @tx_pause_ctrl_frms: Count of MAC PAUSE control frames that are transmitted. + * Since, the only control frames supported by this device are + * PAUSE frames, this register is a count of all transmitted MAC + * control frames. + * @tx_marker_pdu_frms: Count of Marker PDUs transmitted + * on this Aggregation port. + * @tx_lacpdu_frms: Count of LACPDUs transmitted on this Aggregation port. + * @tx_drop_ip: Count of transmitted IP datagrams that could not be passed to + * the network. Increments because of: + * 1) An internal processing error + * (such as an uncorrectable ECC error). 2) A frame parsing error + * during IP checksum calculation. + * @tx_marker_resp_pdu_frms: Count of Marker Response PDUs transmitted on this + * Aggregation port. + * @tx_xgmii_char2_match: Maintains a count of the number of transmitted XGMII + * characters that match a pattern that is programmable through + * register XMAC_STATS_TX_XGMII_CHAR_PORTn. By default, the pattern + * is set to /T/ (i.e. the terminate character), thus the statistic + * tracks the number of transmitted Terminate characters. + * @tx_xgmii_char1_match: Maintains a count of the number of transmitted XGMII + * characters that match a pattern that is programmable through + * register XMAC_STATS_TX_XGMII_CHAR_PORTn. By default, the pattern + * is set to /S/ (i.e. the start character), + * thus the statistic tracks + * the number of transmitted Start characters. + * @tx_xgmii_column2_match: Maintains a count of the number of transmitted XGMII + * columns that match a pattern that is programmable through register + * XMAC_STATS_TX_XGMII_COLUMN2_PORTn. By default, the pattern is set + * to 4 x /E/ (i.e. a column containing all error characters), thus + * the statistic tracks the number of Error columns transmitted at + * any time. If XMAC_STATS_TX_XGMII_BEHAV_COLUMN2_PORTn.NEAR_COL1 is + * set to 1, then this stat increments when COLUMN2 is found within + * 'n' clocks after COLUMN1. Here, 'n' is defined by + * XMAC_STATS_TX_XGMII_BEHAV_COLUMN2_PORTn.NUM_COL (if 'n' is set + * to 0, then it means to search anywhere for COLUMN2). + * @tx_xgmii_column1_match: Maintains a count of the number of transmitted XGMII + * columns that match a pattern that is programmable through register + * XMAC_STATS_TX_XGMII_COLUMN1_PORTn. By default, the pattern is set + * to 4 x /I/ (i.e. a column containing all idle characters), + * thus the statistic tracks the number of transmitted Idle columns. + * @tx_any_err_frms: Count of transmitted frames containing any error that + * prevents them from being passed to the network. Increments if + * there is an ECC while reading the frame out of the transmit + * buffer. Also increments if the transmit protocol assist (TPA) + * block determines that the frame should not be sent. + * @tx_drop_frms: Count of frames that could not be sent for no other reason + * than internal MAC processing. Increments once whenever the + * transmit buffer is flushed (due to an ECC error on a memory + * descriptor). + * @rx_ttl_frms: Count of total received MAC frames, including frames received + * with frame-too-long, FCS, or length errors. This stat can be + * configured (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count + * everything, even "frames" as small one byte of preamble. + * @rx_vld_frms: Count of successfully received MAC frames. Does not include + * frames received with frame-too-long, FCS, or length errors. + * @rx_offload_frms: Count of offloaded received frames that are passed to + * the host. + * @rx_ttl_octets: Count of total octets of received frames, not including + * framing characters (i.e. less framing bits). To determine the + * total octets of received frames, including framing characters, + * multiply PORTn_RX_TTL_FRMS by 8 and add it to this stat (unless + * otherwise configured, this stat only counts frames that have 8 + * bytes of preamble for each frame). This stat can be configured + * (see XMAC_STATS_GLOBAL_CFG.TTL_FRMS_HANDLING) to count everything, + * even the preamble octets of "frames" as small one byte of preamble + * @rx_data_octets: Count of data and padding octets of successfully received + * frames. Does not include frames received with frame-too-long, + * FCS, or length errors. + * @rx_offload_octets: Count of total octets, not including framing + * characters, of offloaded received frames that are passed + * to the host. + * @rx_vld_mcast_frms: Count of successfully received MAC frames containing a + * nonbroadcast group address. Does not include frames received + * with frame-too-long, FCS, or length errors. + * @rx_vld_bcast_frms: Count of successfully received MAC frames containing + * the broadcast group address. Does not include frames received + * with frame-too-long, FCS, or length errors. + * @rx_accepted_ucast_frms: Count of successfully received frames containing + * a unicast address. Only includes frames that are passed to + * the system. + * @rx_accepted_nucast_frms: Count of successfully received frames containing + * a non-unicast (broadcast or multicast) address. Only includes + * frames that are passed to the system. Could include, for instance, + * non-unicast frames that contain FCS errors if the MAC_ERROR_CFG + * register is set to pass FCS-errored frames to the host. + * @rx_tagged_frms: Count of received frames containing a VLAN tag. + * @rx_long_frms: Count of received frames that are longer than RX_MAX_PYLD_LEN + * + 18 bytes (+ 22 bytes if VLAN-tagged). + * @rx_usized_frms: Count of received frames of length (including FCS, but not + * framing bits) less than 64 octets, that are otherwise well-formed. + * In other words, counts runts. + * @rx_osized_frms: Count of received frames of length (including FCS, but not + * framing bits) more than 1518 octets, that are otherwise + * well-formed. Note: If register XMAC_STATS_GLOBAL_CFG.VLAN_HANDLING + * is set to 1, then "more than 1518 octets" becomes "more than 1518 + * (1522 if VLAN-tagged) octets". + * @rx_frag_frms: Count of received frames of length (including FCS, but not + * framing bits) less than 64 octets that had bad FCS. In other + * words, counts fragments. + * @rx_jabber_frms: Count of received frames of length (including FCS, but not + * framing bits) more than 1518 octets that had bad FCS. In other + * words, counts jabbers. Note: If register + * XMAC_STATS_GLOBAL_CFG.VLAN_HANDLING is set to 1, then "more than + * 1518 octets" becomes "more than 1518 (1522 if VLAN-tagged) + * octets". + * @rx_ttl_64_frms: Count of total received MAC frames with length (including + * FCS, but not framing bits) of exactly 64 octets. Includes frames + * received with frame-too-long, FCS, or length errors. + * @rx_ttl_65_127_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 65 and 127 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_128_255_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 128 and 255 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_256_511_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 256 and 511 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_512_1023_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 512 and 1023 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_1024_1518_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 1024 and 1518 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_1519_4095_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 1519 and 4095 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_4096_8191_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 4096 and 8191 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_8192_max_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 8192 and + * RX_MAX_PYLD_LEN+18 octets inclusive. Includes frames received + * with frame-too-long, FCS, or length errors. + * @rx_ttl_gt_max_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) exceeding + * RX_MAX_PYLD_LEN+18 (+22 bytes if VLAN-tagged) octets inclusive. + * Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ip: Count of received IP datagrams. Includes errored IP datagrams. + * @rx_accepted_ip: Count of received IP datagrams that + * are passed to the system. + * @rx_ip_octets: Count of number of octets in received IP datagrams. Includes + * errored IP datagrams. + * @rx_err_ip: Count of received IP datagrams containing errors. For example, + * bad IP checksum. + * @rx_icmp: Count of received ICMP messages. Includes errored ICMP messages. + * @rx_tcp: Count of received TCP segments. Includes errored TCP segments. + * Note: This stat contains a count of all received TCP segments, + * regardless of whether or not they pertain to an established + * connection. + * @rx_udp: Count of received UDP datagrams. + * @rx_err_tcp: Count of received TCP segments containing errors. For example, + * bad TCP checksum. + * @rx_pause_count: Count of number of pause quanta that the MAC has been in + * the paused state. Recall, one pause quantum equates to 512 + * bit times. + * @rx_pause_ctrl_frms: Count of received MAC PAUSE control frames. + * @rx_unsup_ctrl_frms: Count of received MAC control frames that do not + * contain the PAUSE opcode. The sum of RX_PAUSE_CTRL_FRMS and + * this register is a count of all received MAC control frames. + * Note: This stat may be configured to count all layer 2 errors + * (i.e. length errors and FCS errors). + * @rx_fcs_err_frms: Count of received MAC frames that do not pass FCS. Does + * not include frames received with frame-too-long or + * frame-too-short error. + * @rx_in_rng_len_err_frms: Count of received frames with a length/type field + * value between 46 (42 for VLAN-tagged frames) and 1500 (also 1500 + * for VLAN-tagged frames), inclusive, that does not match the + * number of data octets (including pad) received. Also contains + * a count of received frames with a length/type field less than + * 46 (42 for VLAN-tagged frames) and the number of data octets + * (including pad) received is greater than 46 (42 for VLAN-tagged + * frames). + * @rx_out_rng_len_err_frms: Count of received frames with length/type field + * between 1501 and 1535 decimal, inclusive. + * @rx_drop_frms: Count of received frames that could not be passed to the host. + * See PORTn_RX_L2_MGMT_DISCARD, PORTn_RX_RPA_DISCARD, + * PORTn_RX_TRASH_DISCARD, PORTn_RX_RTS_DISCARD, PORTn_RX_RED_DISCARD + * for a list of reasons. Because the RMAC drops one frame at a time, + * this stat also indicates the number of drop events. + * @rx_discarded_frms: Count of received frames containing + * any error that prevents + * them from being passed to the system. See PORTn_RX_FCS_DISCARD, + * PORTn_RX_LEN_DISCARD, and PORTn_RX_SWITCH_DISCARD for a list of + * reasons. + * @rx_drop_ip: Count of received IP datagrams that could not be passed to the + * host. See PORTn_RX_DROP_FRMS for a list of reasons. + * @rx_drop_udp: Count of received UDP datagrams that are not delivered to the + * host. See PORTn_RX_DROP_FRMS for a list of reasons. + * @rx_marker_pdu_frms: Count of valid Marker PDUs received on this Aggregation + * port. + * @rx_lacpdu_frms: Count of valid LACPDUs received on this Aggregation port. + * @rx_unknown_pdu_frms: Count of received frames (on this Aggregation port) + * that carry the Slow Protocols EtherType, but contain an unknown + * PDU. Or frames that contain the Slow Protocols group MAC address, + * but do not carry the Slow Protocols EtherType. + * @rx_marker_resp_pdu_frms: Count of valid Marker Response PDUs received on + * this Aggregation port. + * @rx_fcs_discard: Count of received frames that are discarded because the + * FCS check failed. + * @rx_illegal_pdu_frms: Count of received frames (on this Aggregation port) + * that carry the Slow Protocols EtherType, but contain a badly + * formed PDU. Or frames that carry the Slow Protocols EtherType, + * but contain an illegal value of Protocol Subtype. + * @rx_switch_discard: Count of received frames that are discarded by the + * internal switch because they did not have an entry in the + * Filtering Database. This includes frames that had an invalid + * destination MAC address or VLAN ID. It also includes frames are + * discarded because they did not satisfy the length requirements + * of the target VPATH. + * @rx_len_discard: Count of received frames that are discarded because of an + * invalid frame length (includes fragments, oversized frames and + * mismatch between frame length and length/type field). This stat + * can be configured + * (see XMAC_STATS_GLOBAL_CFG.LEN_DISCARD_HANDLING). + * @rx_rpa_discard: Count of received frames that were discarded because the + * receive protocol assist (RPA) discovered and error in the frame + * or was unable to parse the frame. + * @rx_l2_mgmt_discard: Count of Layer 2 management frames (eg. pause frames, + * Link Aggregation Control Protocol (LACP) frames, etc.) that are + * discarded. + * @rx_rts_discard: Count of received frames that are discarded by the receive + * traffic steering (RTS) logic. Includes those frame discarded + * because the SSC response contradicted the switch table, because + * the SSC timed out, or because the target queue could not fit the + * frame. + * @rx_trash_discard: Count of received frames that are discarded because + * receive traffic steering (RTS) steered the frame to the trash + * queue. + * @rx_buff_full_discard: Count of received frames that are discarded because + * internal buffers are full. Includes frames discarded because the + * RTS logic is waiting for an SSC lookup that has no timeout bound. + * Also, includes frames that are dropped because the MAC2FAU buffer + * is nearly full -- this can happen if the external receive buffer + * is full and the receive path is backing up. + * @rx_red_discard: Count of received frames that are discarded because of RED + * (Random Early Discard). + * @rx_xgmii_ctrl_err_cnt: Maintains a count of unexpected or misplaced control + * characters occuring between times of normal data transmission + * (i.e. not included in RX_XGMII_DATA_ERR_CNT). This counter is + * incremented when either - + * 1) The Reconciliation Sublayer (RS) is expecting one control + * character and gets another (i.e. is expecting a Start + * character, but gets another control character). + * 2) Start control character is not in lane 0 + * Only increments the count by one for each XGMII column. + * @rx_xgmii_data_err_cnt: Maintains a count of unexpected control characters + * during normal data transmission. If the Reconciliation Sublayer + * (RS) receives a control character, other than a terminate control + * character, during receipt of data octets then this register is + * incremented. Also increments if the start frame delimiter is not + * found in the correct location. Only increments the count by one + * for each XGMII column. + * @rx_xgmii_char1_match: Maintains a count of the number of XGMII characters + * that match a pattern that is programmable through register + * XMAC_STATS_RX_XGMII_CHAR_PORTn. By default, the pattern is set + * to /E/ (i.e. the error character), thus the statistic tracks the + * number of Error characters received at any time. + * @rx_xgmii_err_sym: Count of the number of symbol errors in the received + * XGMII data (i.e. PHY indicates "Receive Error" on the XGMII). + * Only includes symbol errors that are observed between the XGMII + * Start Frame Delimiter and End Frame Delimiter, inclusive. And + * only increments the count by one for each frame. + * @rx_xgmii_column1_match: Maintains a count of the number of XGMII columns + * that match a pattern that is programmable through register + * XMAC_STATS_RX_XGMII_COLUMN1_PORTn. By default, the pattern is set + * to 4 x /E/ (i.e. a column containing all error characters), thus + * the statistic tracks the number of Error columns received at any + * time. + * @rx_xgmii_char2_match: Maintains a count of the number of XGMII characters + * that match a pattern that is programmable through register + * XMAC_STATS_RX_XGMII_CHAR_PORTn. By default, the pattern is set + * to /E/ (i.e. the error character), thus the statistic tracks the + * number of Error characters received at any time. + * @rx_local_fault: Maintains a count of the number of times that link + * transitioned from "up" to "down" due to a local fault. + * @rx_xgmii_column2_match: Maintains a count of the number of XGMII columns + * that match a pattern that is programmable through register + * XMAC_STATS_RX_XGMII_COLUMN2_PORTn. By default, the pattern is set + * to 4 x /E/ (i.e. a column containing all error characters), thus + * the statistic tracks the number of Error columns received at any + * time. If XMAC_STATS_RX_XGMII_BEHAV_COLUMN2_PORTn.NEAR_COL1 is set + * to 1, then this stat increments when COLUMN2 is found within 'n' + * clocks after COLUMN1. Here, 'n' is defined by + * XMAC_STATS_RX_XGMII_BEHAV_COLUMN2_PORTn.NUM_COL (if 'n' is set to + * 0, then it means to search anywhere for COLUMN2). + * @rx_jettison: Count of received frames that are jettisoned because internal + * buffers are full. + * @rx_remote_fault: Maintains a count of the number of times that link + * transitioned from "up" to "down" due to a remote fault. + * + * XMAC Port Statistics. + */ +struct vxge_hw_xmac_port_stats { +/*0x000*/ u64 tx_ttl_frms; +/*0x008*/ u64 tx_ttl_octets; +/*0x010*/ u64 tx_data_octets; +/*0x018*/ u64 tx_mcast_frms; +/*0x020*/ u64 tx_bcast_frms; +/*0x028*/ u64 tx_ucast_frms; +/*0x030*/ u64 tx_tagged_frms; +/*0x038*/ u64 tx_vld_ip; +/*0x040*/ u64 tx_vld_ip_octets; +/*0x048*/ u64 tx_icmp; +/*0x050*/ u64 tx_tcp; +/*0x058*/ u64 tx_rst_tcp; +/*0x060*/ u64 tx_udp; +/*0x068*/ u32 tx_parse_error; +/*0x06c*/ u32 tx_unknown_protocol; +/*0x070*/ u64 tx_pause_ctrl_frms; +/*0x078*/ u32 tx_marker_pdu_frms; +/*0x07c*/ u32 tx_lacpdu_frms; +/*0x080*/ u32 tx_drop_ip; +/*0x084*/ u32 tx_marker_resp_pdu_frms; +/*0x088*/ u32 tx_xgmii_char2_match; +/*0x08c*/ u32 tx_xgmii_char1_match; +/*0x090*/ u32 tx_xgmii_column2_match; +/*0x094*/ u32 tx_xgmii_column1_match; +/*0x098*/ u32 unused1; +/*0x09c*/ u16 tx_any_err_frms; +/*0x09e*/ u16 tx_drop_frms; +/*0x0a0*/ u64 rx_ttl_frms; +/*0x0a8*/ u64 rx_vld_frms; +/*0x0b0*/ u64 rx_offload_frms; +/*0x0b8*/ u64 rx_ttl_octets; +/*0x0c0*/ u64 rx_data_octets; +/*0x0c8*/ u64 rx_offload_octets; +/*0x0d0*/ u64 rx_vld_mcast_frms; +/*0x0d8*/ u64 rx_vld_bcast_frms; +/*0x0e0*/ u64 rx_accepted_ucast_frms; +/*0x0e8*/ u64 rx_accepted_nucast_frms; +/*0x0f0*/ u64 rx_tagged_frms; +/*0x0f8*/ u64 rx_long_frms; +/*0x100*/ u64 rx_usized_frms; +/*0x108*/ u64 rx_osized_frms; +/*0x110*/ u64 rx_frag_frms; +/*0x118*/ u64 rx_jabber_frms; +/*0x120*/ u64 rx_ttl_64_frms; +/*0x128*/ u64 rx_ttl_65_127_frms; +/*0x130*/ u64 rx_ttl_128_255_frms; +/*0x138*/ u64 rx_ttl_256_511_frms; +/*0x140*/ u64 rx_ttl_512_1023_frms; +/*0x148*/ u64 rx_ttl_1024_1518_frms; +/*0x150*/ u64 rx_ttl_1519_4095_frms; +/*0x158*/ u64 rx_ttl_4096_8191_frms; +/*0x160*/ u64 rx_ttl_8192_max_frms; +/*0x168*/ u64 rx_ttl_gt_max_frms; +/*0x170*/ u64 rx_ip; +/*0x178*/ u64 rx_accepted_ip; +/*0x180*/ u64 rx_ip_octets; +/*0x188*/ u64 rx_err_ip; +/*0x190*/ u64 rx_icmp; +/*0x198*/ u64 rx_tcp; +/*0x1a0*/ u64 rx_udp; +/*0x1a8*/ u64 rx_err_tcp; +/*0x1b0*/ u64 rx_pause_count; +/*0x1b8*/ u64 rx_pause_ctrl_frms; +/*0x1c0*/ u64 rx_unsup_ctrl_frms; +/*0x1c8*/ u64 rx_fcs_err_frms; +/*0x1d0*/ u64 rx_in_rng_len_err_frms; +/*0x1d8*/ u64 rx_out_rng_len_err_frms; +/*0x1e0*/ u64 rx_drop_frms; +/*0x1e8*/ u64 rx_discarded_frms; +/*0x1f0*/ u64 rx_drop_ip; +/*0x1f8*/ u64 rx_drop_udp; +/*0x200*/ u32 rx_marker_pdu_frms; +/*0x204*/ u32 rx_lacpdu_frms; +/*0x208*/ u32 rx_unknown_pdu_frms; +/*0x20c*/ u32 rx_marker_resp_pdu_frms; +/*0x210*/ u32 rx_fcs_discard; +/*0x214*/ u32 rx_illegal_pdu_frms; +/*0x218*/ u32 rx_switch_discard; +/*0x21c*/ u32 rx_len_discard; +/*0x220*/ u32 rx_rpa_discard; +/*0x224*/ u32 rx_l2_mgmt_discard; +/*0x228*/ u32 rx_rts_discard; +/*0x22c*/ u32 rx_trash_discard; +/*0x230*/ u32 rx_buff_full_discard; +/*0x234*/ u32 rx_red_discard; +/*0x238*/ u32 rx_xgmii_ctrl_err_cnt; +/*0x23c*/ u32 rx_xgmii_data_err_cnt; +/*0x240*/ u32 rx_xgmii_char1_match; +/*0x244*/ u32 rx_xgmii_err_sym; +/*0x248*/ u32 rx_xgmii_column1_match; +/*0x24c*/ u32 rx_xgmii_char2_match; +/*0x250*/ u32 rx_local_fault; +/*0x254*/ u32 rx_xgmii_column2_match; +/*0x258*/ u32 rx_jettison; +/*0x25c*/ u32 rx_remote_fault; +} __packed; + +/** + * struct vxge_hw_xmac_vpath_tx_stats - XMAC Vpath Tx Statistics + * + * @tx_ttl_eth_frms: Count of successfully transmitted MAC frames. + * @tx_ttl_eth_octets: Count of total octets of transmitted frames, + * not including framing characters (i.e. less framing bits). + * To determine the total octets of transmitted frames, including + * framing characters, multiply TX_TTL_ETH_FRMS by 8 and add it to + * this stat (the device always prepends 8 bytes of preamble for + * each frame) + * @tx_data_octets: Count of data and padding octets of successfully transmitted + * frames. + * @tx_mcast_frms: Count of successfully transmitted frames to a group address + * other than the broadcast address. + * @tx_bcast_frms: Count of successfully transmitted frames to the broadcast + * group address. + * @tx_ucast_frms: Count of transmitted frames containing a unicast address. + * Includes discarded frames that are not sent to the network. + * @tx_tagged_frms: Count of transmitted frames containing a VLAN tag. + * @tx_vld_ip: Count of transmitted IP datagrams that are passed to the network. + * @tx_vld_ip_octets: Count of total octets of transmitted IP datagrams that + * are passed to the network. + * @tx_icmp: Count of transmitted ICMP messages. Includes messages not sent due + * to problems within ICMP. + * @tx_tcp: Count of transmitted TCP segments. Does not include segments + * containing retransmitted octets. + * @tx_rst_tcp: Count of transmitted TCP segments containing the RST flag. + * @tx_udp: Count of transmitted UDP datagrams. + * @tx_unknown_protocol: Increments when the TPA encounters an unknown protocol, + * such as a new IPv6 extension header, or an unsupported Routing + * Type. The packet still has a checksum calculated but it may be + * incorrect. + * @tx_lost_ip: Count of transmitted IP datagrams that could not be passed + * to the network. Increments because of: 1) An internal processing + * error (such as an uncorrectable ECC error). 2) A frame parsing + * error during IP checksum calculation. + * @tx_parse_error: Increments when the TPA is unable to parse a packet. This + * generally occurs when a packet is corrupt somehow, including + * packets that have IP version mismatches, invalid Layer 2 control + * fields, etc. L3/L4 checksums are not offloaded, but the packet + * is still be transmitted. + * @tx_tcp_offload: For frames belonging to offloaded sessions only, a count + * of transmitted TCP segments. Does not include segments containing + * retransmitted octets. + * @tx_retx_tcp_offload: For frames belonging to offloaded sessions only, the + * total number of segments retransmitted. Retransmitted segments + * that are sourced by the host are counted by the host. + * @tx_lost_ip_offload: For frames belonging to offloaded sessions only, a count + * of transmitted IP datagrams that could not be passed to the + * network. + * + * XMAC Vpath TX Statistics. + */ +struct vxge_hw_xmac_vpath_tx_stats { + u64 tx_ttl_eth_frms; + u64 tx_ttl_eth_octets; + u64 tx_data_octets; + u64 tx_mcast_frms; + u64 tx_bcast_frms; + u64 tx_ucast_frms; + u64 tx_tagged_frms; + u64 tx_vld_ip; + u64 tx_vld_ip_octets; + u64 tx_icmp; + u64 tx_tcp; + u64 tx_rst_tcp; + u64 tx_udp; + u32 tx_unknown_protocol; + u32 tx_lost_ip; + u32 unused1; + u32 tx_parse_error; + u64 tx_tcp_offload; + u64 tx_retx_tcp_offload; + u64 tx_lost_ip_offload; +} __packed; + +/** + * struct vxge_hw_xmac_vpath_rx_stats - XMAC Vpath RX Statistics + * + * @rx_ttl_eth_frms: Count of successfully received MAC frames. + * @rx_vld_frms: Count of successfully received MAC frames. Does not include + * frames received with frame-too-long, FCS, or length errors. + * @rx_offload_frms: Count of offloaded received frames that are passed to + * the host. + * @rx_ttl_eth_octets: Count of total octets of received frames, not including + * framing characters (i.e. less framing bits). Only counts octets + * of frames that are at least 14 bytes (18 bytes for VLAN-tagged) + * before FCS. To determine the total octets of received frames, + * including framing characters, multiply RX_TTL_ETH_FRMS by 8 and + * add it to this stat (the stat RX_TTL_ETH_FRMS only counts frames + * that have the required 8 bytes of preamble). + * @rx_data_octets: Count of data and padding octets of successfully received + * frames. Does not include frames received with frame-too-long, + * FCS, or length errors. + * @rx_offload_octets: Count of total octets, not including framing characters, + * of offloaded received frames that are passed to the host. + * @rx_vld_mcast_frms: Count of successfully received MAC frames containing a + * nonbroadcast group address. Does not include frames received with + * frame-too-long, FCS, or length errors. + * @rx_vld_bcast_frms: Count of successfully received MAC frames containing the + * broadcast group address. Does not include frames received with + * frame-too-long, FCS, or length errors. + * @rx_accepted_ucast_frms: Count of successfully received frames containing + * a unicast address. Only includes frames that are passed to the + * system. + * @rx_accepted_nucast_frms: Count of successfully received frames containing + * a non-unicast (broadcast or multicast) address. Only includes + * frames that are passed to the system. Could include, for instance, + * non-unicast frames that contain FCS errors if the MAC_ERROR_CFG + * register is set to pass FCS-errored frames to the host. + * @rx_tagged_frms: Count of received frames containing a VLAN tag. + * @rx_long_frms: Count of received frames that are longer than RX_MAX_PYLD_LEN + * + 18 bytes (+ 22 bytes if VLAN-tagged). + * @rx_usized_frms: Count of received frames of length (including FCS, but not + * framing bits) less than 64 octets, that are otherwise well-formed. + * In other words, counts runts. + * @rx_osized_frms: Count of received frames of length (including FCS, but not + * framing bits) more than 1518 octets, that are otherwise + * well-formed. + * @rx_frag_frms: Count of received frames of length (including FCS, but not + * framing bits) less than 64 octets that had bad FCS. + * In other words, counts fragments. + * @rx_jabber_frms: Count of received frames of length (including FCS, but not + * framing bits) more than 1518 octets that had bad FCS. In other + * words, counts jabbers. + * @rx_ttl_64_frms: Count of total received MAC frames with length (including + * FCS, but not framing bits) of exactly 64 octets. Includes frames + * received with frame-too-long, FCS, or length errors. + * @rx_ttl_65_127_frms: Count of total received MAC frames + * with length (including + * FCS, but not framing bits) of between 65 and 127 octets inclusive. + * Includes frames received with frame-too-long, FCS, + * or length errors. + * @rx_ttl_128_255_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) + * of between 128 and 255 octets + * inclusive. Includes frames received with frame-too-long, FCS, + * or length errors. + * @rx_ttl_256_511_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) + * of between 256 and 511 octets + * inclusive. Includes frames received with frame-too-long, FCS, or + * length errors. + * @rx_ttl_512_1023_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 512 and 1023 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_1024_1518_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 1024 and 1518 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_1519_4095_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 1519 and 4095 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_4096_8191_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 4096 and 8191 + * octets inclusive. Includes frames received with frame-too-long, + * FCS, or length errors. + * @rx_ttl_8192_max_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) of between 8192 and + * RX_MAX_PYLD_LEN+18 octets inclusive. Includes frames received + * with frame-too-long, FCS, or length errors. + * @rx_ttl_gt_max_frms: Count of total received MAC frames with length + * (including FCS, but not framing bits) exceeding RX_MAX_PYLD_LEN+18 + * (+22 bytes if VLAN-tagged) octets inclusive. Includes frames + * received with frame-too-long, FCS, or length errors. + * @rx_ip: Count of received IP datagrams. Includes errored IP datagrams. + * @rx_accepted_ip: Count of received IP datagrams that + * are passed to the system. + * @rx_ip_octets: Count of number of octets in received IP datagrams. + * Includes errored IP datagrams. + * @rx_err_ip: Count of received IP datagrams containing errors. For example, + * bad IP checksum. + * @rx_icmp: Count of received ICMP messages. Includes errored ICMP messages. + * @rx_tcp: Count of received TCP segments. Includes errored TCP segments. + * Note: This stat contains a count of all received TCP segments, + * regardless of whether or not they pertain to an established + * connection. + * @rx_udp: Count of received UDP datagrams. + * @rx_err_tcp: Count of received TCP segments containing errors. For example, + * bad TCP checksum. + * @rx_lost_frms: Count of received frames that could not be passed to the host. + * See RX_QUEUE_FULL_DISCARD and RX_RED_DISCARD + * for a list of reasons. + * @rx_lost_ip: Count of received IP datagrams that could not be passed to + * the host. See RX_LOST_FRMS for a list of reasons. + * @rx_lost_ip_offload: For frames belonging to offloaded sessions only, a count + * of received IP datagrams that could not be passed to the host. + * See RX_LOST_FRMS for a list of reasons. + * @rx_various_discard: Count of received frames that are discarded because + * the target receive queue is full. + * @rx_sleep_discard: Count of received frames that are discarded because the + * target VPATH is asleep (a Wake-on-LAN magic packet can be used + * to awaken the VPATH). + * @rx_red_discard: Count of received frames that are discarded because of RED + * (Random Early Discard). + * @rx_queue_full_discard: Count of received frames that are discarded because + * the target receive queue is full. + * @rx_mpa_ok_frms: Count of received frames that pass the MPA checks. + * + * XMAC Vpath RX Statistics. + */ +struct vxge_hw_xmac_vpath_rx_stats { + u64 rx_ttl_eth_frms; + u64 rx_vld_frms; + u64 rx_offload_frms; + u64 rx_ttl_eth_octets; + u64 rx_data_octets; + u64 rx_offload_octets; + u64 rx_vld_mcast_frms; + u64 rx_vld_bcast_frms; + u64 rx_accepted_ucast_frms; + u64 rx_accepted_nucast_frms; + u64 rx_tagged_frms; + u64 rx_long_frms; + u64 rx_usized_frms; + u64 rx_osized_frms; + u64 rx_frag_frms; + u64 rx_jabber_frms; + u64 rx_ttl_64_frms; + u64 rx_ttl_65_127_frms; + u64 rx_ttl_128_255_frms; + u64 rx_ttl_256_511_frms; + u64 rx_ttl_512_1023_frms; + u64 rx_ttl_1024_1518_frms; + u64 rx_ttl_1519_4095_frms; + u64 rx_ttl_4096_8191_frms; + u64 rx_ttl_8192_max_frms; + u64 rx_ttl_gt_max_frms; + u64 rx_ip; + u64 rx_accepted_ip; + u64 rx_ip_octets; + u64 rx_err_ip; + u64 rx_icmp; + u64 rx_tcp; + u64 rx_udp; + u64 rx_err_tcp; + u64 rx_lost_frms; + u64 rx_lost_ip; + u64 rx_lost_ip_offload; + u16 rx_various_discard; + u16 rx_sleep_discard; + u16 rx_red_discard; + u16 rx_queue_full_discard; + u64 rx_mpa_ok_frms; +} __packed; + +/** + * struct vxge_hw_xmac_stats - XMAC Statistics + * + * @aggr_stats: Statistics on aggregate port(port 0, port 1) + * @port_stats: Staticstics on ports(wire 0, wire 1, lag) + * @vpath_tx_stats: Per vpath XMAC TX stats + * @vpath_rx_stats: Per vpath XMAC RX stats + * + * XMAC Statistics. + */ +struct vxge_hw_xmac_stats { + struct vxge_hw_xmac_aggr_stats + aggr_stats[VXGE_HW_MAC_MAX_MAC_PORT_ID]; + struct vxge_hw_xmac_port_stats + port_stats[VXGE_HW_MAC_MAX_MAC_PORT_ID+1]; + struct vxge_hw_xmac_vpath_tx_stats + vpath_tx_stats[VXGE_HW_MAX_VIRTUAL_PATHS]; + struct vxge_hw_xmac_vpath_rx_stats + vpath_rx_stats[VXGE_HW_MAX_VIRTUAL_PATHS]; +}; + +/** + * struct vxge_hw_vpath_stats_hw_info - Titan vpath hardware statistics. + * @ini_num_mwr_sent: The number of PCI memory writes initiated by the PIC block + * for the given VPATH + * @ini_num_mrd_sent: The number of PCI memory reads initiated by the PIC block + * @ini_num_cpl_rcvd: The number of PCI read completions received by the + * PIC block + * @ini_num_mwr_byte_sent: The number of PCI memory write bytes sent by the PIC + * block to the host + * @ini_num_cpl_byte_rcvd: The number of PCI read completion bytes received by + * the PIC block + * @wrcrdtarb_xoff: TBD + * @rdcrdtarb_xoff: TBD + * @vpath_genstats_count0: TBD + * @vpath_genstats_count1: TBD + * @vpath_genstats_count2: TBD + * @vpath_genstats_count3: TBD + * @vpath_genstats_count4: TBD + * @vpath_gennstats_count5: TBD + * @tx_stats: Transmit stats + * @rx_stats: Receive stats + * @prog_event_vnum1: Programmable statistic. Increments when internal logic + * detects a certain event. See register + * XMAC_STATS_CFG.EVENT_VNUM1_CFG for more information. + * @prog_event_vnum0: Programmable statistic. Increments when internal logic + * detects a certain event. See register + * XMAC_STATS_CFG.EVENT_VNUM0_CFG for more information. + * @prog_event_vnum3: Programmable statistic. Increments when internal logic + * detects a certain event. See register + * XMAC_STATS_CFG.EVENT_VNUM3_CFG for more information. + * @prog_event_vnum2: Programmable statistic. Increments when internal logic + * detects a certain event. See register + * XMAC_STATS_CFG.EVENT_VNUM2_CFG for more information. + * @rx_multi_cast_frame_discard: TBD + * @rx_frm_transferred: TBD + * @rxd_returned: TBD + * @rx_mpa_len_fail_frms: Count of received frames + * that fail the MPA length check + * @rx_mpa_mrk_fail_frms: Count of received frames + * that fail the MPA marker check + * @rx_mpa_crc_fail_frms: Count of received frames that fail the MPA CRC check + * @rx_permitted_frms: Count of frames that pass through the FAU and on to the + * frame buffer (and subsequently to the host). + * @rx_vp_reset_discarded_frms: Count of receive frames that are discarded + * because the VPATH is in reset + * @rx_wol_frms: Count of received "magic packet" frames. Stat increments + * whenever the received frame matches the VPATH's Wake-on-LAN + * signature(s) CRC. + * @tx_vp_reset_discarded_frms: Count of transmit frames that are discarded + * because the VPATH is in reset. Includes frames that are discarded + * because the current VPIN does not match that VPIN of the frame + * + * Titan vpath hardware statistics. + */ +struct vxge_hw_vpath_stats_hw_info { +/*0x000*/ u32 ini_num_mwr_sent; +/*0x004*/ u32 unused1; +/*0x008*/ u32 ini_num_mrd_sent; +/*0x00c*/ u32 unused2; +/*0x010*/ u32 ini_num_cpl_rcvd; +/*0x014*/ u32 unused3; +/*0x018*/ u64 ini_num_mwr_byte_sent; +/*0x020*/ u64 ini_num_cpl_byte_rcvd; +/*0x028*/ u32 wrcrdtarb_xoff; +/*0x02c*/ u32 unused4; +/*0x030*/ u32 rdcrdtarb_xoff; +/*0x034*/ u32 unused5; +/*0x038*/ u32 vpath_genstats_count0; +/*0x03c*/ u32 vpath_genstats_count1; +/*0x040*/ u32 vpath_genstats_count2; +/*0x044*/ u32 vpath_genstats_count3; +/*0x048*/ u32 vpath_genstats_count4; +/*0x04c*/ u32 unused6; +/*0x050*/ u32 vpath_genstats_count5; +/*0x054*/ u32 unused7; +/*0x058*/ struct vxge_hw_xmac_vpath_tx_stats tx_stats; +/*0x0e8*/ struct vxge_hw_xmac_vpath_rx_stats rx_stats; +/*0x220*/ u64 unused9; +/*0x228*/ u32 prog_event_vnum1; +/*0x22c*/ u32 prog_event_vnum0; +/*0x230*/ u32 prog_event_vnum3; +/*0x234*/ u32 prog_event_vnum2; +/*0x238*/ u16 rx_multi_cast_frame_discard; +/*0x23a*/ u8 unused10[6]; +/*0x240*/ u32 rx_frm_transferred; +/*0x244*/ u32 unused11; +/*0x248*/ u16 rxd_returned; +/*0x24a*/ u8 unused12[6]; +/*0x252*/ u16 rx_mpa_len_fail_frms; +/*0x254*/ u16 rx_mpa_mrk_fail_frms; +/*0x256*/ u16 rx_mpa_crc_fail_frms; +/*0x258*/ u16 rx_permitted_frms; +/*0x25c*/ u64 rx_vp_reset_discarded_frms; +/*0x25e*/ u64 rx_wol_frms; +/*0x260*/ u64 tx_vp_reset_discarded_frms; +} __packed; + + +/** + * struct vxge_hw_device_stats_mrpcim_info - Titan mrpcim hardware statistics. + * @pic.ini_rd_drop 0x0000 4 Number of DMA reads initiated + * by the adapter that were discarded because the VPATH is out of service + * @pic.ini_wr_drop 0x0004 4 Number of DMA writes initiated by the + * adapter that were discared because the VPATH is out of service + * @pic.wrcrdtarb_ph_crdt_depleted[vplane0] 0x0008 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane1] 0x0010 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane2] 0x0018 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane3] 0x0020 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane4] 0x0028 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane5] 0x0030 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane6] 0x0038 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane7] 0x0040 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane8] 0x0048 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane9] 0x0050 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane10] 0x0058 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane11] 0x0060 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane12] 0x0068 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane13] 0x0070 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane14] 0x0078 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane15] 0x0080 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_ph_crdt_depleted[vplane16] 0x0088 4 Number of times + * the posted header credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane0] 0x0090 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane1] 0x0098 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane2] 0x00a0 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane3] 0x00a8 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane4] 0x00b0 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane5] 0x00b8 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane6] 0x00c0 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane7] 0x00c8 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane8] 0x00d0 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane9] 0x00d8 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane10] 0x00e0 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane11] 0x00e8 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane12] 0x00f0 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane13] 0x00f8 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane14] 0x0100 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane15] 0x0108 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.wrcrdtarb_pd_crdt_depleted[vplane16] 0x0110 4 Number of times + * the posted data credits for upstream PCI writes were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane0] 0x0118 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane1] 0x0120 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane2] 0x0128 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane3] 0x0130 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane4] 0x0138 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane5] 0x0140 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane6] 0x0148 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane7] 0x0150 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane8] 0x0158 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane9] 0x0160 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane10] 0x0168 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane11] 0x0170 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane12] 0x0178 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane13] 0x0180 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane14] 0x0188 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane15] 0x0190 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.rdcrdtarb_nph_crdt_depleted[vplane16] 0x0198 4 Number of times + * the non-posted header credits for upstream PCI reads were depleted + * @pic.ini_rd_vpin_drop 0x01a0 4 Number of DMA reads initiated by + * the adapter that were discarded because the VPATH instance number does + * not match + * @pic.ini_wr_vpin_drop 0x01a4 4 Number of DMA writes initiated + * by the adapter that were discarded because the VPATH instance number + * does not match + * @pic.genstats_count0 0x01a8 4 Configurable statistic #1. Refer + * to the GENSTATS0_CFG for information on configuring this statistic + * @pic.genstats_count1 0x01ac 4 Configurable statistic #2. Refer + * to the GENSTATS1_CFG for information on configuring this statistic + * @pic.genstats_count2 0x01b0 4 Configurable statistic #3. Refer + * to the GENSTATS2_CFG for information on configuring this statistic + * @pic.genstats_count3 0x01b4 4 Configurable statistic #4. Refer + * to the GENSTATS3_CFG for information on configuring this statistic + * @pic.genstats_count4 0x01b8 4 Configurable statistic #5. Refer + * to the GENSTATS4_CFG for information on configuring this statistic + * @pic.genstats_count5 0x01c0 4 Configurable statistic #6. Refer + * to the GENSTATS5_CFG for information on configuring this statistic + * @pci.rstdrop_cpl 0x01c8 4 + * @pci.rstdrop_msg 0x01cc 4 + * @pci.rstdrop_client1 0x01d0 4 + * @pci.rstdrop_client0 0x01d4 4 + * @pci.rstdrop_client2 0x01d8 4 + * @pci.depl_cplh[vplane0] 0x01e2 2 Number of times completion + * header credits were depleted + * @pci.depl_nph[vplane0] 0x01e4 2 Number of times non posted + * header credits were depleted + * @pci.depl_ph[vplane0] 0x01e6 2 Number of times the posted + * header credits were depleted + * @pci.depl_cplh[vplane1] 0x01ea 2 + * @pci.depl_nph[vplane1] 0x01ec 2 + * @pci.depl_ph[vplane1] 0x01ee 2 + * @pci.depl_cplh[vplane2] 0x01f2 2 + * @pci.depl_nph[vplane2] 0x01f4 2 + * @pci.depl_ph[vplane2] 0x01f6 2 + * @pci.depl_cplh[vplane3] 0x01fa 2 + * @pci.depl_nph[vplane3] 0x01fc 2 + * @pci.depl_ph[vplane3] 0x01fe 2 + * @pci.depl_cplh[vplane4] 0x0202 2 + * @pci.depl_nph[vplane4] 0x0204 2 + * @pci.depl_ph[vplane4] 0x0206 2 + * @pci.depl_cplh[vplane5] 0x020a 2 + * @pci.depl_nph[vplane5] 0x020c 2 + * @pci.depl_ph[vplane5] 0x020e 2 + * @pci.depl_cplh[vplane6] 0x0212 2 + * @pci.depl_nph[vplane6] 0x0214 2 + * @pci.depl_ph[vplane6] 0x0216 2 + * @pci.depl_cplh[vplane7] 0x021a 2 + * @pci.depl_nph[vplane7] 0x021c 2 + * @pci.depl_ph[vplane7] 0x021e 2 + * @pci.depl_cplh[vplane8] 0x0222 2 + * @pci.depl_nph[vplane8] 0x0224 2 + * @pci.depl_ph[vplane8] 0x0226 2 + * @pci.depl_cplh[vplane9] 0x022a 2 + * @pci.depl_nph[vplane9] 0x022c 2 + * @pci.depl_ph[vplane9] 0x022e 2 + * @pci.depl_cplh[vplane10] 0x0232 2 + * @pci.depl_nph[vplane10] 0x0234 2 + * @pci.depl_ph[vplane10] 0x0236 2 + * @pci.depl_cplh[vplane11] 0x023a 2 + * @pci.depl_nph[vplane11] 0x023c 2 + * @pci.depl_ph[vplane11] 0x023e 2 + * @pci.depl_cplh[vplane12] 0x0242 2 + * @pci.depl_nph[vplane12] 0x0244 2 + * @pci.depl_ph[vplane12] 0x0246 2 + * @pci.depl_cplh[vplane13] 0x024a 2 + * @pci.depl_nph[vplane13] 0x024c 2 + * @pci.depl_ph[vplane13] 0x024e 2 + * @pci.depl_cplh[vplane14] 0x0252 2 + * @pci.depl_nph[vplane14] 0x0254 2 + * @pci.depl_ph[vplane14] 0x0256 2 + * @pci.depl_cplh[vplane15] 0x025a 2 + * @pci.depl_nph[vplane15] 0x025c 2 + * @pci.depl_ph[vplane15] 0x025e 2 + * @pci.depl_cplh[vplane16] 0x0262 2 + * @pci.depl_nph[vplane16] 0x0264 2 + * @pci.depl_ph[vplane16] 0x0266 2 + * @pci.depl_cpld[vplane0] 0x026a 2 Number of times completion data + * credits were depleted + * @pci.depl_npd[vplane0] 0x026c 2 Number of times non posted data + * credits were depleted + * @pci.depl_pd[vplane0] 0x026e 2 Number of times the posted data + * credits were depleted + * @pci.depl_cpld[vplane1] 0x0272 2 + * @pci.depl_npd[vplane1] 0x0274 2 + * @pci.depl_pd[vplane1] 0x0276 2 + * @pci.depl_cpld[vplane2] 0x027a 2 + * @pci.depl_npd[vplane2] 0x027c 2 + * @pci.depl_pd[vplane2] 0x027e 2 + * @pci.depl_cpld[vplane3] 0x0282 2 + * @pci.depl_npd[vplane3] 0x0284 2 + * @pci.depl_pd[vplane3] 0x0286 2 + * @pci.depl_cpld[vplane4] 0x028a 2 + * @pci.depl_npd[vplane4] 0x028c 2 + * @pci.depl_pd[vplane4] 0x028e 2 + * @pci.depl_cpld[vplane5] 0x0292 2 + * @pci.depl_npd[vplane5] 0x0294 2 + * @pci.depl_pd[vplane5] 0x0296 2 + * @pci.depl_cpld[vplane6] 0x029a 2 + * @pci.depl_npd[vplane6] 0x029c 2 + * @pci.depl_pd[vplane6] 0x029e 2 + * @pci.depl_cpld[vplane7] 0x02a2 2 + * @pci.depl_npd[vplane7] 0x02a4 2 + * @pci.depl_pd[vplane7] 0x02a6 2 + * @pci.depl_cpld[vplane8] 0x02aa 2 + * @pci.depl_npd[vplane8] 0x02ac 2 + * @pci.depl_pd[vplane8] 0x02ae 2 + * @pci.depl_cpld[vplane9] 0x02b2 2 + * @pci.depl_npd[vplane9] 0x02b4 2 + * @pci.depl_pd[vplane9] 0x02b6 2 + * @pci.depl_cpld[vplane10] 0x02ba 2 + * @pci.depl_npd[vplane10] 0x02bc 2 + * @pci.depl_pd[vplane10] 0x02be 2 + * @pci.depl_cpld[vplane11] 0x02c2 2 + * @pci.depl_npd[vplane11] 0x02c4 2 + * @pci.depl_pd[vplane11] 0x02c6 2 + * @pci.depl_cpld[vplane12] 0x02ca 2 + * @pci.depl_npd[vplane12] 0x02cc 2 + * @pci.depl_pd[vplane12] 0x02ce 2 + * @pci.depl_cpld[vplane13] 0x02d2 2 + * @pci.depl_npd[vplane13] 0x02d4 2 + * @pci.depl_pd[vplane13] 0x02d6 2 + * @pci.depl_cpld[vplane14] 0x02da 2 + * @pci.depl_npd[vplane14] 0x02dc 2 + * @pci.depl_pd[vplane14] 0x02de 2 + * @pci.depl_cpld[vplane15] 0x02e2 2 + * @pci.depl_npd[vplane15] 0x02e4 2 + * @pci.depl_pd[vplane15] 0x02e6 2 + * @pci.depl_cpld[vplane16] 0x02ea 2 + * @pci.depl_npd[vplane16] 0x02ec 2 + * @pci.depl_pd[vplane16] 0x02ee 2 + * @xgmac_port[3]; + * @xgmac_aggr[2]; + * @xgmac.global_prog_event_gnum0 0x0ae0 8 Programmable statistic. + * Increments when internal logic detects a certain event. See register + * XMAC_STATS_GLOBAL_CFG.EVENT_GNUM0_CFG for more information. + * @xgmac.global_prog_event_gnum1 0x0ae8 8 Programmable statistic. + * Increments when internal logic detects a certain event. See register + * XMAC_STATS_GLOBAL_CFG.EVENT_GNUM1_CFG for more information. + * @xgmac.orp_lro_events 0x0af8 8 + * @xgmac.orp_bs_events 0x0b00 8 + * @xgmac.orp_iwarp_events 0x0b08 8 + * @xgmac.tx_permitted_frms 0x0b14 4 + * @xgmac.port2_tx_any_frms 0x0b1d 1 + * @xgmac.port1_tx_any_frms 0x0b1e 1 + * @xgmac.port0_tx_any_frms 0x0b1f 1 + * @xgmac.port2_rx_any_frms 0x0b25 1 + * @xgmac.port1_rx_any_frms 0x0b26 1 + * @xgmac.port0_rx_any_frms 0x0b27 1 + * + * Titan mrpcim hardware statistics. + */ +struct vxge_hw_device_stats_mrpcim_info { +/*0x0000*/ u32 pic_ini_rd_drop; +/*0x0004*/ u32 pic_ini_wr_drop; +/*0x0008*/ struct { + /*0x0000*/ u32 pic_wrcrdtarb_ph_crdt_depleted; + /*0x0004*/ u32 unused1; + } pic_wrcrdtarb_ph_crdt_depleted_vplane[17]; +/*0x0090*/ struct { + /*0x0000*/ u32 pic_wrcrdtarb_pd_crdt_depleted; + /*0x0004*/ u32 unused2; + } pic_wrcrdtarb_pd_crdt_depleted_vplane[17]; +/*0x0118*/ struct { + /*0x0000*/ u32 pic_rdcrdtarb_nph_crdt_depleted; + /*0x0004*/ u32 unused3; + } pic_rdcrdtarb_nph_crdt_depleted_vplane[17]; +/*0x01a0*/ u32 pic_ini_rd_vpin_drop; +/*0x01a4*/ u32 pic_ini_wr_vpin_drop; +/*0x01a8*/ u32 pic_genstats_count0; +/*0x01ac*/ u32 pic_genstats_count1; +/*0x01b0*/ u32 pic_genstats_count2; +/*0x01b4*/ u32 pic_genstats_count3; +/*0x01b8*/ u32 pic_genstats_count4; +/*0x01bc*/ u32 unused4; +/*0x01c0*/ u32 pic_genstats_count5; +/*0x01c4*/ u32 unused5; +/*0x01c8*/ u32 pci_rstdrop_cpl; +/*0x01cc*/ u32 pci_rstdrop_msg; +/*0x01d0*/ u32 pci_rstdrop_client1; +/*0x01d4*/ u32 pci_rstdrop_client0; +/*0x01d8*/ u32 pci_rstdrop_client2; +/*0x01dc*/ u32 unused6; +/*0x01e0*/ struct { + /*0x0000*/ u16 unused7; + /*0x0002*/ u16 pci_depl_cplh; + /*0x0004*/ u16 pci_depl_nph; + /*0x0006*/ u16 pci_depl_ph; + } pci_depl_h_vplane[17]; +/*0x0268*/ struct { + /*0x0000*/ u16 unused8; + /*0x0002*/ u16 pci_depl_cpld; + /*0x0004*/ u16 pci_depl_npd; + /*0x0006*/ u16 pci_depl_pd; + } pci_depl_d_vplane[17]; +/*0x02f0*/ struct vxge_hw_xmac_port_stats xgmac_port[3]; +/*0x0a10*/ struct vxge_hw_xmac_aggr_stats xgmac_aggr[2]; +/*0x0ae0*/ u64 xgmac_global_prog_event_gnum0; +/*0x0ae8*/ u64 xgmac_global_prog_event_gnum1; +/*0x0af0*/ u64 unused7; +/*0x0af8*/ u64 unused8; +/*0x0b00*/ u64 unused9; +/*0x0b08*/ u64 unused10; +/*0x0b10*/ u32 unused11; +/*0x0b14*/ u32 xgmac_tx_permitted_frms; +/*0x0b18*/ u32 unused12; +/*0x0b1c*/ u8 unused13; +/*0x0b1d*/ u8 xgmac_port2_tx_any_frms; +/*0x0b1e*/ u8 xgmac_port1_tx_any_frms; +/*0x0b1f*/ u8 xgmac_port0_tx_any_frms; +/*0x0b20*/ u32 unused14; +/*0x0b24*/ u8 unused15; +/*0x0b25*/ u8 xgmac_port2_rx_any_frms; +/*0x0b26*/ u8 xgmac_port1_rx_any_frms; +/*0x0b27*/ u8 xgmac_port0_rx_any_frms; +} __packed; + +/** + * struct vxge_hw_device_stats_hw_info - Titan hardware statistics. + * @vpath_info: VPath statistics + * @vpath_info_sav: Vpath statistics saved + * + * Titan hardware statistics. + */ +struct vxge_hw_device_stats_hw_info { + struct vxge_hw_vpath_stats_hw_info + *vpath_info[VXGE_HW_MAX_VIRTUAL_PATHS]; + struct vxge_hw_vpath_stats_hw_info + vpath_info_sav[VXGE_HW_MAX_VIRTUAL_PATHS]; +}; + +/** + * struct vxge_hw_vpath_stats_sw_common_info - HW common + * statistics for queues. + * @full_cnt: Number of times the queue was full + * @usage_cnt: usage count. + * @usage_max: Maximum usage + * @reserve_free_swaps_cnt: Reserve/free swap counter. Internal usage. + * @total_compl_cnt: Total descriptor completion count. + * + * Hw queue counters + * See also: struct vxge_hw_vpath_stats_sw_fifo_info{}, + * struct vxge_hw_vpath_stats_sw_ring_info{}, + */ +struct vxge_hw_vpath_stats_sw_common_info { + u32 full_cnt; + u32 usage_cnt; + u32 usage_max; + u32 reserve_free_swaps_cnt; + u32 total_compl_cnt; +}; + +/** + * struct vxge_hw_vpath_stats_sw_fifo_info - HW fifo statistics + * @common_stats: Common counters for all queues + * @total_posts: Total number of postings on the queue. + * @total_buffers: Total number of buffers posted. + * @txd_t_code_err_cnt: Array of transmit transfer codes. The position + * (index) in this array reflects the transfer code type, for instance + * 0xA - "loss of link". + * Value txd_t_code_err_cnt[i] reflects the + * number of times the corresponding transfer code was encountered. + * + * HW fifo counters + * See also: struct vxge_hw_vpath_stats_sw_common_info{}, + * struct vxge_hw_vpath_stats_sw_ring_info{}, + */ +struct vxge_hw_vpath_stats_sw_fifo_info { + struct vxge_hw_vpath_stats_sw_common_info common_stats; + u32 total_posts; + u32 total_buffers; + u32 txd_t_code_err_cnt[VXGE_HW_DTR_MAX_T_CODE]; +}; + +/** + * struct vxge_hw_vpath_stats_sw_ring_info - HW ring statistics + * @common_stats: Common counters for all queues + * @rxd_t_code_err_cnt: Array of receive transfer codes. The position + * (index) in this array reflects the transfer code type, + * for instance + * 0x7 - for "invalid receive buffer size", or 0x8 - for ECC. + * Value rxd_t_code_err_cnt[i] reflects the + * number of times the corresponding transfer code was encountered. + * + * HW ring counters + * See also: struct vxge_hw_vpath_stats_sw_common_info{}, + * struct vxge_hw_vpath_stats_sw_fifo_info{}, + */ +struct vxge_hw_vpath_stats_sw_ring_info { + struct vxge_hw_vpath_stats_sw_common_info common_stats; + u32 rxd_t_code_err_cnt[VXGE_HW_DTR_MAX_T_CODE]; + +}; + +/** + * struct vxge_hw_vpath_stats_sw_err - HW vpath error statistics + * @unknown_alarms: + * @network_sustained_fault: + * @network_sustained_ok: + * @kdfcctl_fifo0_overwrite: + * @kdfcctl_fifo0_poison: + * @kdfcctl_fifo0_dma_error: + * @dblgen_fifo0_overflow: + * @statsb_pif_chain_error: + * @statsb_drop_timeout: + * @target_illegal_access: + * @ini_serr_det: + * @prc_ring_bumps: + * @prc_rxdcm_sc_err: + * @prc_rxdcm_sc_abort: + * @prc_quanta_size_err: + * + * HW vpath error statistics + */ +struct vxge_hw_vpath_stats_sw_err { + u32 unknown_alarms; + u32 network_sustained_fault; + u32 network_sustained_ok; + u32 kdfcctl_fifo0_overwrite; + u32 kdfcctl_fifo0_poison; + u32 kdfcctl_fifo0_dma_error; + u32 dblgen_fifo0_overflow; + u32 statsb_pif_chain_error; + u32 statsb_drop_timeout; + u32 target_illegal_access; + u32 ini_serr_det; + u32 prc_ring_bumps; + u32 prc_rxdcm_sc_err; + u32 prc_rxdcm_sc_abort; + u32 prc_quanta_size_err; +}; + +/** + * struct vxge_hw_vpath_stats_sw_info - HW vpath sw statistics + * @soft_reset_cnt: Number of times soft reset is done on this vpath. + * @error_stats: error counters for the vpath + * @ring_stats: counters for ring belonging to the vpath + * @fifo_stats: counters for fifo belonging to the vpath + * + * HW vpath sw statistics + * See also: struct vxge_hw_device_info{} }. + */ +struct vxge_hw_vpath_stats_sw_info { + u32 soft_reset_cnt; + struct vxge_hw_vpath_stats_sw_err error_stats; + struct vxge_hw_vpath_stats_sw_ring_info ring_stats; + struct vxge_hw_vpath_stats_sw_fifo_info fifo_stats; +}; + +/** + * struct vxge_hw_device_stats_sw_info - HW own per-device statistics. + * + * @not_traffic_intr_cnt: Number of times the host was interrupted + * without new completions. + * "Non-traffic interrupt counter". + * @traffic_intr_cnt: Number of traffic interrupts for the device. + * @total_intr_cnt: Total number of traffic interrupts for the device. + * @total_intr_cnt == @traffic_intr_cnt + + * @not_traffic_intr_cnt + * @soft_reset_cnt: Number of times soft reset is done on this device. + * @vpath_info: please see struct vxge_hw_vpath_stats_sw_info{} + * HW per-device statistics. + */ +struct vxge_hw_device_stats_sw_info { + u32 not_traffic_intr_cnt; + u32 traffic_intr_cnt; + u32 total_intr_cnt; + u32 soft_reset_cnt; + struct vxge_hw_vpath_stats_sw_info + vpath_info[VXGE_HW_MAX_VIRTUAL_PATHS]; +}; + +/** + * struct vxge_hw_device_stats_sw_err - HW device error statistics. + * @vpath_alarms: Number of vpath alarms + * + * HW Device error stats + */ +struct vxge_hw_device_stats_sw_err { + u32 vpath_alarms; +}; + +/** + * struct vxge_hw_device_stats - Contains HW per-device statistics, + * including hw. + * @devh: HW device handle. + * @dma_addr: DMA addres of the %hw_info. Given to device to fill-in the stats. + * @hw_info_dmah: DMA handle used to map hw statistics onto the device memory + * space. + * @hw_info_dma_acch: One more DMA handle used subsequently to free the + * DMA object. Note that this and the previous handle have + * physical meaning for Solaris; on Windows and Linux the + * corresponding value will be simply pointer to PCI device. + * + * @hw_dev_info_stats: Titan statistics maintained by the hardware. + * @sw_dev_info_stats: HW's "soft" device informational statistics, e.g. number + * of completions per interrupt. + * @sw_dev_err_stats: HW's "soft" device error statistics. + * + * Structure-container of HW per-device statistics. Note that per-channel + * statistics are kept in separate structures under HW's fifo and ring + * channels. + */ +struct vxge_hw_device_stats { + /* handles */ + struct __vxge_hw_device *devh; + + /* HW device hardware statistics */ + struct vxge_hw_device_stats_hw_info hw_dev_info_stats; + + /* HW device "soft" stats */ + struct vxge_hw_device_stats_sw_err sw_dev_err_stats; + struct vxge_hw_device_stats_sw_info sw_dev_info_stats; + +}; + +enum vxge_hw_status vxge_hw_device_hw_stats_enable( + struct __vxge_hw_device *devh); + +enum vxge_hw_status vxge_hw_device_stats_get( + struct __vxge_hw_device *devh, + struct vxge_hw_device_stats_hw_info *hw_stats); + +enum vxge_hw_status vxge_hw_driver_stats_get( + struct __vxge_hw_device *devh, + struct vxge_hw_device_stats_sw_info *sw_stats); + +enum vxge_hw_status vxge_hw_mrpcim_stats_enable(struct __vxge_hw_device *devh); + +enum vxge_hw_status vxge_hw_mrpcim_stats_disable(struct __vxge_hw_device *devh); + +enum vxge_hw_status +vxge_hw_mrpcim_stats_access( + struct __vxge_hw_device *devh, + u32 operation, + u32 location, + u32 offset, + u64 *stat); + +enum vxge_hw_status +vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *devh, u32 port, + struct vxge_hw_xmac_aggr_stats *aggr_stats); + +enum vxge_hw_status +vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *devh, u32 port, + struct vxge_hw_xmac_port_stats *port_stats); + +enum vxge_hw_status +vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *devh, + struct vxge_hw_xmac_stats *xmac_stats); + +/** + * enum enum vxge_hw_mgmt_reg_type - Register types. + * + * @vxge_hw_mgmt_reg_type_legacy: Legacy registers + * @vxge_hw_mgmt_reg_type_toc: TOC Registers + * @vxge_hw_mgmt_reg_type_common: Common Registers + * @vxge_hw_mgmt_reg_type_mrpcim: mrpcim registers + * @vxge_hw_mgmt_reg_type_srpcim: srpcim registers + * @vxge_hw_mgmt_reg_type_vpmgmt: vpath management registers + * @vxge_hw_mgmt_reg_type_vpath: vpath registers + * + * Register type enumaration + */ +enum vxge_hw_mgmt_reg_type { + vxge_hw_mgmt_reg_type_legacy = 0, + vxge_hw_mgmt_reg_type_toc = 1, + vxge_hw_mgmt_reg_type_common = 2, + vxge_hw_mgmt_reg_type_mrpcim = 3, + vxge_hw_mgmt_reg_type_srpcim = 4, + vxge_hw_mgmt_reg_type_vpmgmt = 5, + vxge_hw_mgmt_reg_type_vpath = 6 +}; + +enum vxge_hw_status +vxge_hw_mgmt_reg_read(struct __vxge_hw_device *devh, + enum vxge_hw_mgmt_reg_type type, + u32 index, + u32 offset, + u64 *value); + +enum vxge_hw_status +vxge_hw_mgmt_reg_write(struct __vxge_hw_device *devh, + enum vxge_hw_mgmt_reg_type type, + u32 index, + u32 offset, + u64 value); + +/** + * enum enum vxge_hw_rxd_state - Descriptor (RXD) state. + * @VXGE_HW_RXD_STATE_NONE: Invalid state. + * @VXGE_HW_RXD_STATE_AVAIL: Descriptor is available for reservation. + * @VXGE_HW_RXD_STATE_POSTED: Descriptor is posted for processing by the + * device. + * @VXGE_HW_RXD_STATE_FREED: Descriptor is free and can be reused for + * filling-in and posting later. + * + * Titan/HW descriptor states. + * + */ +enum vxge_hw_rxd_state { + VXGE_HW_RXD_STATE_NONE = 0, + VXGE_HW_RXD_STATE_AVAIL = 1, + VXGE_HW_RXD_STATE_POSTED = 2, + VXGE_HW_RXD_STATE_FREED = 3 +}; + +/** + * struct vxge_hw_ring_rxd_info - Extended information associated with a + * completed ring descriptor. + * @syn_flag: SYN flag + * @is_icmp: Is ICMP + * @fast_path_eligible: Fast Path Eligible flag + * @l3_cksum: in L3 checksum is valid + * @l3_cksum: Result of IP checksum check (by Titan hardware). + * This field containing VXGE_HW_L3_CKSUM_OK would mean that + * the checksum is correct, otherwise - the datagram is + * corrupted. + * @l4_cksum: in L4 checksum is valid + * @l4_cksum: Result of TCP/UDP checksum check (by Titan hardware). + * This field containing VXGE_HW_L4_CKSUM_OK would mean that + * the checksum is correct. Otherwise - the packet is + * corrupted. + * @frame: Zero or more of enum vxge_hw_frame_type flags. + * See enum vxge_hw_frame_type{}. + * @proto: zero or more of enum vxge_hw_frame_proto flags. Reporting bits for + * various higher-layer protocols, including (but note restricted to) + * TCP and UDP. See enum vxge_hw_frame_proto{}. + * @is_vlan: If vlan tag is valid + * @vlan: VLAN tag extracted from the received frame. + * @rth_bucket: RTH bucket + * @rth_it_hit: Set, If RTH hash value calculated by the Titan hardware + * has a matching entry in the Indirection table. + * @rth_spdm_hit: Set, If RTH hash value calculated by the Titan hardware + * has a matching entry in the Socket Pair Direct Match table. + * @rth_hash_type: RTH hash code of the function used to calculate the hash. + * @rth_value: Receive Traffic Hashing(RTH) hash value. Produced by Titan + * hardware if RTH is enabled. + */ +struct vxge_hw_ring_rxd_info { + u32 syn_flag; + u32 is_icmp; + u32 fast_path_eligible; + u32 l3_cksum_valid; + u32 l3_cksum; + u32 l4_cksum_valid; + u32 l4_cksum; + u32 frame; + u32 proto; + u32 is_vlan; + u32 vlan; + u32 rth_bucket; + u32 rth_it_hit; + u32 rth_spdm_hit; + u32 rth_hash_type; + u32 rth_value; +}; + +/** + * enum enum vxge_hw_ring_hash_type - RTH hash types + * @VXGE_HW_RING_HASH_TYPE_NONE: No Hash + * @VXGE_HW_RING_HASH_TYPE_TCP_IPV4: TCP IPv4 + * @VXGE_HW_RING_HASH_TYPE_UDP_IPV4: UDP IPv4 + * @VXGE_HW_RING_HASH_TYPE_IPV4: IPv4 + * @VXGE_HW_RING_HASH_TYPE_TCP_IPV6: TCP IPv6 + * @VXGE_HW_RING_HASH_TYPE_UDP_IPV6: UDP IPv6 + * @VXGE_HW_RING_HASH_TYPE_IPV6: IPv6 + * @VXGE_HW_RING_HASH_TYPE_TCP_IPV6_EX: TCP IPv6 extension + * @VXGE_HW_RING_HASH_TYPE_UDP_IPV6_EX: UDP IPv6 extension + * @VXGE_HW_RING_HASH_TYPE_IPV6_EX: IPv6 extension + * + * RTH hash types + */ +enum vxge_hw_ring_hash_type { + VXGE_HW_RING_HASH_TYPE_NONE = 0x0, + VXGE_HW_RING_HASH_TYPE_TCP_IPV4 = 0x1, + VXGE_HW_RING_HASH_TYPE_UDP_IPV4 = 0x2, + VXGE_HW_RING_HASH_TYPE_IPV4 = 0x3, + VXGE_HW_RING_HASH_TYPE_TCP_IPV6 = 0x4, + VXGE_HW_RING_HASH_TYPE_UDP_IPV6 = 0x5, + VXGE_HW_RING_HASH_TYPE_IPV6 = 0x6, + VXGE_HW_RING_HASH_TYPE_TCP_IPV6_EX = 0x7, + VXGE_HW_RING_HASH_TYPE_UDP_IPV6_EX = 0x8, + VXGE_HW_RING_HASH_TYPE_IPV6_EX = 0x9 +}; + +enum vxge_hw_status vxge_hw_ring_rxd_reserve( + struct __vxge_hw_ring *ring_handle, + void **rxdh); + +void +vxge_hw_ring_rxd_pre_post( + struct __vxge_hw_ring *ring_handle, + void *rxdh); + +void +vxge_hw_ring_rxd_post_post( + struct __vxge_hw_ring *ring_handle, + void *rxdh); + +enum vxge_hw_status +vxge_hw_ring_replenish(struct __vxge_hw_ring *ring_handle, u16 min_flag); + +void +vxge_hw_ring_rxd_post_post_wmb( + struct __vxge_hw_ring *ring_handle, + void *rxdh); + +void vxge_hw_ring_rxd_post( + struct __vxge_hw_ring *ring_handle, + void *rxdh); + +enum vxge_hw_status vxge_hw_ring_rxd_next_completed( + struct __vxge_hw_ring *ring_handle, + void **rxdh, + u8 *t_code); + +enum vxge_hw_status vxge_hw_ring_handle_tcode( + struct __vxge_hw_ring *ring_handle, + void *rxdh, + u8 t_code); + +void vxge_hw_ring_rxd_free( + struct __vxge_hw_ring *ring_handle, + void *rxdh); + +/** + * enum enum vxge_hw_frame_proto - Higher-layer ethernet protocols. + * @VXGE_HW_FRAME_PROTO_VLAN_TAGGED: VLAN. + * @VXGE_HW_FRAME_PROTO_IPV4: IPv4. + * @VXGE_HW_FRAME_PROTO_IPV6: IPv6. + * @VXGE_HW_FRAME_PROTO_IP_FRAG: IP fragmented. + * @VXGE_HW_FRAME_PROTO_TCP: TCP. + * @VXGE_HW_FRAME_PROTO_UDP: UDP. + * @VXGE_HW_FRAME_PROTO_TCP_OR_UDP: TCP or UDP. + * + * Higher layer ethernet protocols and options. + */ +enum vxge_hw_frame_proto { + VXGE_HW_FRAME_PROTO_VLAN_TAGGED = 0x80, + VXGE_HW_FRAME_PROTO_IPV4 = 0x10, + VXGE_HW_FRAME_PROTO_IPV6 = 0x08, + VXGE_HW_FRAME_PROTO_IP_FRAG = 0x04, + VXGE_HW_FRAME_PROTO_TCP = 0x02, + VXGE_HW_FRAME_PROTO_UDP = 0x01, + VXGE_HW_FRAME_PROTO_TCP_OR_UDP = (VXGE_HW_FRAME_PROTO_TCP | \ + VXGE_HW_FRAME_PROTO_UDP) +}; + +/** + * enum enum vxge_hw_fifo_gather_code - Gather codes used in fifo TxD + * @VXGE_HW_FIFO_GATHER_CODE_FIRST: First TxDL + * @VXGE_HW_FIFO_GATHER_CODE_MIDDLE: Middle TxDL + * @VXGE_HW_FIFO_GATHER_CODE_LAST: Last TxDL + * @VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST: First and Last TxDL. + * + * These gather codes are used to indicate the position of a TxD in a TxD list + */ +enum vxge_hw_fifo_gather_code { + VXGE_HW_FIFO_GATHER_CODE_FIRST = 0x2, + VXGE_HW_FIFO_GATHER_CODE_MIDDLE = 0x0, + VXGE_HW_FIFO_GATHER_CODE_LAST = 0x1, + VXGE_HW_FIFO_GATHER_CODE_FIRST_LAST = 0x3 +}; + +/** + * enum enum vxge_hw_fifo_tcode - tcodes used in fifo + * @VXGE_HW_FIFO_T_CODE_OK: Transfer OK + * @VXGE_HW_FIFO_T_CODE_PCI_READ_CORRUPT: PCI read transaction (either TxD or + * frame data) returned with corrupt data. + * @VXGE_HW_FIFO_T_CODE_PCI_READ_FAIL:PCI read transaction was returned + * with no data. + * @VXGE_HW_FIFO_T_CODE_INVALID_MSS: The host attempted to send either a + * frame or LSO MSS that was too long (>9800B). + * @VXGE_HW_FIFO_T_CODE_LSO_ERROR: Error detected during TCP/UDP Large Send + * Offload operation, due to improper header template, + * unsupported protocol, etc. + * @VXGE_HW_FIFO_T_CODE_UNUSED: Unused + * @VXGE_HW_FIFO_T_CODE_MULTI_ERROR: Set to 1 by the adapter if multiple + * data buffer transfer errors are encountered (see below). + * Otherwise it is set to 0. + * + * These tcodes are returned in various API for TxD status + */ +enum vxge_hw_fifo_tcode { + VXGE_HW_FIFO_T_CODE_OK = 0x0, + VXGE_HW_FIFO_T_CODE_PCI_READ_CORRUPT = 0x1, + VXGE_HW_FIFO_T_CODE_PCI_READ_FAIL = 0x2, + VXGE_HW_FIFO_T_CODE_INVALID_MSS = 0x3, + VXGE_HW_FIFO_T_CODE_LSO_ERROR = 0x4, + VXGE_HW_FIFO_T_CODE_UNUSED = 0x7, + VXGE_HW_FIFO_T_CODE_MULTI_ERROR = 0x8 +}; + +enum vxge_hw_status vxge_hw_fifo_txdl_reserve( + struct __vxge_hw_fifo *fifoh, + void **txdlh, + void **txdl_priv); + +void vxge_hw_fifo_txdl_buffer_set( + struct __vxge_hw_fifo *fifo_handle, + void *txdlh, + u32 frag_idx, + dma_addr_t dma_pointer, + u32 size); + +void vxge_hw_fifo_txdl_post( + struct __vxge_hw_fifo *fifo_handle, + void *txdlh); + +u32 vxge_hw_fifo_free_txdl_count_get( + struct __vxge_hw_fifo *fifo_handle); + +enum vxge_hw_status vxge_hw_fifo_txdl_next_completed( + struct __vxge_hw_fifo *fifoh, + void **txdlh, + enum vxge_hw_fifo_tcode *t_code); + +enum vxge_hw_status vxge_hw_fifo_handle_tcode( + struct __vxge_hw_fifo *fifoh, + void *txdlh, + enum vxge_hw_fifo_tcode t_code); + +void vxge_hw_fifo_txdl_free( + struct __vxge_hw_fifo *fifoh, + void *txdlh); + +/* + * Device + */ + +#define VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET (VXGE_HW_BLOCK_SIZE-8) +#define VXGE_HW_RING_MEMBLOCK_IDX_OFFSET (VXGE_HW_BLOCK_SIZE-16) +#define VXGE_HW_RING_MIN_BUFF_ALLOCATION 64 + +/* + * struct __vxge_hw_ring_rxd_priv - Receive descriptor HW-private data. + * @dma_addr: DMA (mapped) address of _this_ descriptor. + * @dma_handle: DMA handle used to map the descriptor onto device. + * @dma_offset: Descriptor's offset in the memory block. HW allocates + * descriptors in memory blocks of %VXGE_HW_BLOCK_SIZE + * bytes. Each memblock is contiguous DMA-able memory. Each + * memblock contains 1 or more 4KB RxD blocks visible to the + * Titan hardware. + * @dma_object: DMA address and handle of the memory block that contains + * the descriptor. This member is used only in the "checked" + * version of the HW (to enforce certain assertions); + * otherwise it gets compiled out. + * @allocated: True if the descriptor is reserved, 0 otherwise. Internal usage. + * + * Per-receive decsriptor HW-private data. HW uses the space to keep DMA + * information associated with the descriptor. Note that driver can ask HW + * to allocate additional per-descriptor space for its own (driver-specific) + * purposes. + */ +struct __vxge_hw_ring_rxd_priv { + dma_addr_t dma_addr; + struct pci_dev *dma_handle; + ptrdiff_t dma_offset; +#ifdef VXGE_DEBUG_ASSERT + struct vxge_hw_mempool_dma *dma_object; +#endif +}; + +/* ========================= RING PRIVATE API ============================= */ +u64 +__vxge_hw_ring_first_block_address_get( + struct __vxge_hw_ring *ringh); + +enum vxge_hw_status +__vxge_hw_ring_create( + struct __vxge_hw_vpath_handle *vpath_handle, + struct vxge_hw_ring_attr *attr); + +enum vxge_hw_status +__vxge_hw_ring_abort( + struct __vxge_hw_ring *ringh); + +enum vxge_hw_status +__vxge_hw_ring_reset( + struct __vxge_hw_ring *ringh); + +enum vxge_hw_status +__vxge_hw_ring_delete( + struct __vxge_hw_vpath_handle *vpath_handle); + +/* ========================= FIFO PRIVATE API ============================= */ + +struct vxge_hw_fifo_attr; + +enum vxge_hw_status +__vxge_hw_fifo_create( + struct __vxge_hw_vpath_handle *vpath_handle, + struct vxge_hw_fifo_attr *attr); + +enum vxge_hw_status +__vxge_hw_fifo_abort( + struct __vxge_hw_fifo *fifoh); + +enum vxge_hw_status +__vxge_hw_fifo_reset( + struct __vxge_hw_fifo *ringh); + +enum vxge_hw_status +__vxge_hw_fifo_delete( + struct __vxge_hw_vpath_handle *vpath_handle); + +struct vxge_hw_mempool_cbs { + void (*item_func_alloc)( + struct vxge_hw_mempool *mempoolh, + u32 memblock_index, + struct vxge_hw_mempool_dma *dma_object, + u32 index, + u32 is_last); +}; + +void +__vxge_hw_mempool_destroy( + struct vxge_hw_mempool *mempool); + +#define VXGE_HW_VIRTUAL_PATH_HANDLE(vpath) \ + ((struct __vxge_hw_vpath_handle *)(vpath)->vpath_handles.next) + +enum vxge_hw_status +__vxge_hw_vpath_rts_table_get( + struct __vxge_hw_vpath_handle *vpath_handle, + u32 action, + u32 rts_table, + u32 offset, + u64 *data1, + u64 *data2); + +enum vxge_hw_status +__vxge_hw_vpath_rts_table_set( + struct __vxge_hw_vpath_handle *vpath_handle, + u32 action, + u32 rts_table, + u32 offset, + u64 data1, + u64 data2); + +enum vxge_hw_status +__vxge_hw_vpath_reset( + struct __vxge_hw_device *devh, + u32 vp_id); + +enum vxge_hw_status +__vxge_hw_vpath_sw_reset( + struct __vxge_hw_device *devh, + u32 vp_id); + +enum vxge_hw_status +__vxge_hw_vpath_enable( + struct __vxge_hw_device *devh, + u32 vp_id); + +void +__vxge_hw_vpath_prc_configure( + struct __vxge_hw_device *devh, + u32 vp_id); + +enum vxge_hw_status +__vxge_hw_vpath_kdfc_configure( + struct __vxge_hw_device *devh, + u32 vp_id); + +enum vxge_hw_status +__vxge_hw_vpath_mac_configure( + struct __vxge_hw_device *devh, + u32 vp_id); + +enum vxge_hw_status +__vxge_hw_vpath_tim_configure( + struct __vxge_hw_device *devh, + u32 vp_id); + +enum vxge_hw_status +__vxge_hw_vpath_initialize( + struct __vxge_hw_device *devh, + u32 vp_id); + +enum vxge_hw_status +__vxge_hw_vp_initialize( + struct __vxge_hw_device *devh, + u32 vp_id, + struct vxge_hw_vp_config *config); + +void +__vxge_hw_vp_terminate( + struct __vxge_hw_device *devh, + u32 vp_id); + +enum vxge_hw_status +__vxge_hw_vpath_alarm_process( + struct __vxge_hw_virtualpath *vpath, + u32 skip_alarms); + +void vxge_hw_device_intr_enable( + struct __vxge_hw_device *devh); + +u32 vxge_hw_device_set_intr_type(struct __vxge_hw_device *devh, u32 intr_mode); + +void vxge_hw_device_intr_disable( + struct __vxge_hw_device *devh); + +void vxge_hw_device_mask_all( + struct __vxge_hw_device *devh); + +void vxge_hw_device_unmask_all( + struct __vxge_hw_device *devh); + +enum vxge_hw_status vxge_hw_device_begin_irq( + struct __vxge_hw_device *devh, + u32 skip_alarms, + u64 *reason); + +void vxge_hw_device_clear_tx_rx( + struct __vxge_hw_device *devh); + +/* + * Virtual Paths + */ + +u32 vxge_hw_vpath_id( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_vpath_mac_addr_add_mode { + VXGE_HW_VPATH_MAC_ADDR_ADD_DUPLICATE = 0, + VXGE_HW_VPATH_MAC_ADDR_DISCARD_DUPLICATE = 1, + VXGE_HW_VPATH_MAC_ADDR_REPLACE_DUPLICATE = 2 +}; + +enum vxge_hw_status +vxge_hw_vpath_mac_addr_add( + struct __vxge_hw_vpath_handle *vpath_handle, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN], + enum vxge_hw_vpath_mac_addr_add_mode duplicate_mode); + +enum vxge_hw_status +vxge_hw_vpath_mac_addr_get( + struct __vxge_hw_vpath_handle *vpath_handle, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN]); + +enum vxge_hw_status +vxge_hw_vpath_mac_addr_get_next( + struct __vxge_hw_vpath_handle *vpath_handle, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN]); + +enum vxge_hw_status +vxge_hw_vpath_mac_addr_delete( + struct __vxge_hw_vpath_handle *vpath_handle, + u8 (macaddr)[ETH_ALEN], + u8 (macaddr_mask)[ETH_ALEN]); + +enum vxge_hw_status +vxge_hw_vpath_vid_add( + struct __vxge_hw_vpath_handle *vpath_handle, + u64 vid); + +enum vxge_hw_status +vxge_hw_vpath_vid_get( + struct __vxge_hw_vpath_handle *vpath_handle, + u64 *vid); + +enum vxge_hw_status +vxge_hw_vpath_vid_get_next( + struct __vxge_hw_vpath_handle *vpath_handle, + u64 *vid); + +enum vxge_hw_status +vxge_hw_vpath_vid_delete( + struct __vxge_hw_vpath_handle *vpath_handle, + u64 vid); + +enum vxge_hw_status +vxge_hw_vpath_etype_add( + struct __vxge_hw_vpath_handle *vpath_handle, + u64 etype); + +enum vxge_hw_status +vxge_hw_vpath_etype_get( + struct __vxge_hw_vpath_handle *vpath_handle, + u64 *etype); + +enum vxge_hw_status +vxge_hw_vpath_etype_get_next( + struct __vxge_hw_vpath_handle *vpath_handle, + u64 *etype); + +enum vxge_hw_status +vxge_hw_vpath_etype_delete( + struct __vxge_hw_vpath_handle *vpath_handle, + u64 etype); + +enum vxge_hw_status vxge_hw_vpath_promisc_enable( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status vxge_hw_vpath_promisc_disable( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status vxge_hw_vpath_bcast_enable( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status vxge_hw_vpath_mcast_enable( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status vxge_hw_vpath_mcast_disable( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status vxge_hw_vpath_poll_rx( + struct __vxge_hw_ring *ringh); + +enum vxge_hw_status vxge_hw_vpath_poll_tx( + struct __vxge_hw_fifo *fifoh, + void **skb_ptr); + +enum vxge_hw_status vxge_hw_vpath_alarm_process( + struct __vxge_hw_vpath_handle *vpath_handle, + u32 skip_alarms); + +enum vxge_hw_status +vxge_hw_vpath_msix_set(struct __vxge_hw_vpath_handle *vpath_handle, + int *tim_msix_id, int alarm_msix_id); + +void +vxge_hw_vpath_msix_mask(struct __vxge_hw_vpath_handle *vpath_handle, + int msix_id); + +void vxge_hw_device_flush_io(struct __vxge_hw_device *devh); + +void +vxge_hw_vpath_msix_clear(struct __vxge_hw_vpath_handle *vpath_handle, + int msix_id); + +void +vxge_hw_vpath_msix_unmask(struct __vxge_hw_vpath_handle *vpath_handle, + int msix_id); + +void +vxge_hw_vpath_msix_mask_all(struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status vxge_hw_vpath_intr_enable( + struct __vxge_hw_vpath_handle *vpath_handle); + +enum vxge_hw_status vxge_hw_vpath_intr_disable( + struct __vxge_hw_vpath_handle *vpath_handle); + +void vxge_hw_vpath_inta_mask_tx_rx( + struct __vxge_hw_vpath_handle *vpath_handle); + +void vxge_hw_vpath_inta_unmask_tx_rx( + struct __vxge_hw_vpath_handle *vpath_handle); + +void +vxge_hw_channel_msix_mask(struct __vxge_hw_channel *channelh, int msix_id); + +void +vxge_hw_channel_msix_unmask(struct __vxge_hw_channel *channelh, int msix_id); + +enum vxge_hw_status +vxge_hw_channel_dtr_alloc(struct __vxge_hw_channel *channel, void **dtrh); + +void +vxge_hw_channel_dtr_post(struct __vxge_hw_channel *channel, void *dtrh); + +void +vxge_hw_channel_dtr_try_complete(struct __vxge_hw_channel *channel, + void **dtrh); + +void +vxge_hw_channel_dtr_complete(struct __vxge_hw_channel *channel); + +void +vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh); + +int +vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel); + +/* ========================== PRIVATE API ================================= */ + +enum vxge_hw_status +__vxge_hw_device_handle_link_up_ind(struct __vxge_hw_device *hldev); + +enum vxge_hw_status +__vxge_hw_device_handle_link_down_ind(struct __vxge_hw_device *hldev); + +enum vxge_hw_status +__vxge_hw_device_handle_error( + struct __vxge_hw_device *hldev, + u32 vp_id, + enum vxge_hw_event type); + +#endif diff --git a/trunk/drivers/net/vxge/vxge-version.h b/trunk/drivers/net/vxge/vxge-version.h new file mode 100644 index 000000000000..7da02c545ed5 --- /dev/null +++ b/trunk/drivers/net/vxge/vxge-version.h @@ -0,0 +1,23 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-version.h: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#ifndef VXGE_VERSION_H + +#define VXGE_VERSION_H + +#define VXGE_VERSION_MAJOR "2" +#define VXGE_VERSION_MINOR "0" +#define VXGE_VERSION_FIX "1" +#define VXGE_VERSION_BUILD "17129" +#define VXGE_VERSION_FOR "k" +#endif diff --git a/trunk/drivers/of/base.c b/trunk/drivers/of/base.c index cd17092b82bd..41c5dfd85358 100644 --- a/trunk/drivers/of/base.c +++ b/trunk/drivers/of/base.c @@ -446,6 +446,7 @@ struct of_modalias_table { }; static struct of_modalias_table of_modalias_table[] = { { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" }, + { "mmc-spi-slot", "mmc_spi" }, }; /** diff --git a/trunk/drivers/parisc/asp.c b/trunk/drivers/parisc/asp.c index 7931133526c4..9ca21098b146 100644 --- a/trunk/drivers/parisc/asp.c +++ b/trunk/drivers/parisc/asp.c @@ -81,7 +81,7 @@ static int __init asp_init_chip(struct parisc_device *dev) asp.hpa = ASP_INTERRUPT_ADDR; printk(KERN_INFO "%s version %d at 0x%lx found.\n", - asp.name, asp.version, dev->hpa.start); + asp.name, asp.version, (unsigned long)dev->hpa.start); /* the IRQ ASP should use */ ret = -EBUSY; diff --git a/trunk/drivers/parisc/ccio-dma.c b/trunk/drivers/parisc/ccio-dma.c index cd4dd7ed2c06..5d610cbcfe80 100644 --- a/trunk/drivers/parisc/ccio-dma.c +++ b/trunk/drivers/parisc/ccio-dma.c @@ -406,8 +406,6 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) } ioc->avg_search[ioc->avg_idx++] = cr_start; ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1; -#endif -#ifdef CCIO_COLLECT_STATS ioc->used_pages += pages_needed; #endif /* @@ -453,10 +451,10 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) unsigned long mask = ~(~0UL >> pages_mapped); CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8); #else - CCIO_FREE_MAPPINGS(ioc, res_idx, 0xff, 8); + CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffUL, 8); #endif } else if(pages_mapped <= 16) { - CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffff, 16); + CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffffUL, 16); } else if(pages_mapped <= 32) { CCIO_FREE_MAPPINGS(ioc, res_idx, ~(unsigned int)0, 32); #ifdef __LP64__ @@ -1028,8 +1026,10 @@ static int ccio_proc_info(struct seq_file *m, void *p) while (ioc != NULL) { unsigned int total_pages = ioc->res_size << 3; +#ifdef CCIO_COLLECT_STATS unsigned long avg = 0, min, max; int j; +#endif len += seq_printf(m, "%s\n", ioc->name); @@ -1060,8 +1060,7 @@ static int ccio_proc_info(struct seq_file *m, void *p) avg /= CCIO_SEARCH_SAMPLE; len += seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", min, avg, max); -#endif -#ifdef CCIO_COLLECT_STATS + len += seq_printf(m, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", ioc->msingle_calls, ioc->msingle_pages, (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls)); @@ -1400,7 +1399,7 @@ ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr) result = insert_resource(&iomem_resource, res); if (result < 0) { printk(KERN_ERR "%s() failed to claim CCIO bus address space (%08lx,%08lx)\n", - __func__, res->start, res->end); + __func__, (unsigned long)res->start, (unsigned long)res->end); } } @@ -1551,7 +1550,8 @@ static int __init ccio_probe(struct parisc_device *dev) ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn"; - printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, dev->hpa.start); + printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, + (unsigned long)dev->hpa.start); for (i = 0; i < ioc_count; i++) { ioc_p = &(*ioc_p)->next; diff --git a/trunk/drivers/parisc/dino.c b/trunk/drivers/parisc/dino.c index bb5a1c9597cb..52ae0b1d470c 100644 --- a/trunk/drivers/parisc/dino.c +++ b/trunk/drivers/parisc/dino.c @@ -819,7 +819,9 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name) result = ccio_request_resource(dino_dev->hba.dev, &res[i]); if (result < 0) { - printk(KERN_ERR "%s: failed to claim PCI Bus address space %d (0x%lx-0x%lx)!\n", name, i, res[i].start, res[i].end); + printk(KERN_ERR "%s: failed to claim PCI Bus address " + "space %d (0x%lx-0x%lx)!\n", name, i, + (unsigned long)res[i].start, (unsigned long)res[i].end); return result; } } @@ -899,7 +901,8 @@ static int __init dino_common_init(struct parisc_device *dev, if (request_resource(&ioport_resource, res) < 0) { printk(KERN_ERR "%s: request I/O Port region failed " "0x%lx/%lx (hpa 0x%p)\n", - name, res->start, res->end, dino_dev->hba.base_addr); + name, (unsigned long)res->start, (unsigned long)res->end, + dino_dev->hba.base_addr); return 1; } diff --git a/trunk/drivers/parisc/eisa.c b/trunk/drivers/parisc/eisa.c index 7891db50c483..f415fdd9a885 100644 --- a/trunk/drivers/parisc/eisa.c +++ b/trunk/drivers/parisc/eisa.c @@ -314,7 +314,7 @@ static int __init eisa_probe(struct parisc_device *dev) char *name = is_mongoose(dev) ? "Mongoose" : "Wax"; printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n", - name, dev->hpa.start); + name, (unsigned long)dev->hpa.start); eisa_dev.hba.dev = dev; eisa_dev.hba.iommu = ccio_get_iommu(dev); diff --git a/trunk/drivers/parisc/eisa_enumerator.c b/trunk/drivers/parisc/eisa_enumerator.c index 6d8aae003f6c..c709ecc2b7f7 100644 --- a/trunk/drivers/parisc/eisa_enumerator.c +++ b/trunk/drivers/parisc/eisa_enumerator.c @@ -98,7 +98,7 @@ static int configure_memory(const unsigned char *buf, res->start = mem_parent->start + get_24(buf+len+2); res->end = res->start + get_16(buf+len+5)*1024; res->flags = IORESOURCE_MEM; - printk("memory %lx-%lx ", res->start, res->end); + printk("memory %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end); result = request_resource(mem_parent, res); if (result < 0) { printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n"); @@ -188,7 +188,7 @@ static int configure_port(const unsigned char *buf, struct resource *io_parent, res->start = get_16(buf+len+1); res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1; res->flags = IORESOURCE_IO; - printk("ioports %lx-%lx ", res->start, res->end); + printk("ioports %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end); result = request_resource(io_parent, res); if (result < 0) { printk("\n" KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n"); diff --git a/trunk/drivers/parisc/iosapic.c b/trunk/drivers/parisc/iosapic.c index 501aaf1f253f..73348c4047e9 100644 --- a/trunk/drivers/parisc/iosapic.c +++ b/trunk/drivers/parisc/iosapic.c @@ -714,7 +714,7 @@ static void iosapic_set_affinity_irq(unsigned int irq, if (dest_cpu < 0) return; - irq_desc[irq].affinity = cpumask_of_cpu(dest_cpu); + cpumask_copy(irq_desc[irq].affinity, cpumask_of(dest_cpu)); vi->txn_addr = txn_affinity_addr(irq, dest_cpu); spin_lock_irqsave(&iosapic_lock, flags); diff --git a/trunk/drivers/parisc/led.c b/trunk/drivers/parisc/led.c index 454b6532e409..9581d3619450 100644 --- a/trunk/drivers/parisc/led.c +++ b/trunk/drivers/parisc/led.c @@ -3,7 +3,7 @@ * * (c) Copyright 2000 Red Hat Software * (c) Copyright 2000 Helge Deller - * (c) Copyright 2001-2005 Helge Deller + * (c) Copyright 2001-2009 Helge Deller * (c) Copyright 2001 Randolph Chung * * This program is free software; you can redistribute it and/or modify @@ -243,13 +243,11 @@ static int __init led_create_procfs(void) proc_pdc_root = proc_mkdir("pdc", 0); if (!proc_pdc_root) return -1; - proc_pdc_root->owner = THIS_MODULE; ent = create_proc_entry("led", S_IFREG|S_IRUGO|S_IWUSR, proc_pdc_root); if (!ent) return -1; ent->data = (void *)LED_NOLCD; /* LED */ ent->read_proc = led_proc_read; ent->write_proc = led_proc_write; - ent->owner = THIS_MODULE; if (led_type == LED_HASLCD) { @@ -258,7 +256,6 @@ static int __init led_create_procfs(void) ent->data = (void *)LED_HASLCD; /* LCD */ ent->read_proc = led_proc_read; ent->write_proc = led_proc_write; - ent->owner = THIS_MODULE; } return 0; @@ -463,9 +460,20 @@ static void led_work_func (struct work_struct *unused) if (likely(led_lanrxtx)) currentleds |= led_get_net_activity(); if (likely(led_diskio)) currentleds |= led_get_diskio_activity(); - /* blink all LEDs twice a second if we got an Oops (HPMC) */ - if (unlikely(oops_in_progress)) - currentleds = (count_HZ<=(HZ/2)) ? 0 : 0xff; + /* blink LEDs if we got an Oops (HPMC) */ + if (unlikely(oops_in_progress)) { + if (boot_cpu_data.cpu_type >= pcxl2) { + /* newer machines don't have loadavg. LEDs, so we + * let all LEDs blink twice per second instead */ + currentleds = (count_HZ <= (HZ/2)) ? 0 : 0xff; + } else { + /* old machines: blink loadavg. LEDs twice per second */ + if (count_HZ <= (HZ/2)) + currentleds &= ~(LED4|LED5|LED6|LED7); + else + currentleds |= (LED4|LED5|LED6|LED7); + } + } if (currentleds != lastleds) { @@ -511,7 +519,7 @@ static int led_halt(struct notifier_block *nb, unsigned long event, void *buf) /* Cancel the work item and delete the queue */ if (led_wq) { - cancel_rearming_delayed_workqueue(led_wq, &led_task); + cancel_delayed_work_sync(&led_task); destroy_workqueue(led_wq); led_wq = NULL; } @@ -630,7 +638,7 @@ int lcd_print( const char *str ) /* temporarily disable the led work task */ if (led_wq) - cancel_rearming_delayed_workqueue(led_wq, &led_task); + cancel_delayed_work_sync(&led_task); /* copy display string to buffer for procfs */ strlcpy(lcd_text, str, sizeof(lcd_text)); diff --git a/trunk/drivers/parport/parport_serial.c b/trunk/drivers/parport/parport_serial.c index 032db815b0f9..f3492110b1ad 100644 --- a/trunk/drivers/parport/parport_serial.c +++ b/trunk/drivers/parport/parport_serial.c @@ -30,6 +30,7 @@ enum parport_pc_pci_cards { titan_210l, netmos_9xx5_combo, netmos_9855, + netmos_9855_2p, avlab_1s1p, avlab_1s2p, avlab_2s1p, @@ -62,7 +63,7 @@ struct parport_pc_pci { struct parport_pc_pci *card, int failed); }; -static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *card, int autoirq, int autodma) +static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc_pci *par, int autoirq, int autodma) { /* the rule described below doesn't hold for this device */ if (dev->device == PCI_DEVICE_ID_NETMOS_9835 && @@ -74,9 +75,17 @@ static int __devinit netmos_parallel_init(struct pci_dev *dev, struct parport_pc * and serial ports. The form is 0x00PS, where

is the number of * parallel ports and is the number of serial ports. */ - card->numports = (dev->subsystem_device & 0xf0) >> 4; - if (card->numports > ARRAY_SIZE(card->addr)) - card->numports = ARRAY_SIZE(card->addr); + par->numports = (dev->subsystem_device & 0xf0) >> 4; + if (par->numports > ARRAY_SIZE(par->addr)) + par->numports = ARRAY_SIZE(par->addr); + /* + * This function is currently only called for cards with up to + * one parallel port. + * Parallel port BAR is either before or after serial ports BARS; + * hence, lo should be either 0 or equal to the number of serial ports. + */ + if (par->addr[0].lo != 0) + par->addr[0].lo = dev->subsystem_device & 0xf; return 0; } @@ -84,7 +93,8 @@ static struct parport_pc_pci cards[] __devinitdata = { /* titan_110l */ { 1, { { 3, -1 }, } }, /* titan_210l */ { 1, { { 3, -1 }, } }, /* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init }, - /* netmos_9855 */ { 1, { { 2, -1 }, }, netmos_parallel_init }, + /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init }, + /* netmos_9855_2p */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* avlab_1s1p */ { 1, { { 1, 2}, } }, /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} }, /* avlab_2s1p */ { 1, { { 2, 3}, } }, @@ -109,6 +119,10 @@ static struct pci_device_id parport_serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, + 0x1000, 0x0020, 0, 0, netmos_9855_2p }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, + 0x1000, 0x0022, 0, 0, netmos_9855_2p }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9855 }, /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ @@ -192,6 +206,12 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { .uart_offset = 8, }, [netmos_9855] = { + .flags = FL_BASE2 | FL_BASE_BARS, + .num_ports = 1, + .base_baud = 115200, + .uart_offset = 8, + }, + [netmos_9855_2p] = { .flags = FL_BASE4 | FL_BASE_BARS, .num_ports = 1, .base_baud = 115200, diff --git a/trunk/drivers/pci/Kconfig b/trunk/drivers/pci/Kconfig index 2a4501dd2515..fdc864f9cf23 100644 --- a/trunk/drivers/pci/Kconfig +++ b/trunk/drivers/pci/Kconfig @@ -59,3 +59,13 @@ config HT_IRQ This allows native hypertransport devices to use interrupts. If unsure say Y. + +config PCI_IOV + bool "PCI IOV support" + depends on PCI + help + I/O Virtualization is a PCI feature supported by some devices + which allows them to create virtual devices which share their + physical resources. + + If unsure, say N. diff --git a/trunk/drivers/pci/Makefile b/trunk/drivers/pci/Makefile index 3d07ce24f6a8..ba6af162fd39 100644 --- a/trunk/drivers/pci/Makefile +++ b/trunk/drivers/pci/Makefile @@ -29,6 +29,8 @@ obj-$(CONFIG_DMAR) += dmar.o iova.o intel-iommu.o obj-$(CONFIG_INTR_REMAP) += dmar.o intr_remapping.o +obj-$(CONFIG_PCI_IOV) += iov.o + # # Some architectures use the generic PCI setup functions # diff --git a/trunk/drivers/pci/bus.c b/trunk/drivers/pci/bus.c index 52b54f053be0..68f91a252595 100644 --- a/trunk/drivers/pci/bus.c +++ b/trunk/drivers/pci/bus.c @@ -133,7 +133,7 @@ int pci_bus_add_child(struct pci_bus *bus) * * Call hotplug for each new devices. */ -void pci_bus_add_devices(struct pci_bus *bus) +void pci_bus_add_devices(const struct pci_bus *bus) { struct pci_dev *dev; struct pci_bus *child; @@ -184,8 +184,10 @@ void pci_enable_bridges(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->subordinate) { - retval = pci_enable_device(dev); - pci_set_master(dev); + if (atomic_read(&dev->enable_cnt) == 0) { + retval = pci_enable_device(dev); + pci_set_master(dev); + } pci_enable_bridges(dev->subordinate); } } diff --git a/trunk/drivers/pci/hotplug/acpi_pcihp.c b/trunk/drivers/pci/hotplug/acpi_pcihp.c index 1c1141801060..fbc63d5e459f 100644 --- a/trunk/drivers/pci/hotplug/acpi_pcihp.c +++ b/trunk/drivers/pci/hotplug/acpi_pcihp.c @@ -30,9 +30,8 @@ #include #include #include +#include #include -#include -#include #define MY_NAME "acpi_pcihp" @@ -333,19 +332,14 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus, { acpi_status status = AE_NOT_FOUND; acpi_handle handle, phandle; - struct pci_bus *pbus = bus; - struct pci_dev *pdev; - - do { - pdev = pbus->self; - if (!pdev) { - handle = acpi_get_pci_rootbridge_handle( - pci_domain_nr(pbus), pbus->number); + struct pci_bus *pbus; + + handle = NULL; + for (pbus = bus; pbus; pbus = pbus->parent) { + handle = acpi_pci_get_bridge_handle(pbus); + if (handle) break; - } - handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); - pbus = pbus->parent; - } while (!handle); + } /* * _HPP settings apply to all child buses, until another _HPP is @@ -378,12 +372,10 @@ EXPORT_SYMBOL_GPL(acpi_get_hp_params_from_firmware); * * Attempt to take hotplug control from firmware. */ -int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) +int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) { acpi_status status; acpi_handle chandle, handle; - struct pci_dev *pdev = dev; - struct pci_bus *parent; struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL }; flags &= (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | @@ -408,33 +400,25 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); dbg("Trying to get hotplug control for %s\n", (char *)string.pointer); - status = pci_osc_control_set(handle, flags); + status = acpi_pci_osc_control_set(handle, flags); if (ACPI_SUCCESS(status)) goto got_one; kfree(string.pointer); string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL }; } - pdev = dev; - handle = DEVICE_ACPI_HANDLE(&dev->dev); - while (!handle) { + handle = DEVICE_ACPI_HANDLE(&pdev->dev); + if (!handle) { /* * This hotplug controller was not listed in the ACPI name * space at all. Try to get acpi handle of parent pci bus. */ - if (!pdev || !pdev->bus->parent) - break; - parent = pdev->bus->parent; - dbg("Could not find %s in acpi namespace, trying parent\n", - pci_name(pdev)); - if (!parent->self) - /* Parent must be a host bridge */ - handle = acpi_get_pci_rootbridge_handle( - pci_domain_nr(parent), - parent->number); - else - handle = DEVICE_ACPI_HANDLE(&(parent->self->dev)); - pdev = parent->self; + struct pci_bus *pbus; + for (pbus = pdev->bus; pbus; pbus = pbus->parent) { + handle = acpi_pci_get_bridge_handle(pbus); + if (handle) + break; + } } while (handle) { @@ -453,13 +437,13 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags) } dbg("Cannot get control of hotplug hardware for pci %s\n", - pci_name(dev)); + pci_name(pdev)); kfree(string.pointer); return -ENODEV; got_one: - dbg("Gained control for hotplug HW for pci %s (%s)\n", pci_name(dev), - (char *)string.pointer); + dbg("Gained control for hotplug HW for pci %s (%s)\n", + pci_name(pdev), (char *)string.pointer); kfree(string.pointer); return 0; } diff --git a/trunk/drivers/pci/hotplug/fakephp.c b/trunk/drivers/pci/hotplug/fakephp.c index d8649e127298..6151389fd903 100644 --- a/trunk/drivers/pci/hotplug/fakephp.c +++ b/trunk/drivers/pci/hotplug/fakephp.c @@ -1,395 +1,163 @@ -/* - * Fake PCI Hot Plug Controller Driver +/* Works like the fakephp driver used to, except a little better. * - * Copyright (C) 2003 Greg Kroah-Hartman - * Copyright (C) 2003 IBM Corp. - * Copyright (C) 2003 Rolf Eike Beer + * - It's possible to remove devices with subordinate busses. + * - New PCI devices that appear via any method, not just a fakephp triggered + * rescan, will be noticed. + * - Devices that are removed via any method, not just a fakephp triggered + * removal, will also be noticed. * - * Based on ideas and code from: - * Vladimir Kondratiev - * Rolf Eike Beer + * Uses nothing from the pci-hotplug subsystem. * - * 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 of the License. - * - * Send feedback to */ -/* - * - * This driver will "emulate" removing PCI devices from the system. If - * the "power" file is written to with "0" then the specified PCI device - * will be completely removed from the kernel. - * - * WARNING, this does NOT turn off the power to the PCI device. This is - * a "logical" removal, not a physical or electrical removal. - * - * Use this module at your own risk, you have been warned! - * - * Enabling PCI devices is left as an exercise for the reader... - * - */ -#include #include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include #include "../pci.h" -#if !defined(MODULE) - #define MY_NAME "fakephp" -#else - #define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG "%s: " format, \ - MY_NAME , ## arg); \ - } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) - -#define DRIVER_AUTHOR "Greg Kroah-Hartman " -#define DRIVER_DESC "Fake PCI Hot Plug Controller Driver" - -struct dummy_slot { - struct list_head node; - struct hotplug_slot *slot; - struct pci_dev *dev; - struct work_struct remove_work; - unsigned long removed; +struct legacy_slot { + struct kobject kobj; + struct pci_dev *dev; + struct list_head list; }; -static int debug; -static int dup_slots; -static LIST_HEAD(slot_list); -static struct workqueue_struct *dummyphp_wq; - -static void pci_rescan_worker(struct work_struct *work); -static DECLARE_WORK(pci_rescan_work, pci_rescan_worker); - -static int enable_slot (struct hotplug_slot *slot); -static int disable_slot (struct hotplug_slot *slot); +static LIST_HEAD(legacy_list); -static struct hotplug_slot_ops dummy_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, -}; - -static void dummy_release(struct hotplug_slot *slot) +static ssize_t legacy_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct dummy_slot *dslot = slot->private; - - list_del(&dslot->node); - kfree(dslot->slot->info); - kfree(dslot->slot); - pci_dev_put(dslot->dev); - kfree(dslot); + struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj); + strcpy(buf, "1\n"); + return 2; } -#define SLOT_NAME_SIZE 8 - -static int add_slot(struct pci_dev *dev) +static void remove_callback(void *data) { - struct dummy_slot *dslot; - struct hotplug_slot *slot; - char name[SLOT_NAME_SIZE]; - int retval = -ENOMEM; - static int count = 1; - - slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!slot) - goto error; - - slot->info = kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!slot->info) - goto error_slot; - - slot->info->power_status = 1; - slot->info->max_bus_speed = PCI_SPEED_UNKNOWN; - slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; - - dslot = kzalloc(sizeof(struct dummy_slot), GFP_KERNEL); - if (!dslot) - goto error_info; - - if (dup_slots) - snprintf(name, SLOT_NAME_SIZE, "fake"); - else - snprintf(name, SLOT_NAME_SIZE, "fake%d", count++); - dbg("slot->name = %s\n", name); - slot->ops = &dummy_hotplug_slot_ops; - slot->release = &dummy_release; - slot->private = dslot; - - retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn), name); - if (retval) { - err("pci_hp_register failed with error %d\n", retval); - goto error_dslot; - } - - dbg("slot->name = %s\n", hotplug_slot_name(slot)); - dslot->slot = slot; - dslot->dev = pci_dev_get(dev); - list_add (&dslot->node, &slot_list); - return retval; - -error_dslot: - kfree(dslot); -error_info: - kfree(slot->info); -error_slot: - kfree(slot); -error: - return retval; + pci_remove_bus_device((struct pci_dev *)data); } -static int __init pci_scan_buses(void) +static ssize_t legacy_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t len) { - struct pci_dev *dev = NULL; - int lastslot = 0; + struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj); + unsigned long val; - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { - if (PCI_FUNC(dev->devfn) > 0 && - lastslot == PCI_SLOT(dev->devfn)) - continue; - lastslot = PCI_SLOT(dev->devfn); - add_slot(dev); - } + if (strict_strtoul(buf, 0, &val) < 0) + return -EINVAL; - return 0; + if (val) + pci_rescan_bus(slot->dev->bus); + else + sysfs_schedule_callback(&slot->dev->dev.kobj, remove_callback, + slot->dev, THIS_MODULE); + return len; } -static void remove_slot(struct dummy_slot *dslot) -{ - int retval; - - dbg("removing slot %s\n", hotplug_slot_name(dslot->slot)); - retval = pci_hp_deregister(dslot->slot); - if (retval) - err("Problem unregistering a slot %s\n", - hotplug_slot_name(dslot->slot)); -} +static struct attribute *legacy_attrs[] = { + &(struct attribute){ .name = "power", .mode = 0644 }, + NULL, +}; -/* called from the single-threaded workqueue handler to remove a slot */ -static void remove_slot_worker(struct work_struct *work) +static void legacy_release(struct kobject *kobj) { - struct dummy_slot *dslot = - container_of(work, struct dummy_slot, remove_work); - remove_slot(dslot); -} + struct legacy_slot *slot = container_of(kobj, typeof(*slot), kobj); -/** - * pci_rescan_slot - Rescan slot - * @temp: Device template. Should be set: bus and devfn. - * - * Tries hard not to re-enable already existing devices; - * also handles scanning of subfunctions. - */ -static int pci_rescan_slot(struct pci_dev *temp) -{ - struct pci_bus *bus = temp->bus; - struct pci_dev *dev; - int func; - u8 hdr_type; - int count = 0; - - if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) { - temp->hdr_type = hdr_type & 0x7f; - if ((dev = pci_get_slot(bus, temp->devfn)) != NULL) - pci_dev_put(dev); - else { - dev = pci_scan_single_device(bus, temp->devfn); - if (dev) { - dbg("New device on %s function %x:%x\n", - bus->name, temp->devfn >> 3, - temp->devfn & 7); - count++; - } - } - /* multifunction device? */ - if (!(hdr_type & 0x80)) - return count; - - /* continue scanning for other functions */ - for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) { - if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) - continue; - temp->hdr_type = hdr_type & 0x7f; - - if ((dev = pci_get_slot(bus, temp->devfn)) != NULL) - pci_dev_put(dev); - else { - dev = pci_scan_single_device(bus, temp->devfn); - if (dev) { - dbg("New device on %s function %x:%x\n", - bus->name, temp->devfn >> 3, - temp->devfn & 7); - count++; - } - } - } - } - - return count; + pci_dev_put(slot->dev); + kfree(slot); } +static struct kobj_type legacy_ktype = { + .sysfs_ops = &(struct sysfs_ops){ + .store = legacy_store, .show = legacy_show + }, + .release = &legacy_release, + .default_attrs = legacy_attrs, +}; -/** - * pci_rescan_bus - Rescan PCI bus - * @bus: the PCI bus to rescan - * - * Call pci_rescan_slot for each possible function of the bus. - */ -static void pci_rescan_bus(const struct pci_bus *bus) +static int legacy_add_slot(struct pci_dev *pdev) { - unsigned int devfn; - struct pci_dev *dev; - int retval; - int found = 0; - dev = alloc_pci_dev(); - if (!dev) - return; + struct legacy_slot *slot = kzalloc(sizeof(*slot), GFP_KERNEL); - dev->bus = (struct pci_bus*)bus; - dev->sysdata = bus->sysdata; - for (devfn = 0; devfn < 0x100; devfn += 8) { - dev->devfn = devfn; - found += pci_rescan_slot(dev); - } - - if (found) { - pci_bus_assign_resources(bus); - list_for_each_entry(dev, &bus->devices, bus_list) { - /* Skip already-added devices */ - if (dev->is_added) - continue; - retval = pci_bus_add_device(dev); - if (retval) - dev_err(&dev->dev, - "Error adding device, continuing\n"); - else - add_slot(dev); - } - pci_bus_add_devices(bus); - } - kfree(dev); -} + if (!slot) + return -ENOMEM; -/* recursively scan all buses */ -static void pci_rescan_buses(const struct list_head *list) -{ - const struct list_head *l; - list_for_each(l,list) { - const struct pci_bus *b = pci_bus_b(l); - pci_rescan_bus(b); - pci_rescan_buses(&b->children); + if (kobject_init_and_add(&slot->kobj, &legacy_ktype, + &pci_slots_kset->kobj, "%s", + dev_name(&pdev->dev))) { + dev_warn(&pdev->dev, "Failed to created legacy fake slot\n"); + return -EINVAL; } -} + slot->dev = pci_dev_get(pdev); -/* initiate rescan of all pci buses */ -static inline void pci_rescan(void) { - pci_rescan_buses(&pci_root_buses); -} - -/* called from the single-threaded workqueue handler to rescan all pci buses */ -static void pci_rescan_worker(struct work_struct *work) -{ - pci_rescan(); -} + list_add(&slot->list, &legacy_list); -static int enable_slot(struct hotplug_slot *hotplug_slot) -{ - /* mis-use enable_slot for rescanning of the pci bus */ - cancel_work_sync(&pci_rescan_work); - queue_work(dummyphp_wq, &pci_rescan_work); return 0; } -static int disable_slot(struct hotplug_slot *slot) +static int legacy_notify(struct notifier_block *nb, + unsigned long action, void *data) { - struct dummy_slot *dslot; - struct pci_dev *dev; - int func; - - if (!slot) - return -ENODEV; - dslot = slot->private; - - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(slot)); + struct pci_dev *pdev = to_pci_dev(data); - for (func = 7; func >= 0; func--) { - dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func); - if (!dev) - continue; + if (action == BUS_NOTIFY_ADD_DEVICE) { + legacy_add_slot(pdev); + } else if (action == BUS_NOTIFY_DEL_DEVICE) { + struct legacy_slot *slot; - if (test_and_set_bit(0, &dslot->removed)) { - dbg("Slot already scheduled for removal\n"); - pci_dev_put(dev); - return -ENODEV; - } + list_for_each_entry(slot, &legacy_list, list) + if (slot->dev == pdev) + goto found; - /* remove the device from the pci core */ - pci_remove_bus_device(dev); - - /* queue work item to blow away this sysfs entry and other - * parts. - */ - INIT_WORK(&dslot->remove_work, remove_slot_worker); - queue_work(dummyphp_wq, &dslot->remove_work); - - pci_dev_put(dev); + dev_warn(&pdev->dev, "Missing legacy fake slot?"); + return -ENODEV; +found: + kobject_del(&slot->kobj); + list_del(&slot->list); + kobject_put(&slot->kobj); } + return 0; } -static void cleanup_slots (void) -{ - struct list_head *tmp; - struct list_head *next; - struct dummy_slot *dslot; - - destroy_workqueue(dummyphp_wq); - list_for_each_safe (tmp, next, &slot_list) { - dslot = list_entry (tmp, struct dummy_slot, node); - remove_slot(dslot); - } - -} +static struct notifier_block legacy_notifier = { + .notifier_call = legacy_notify +}; -static int __init dummyphp_init(void) +static int __init init_legacy(void) { - info(DRIVER_DESC "\n"); + struct pci_dev *pdev = NULL; - dummyphp_wq = create_singlethread_workqueue(MY_NAME); - if (!dummyphp_wq) - return -ENOMEM; + /* Add existing devices */ + while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) + legacy_add_slot(pdev); - return pci_scan_buses(); + /* Be alerted of any new ones */ + bus_register_notifier(&pci_bus_type, &legacy_notifier); + return 0; } +module_init(init_legacy); - -static void __exit dummyphp_exit(void) +static void __exit remove_legacy(void) { - cleanup_slots(); + struct legacy_slot *slot, *tmp; + + bus_unregister_notifier(&pci_bus_type, &legacy_notifier); + + list_for_each_entry_safe(slot, tmp, &legacy_list, list) { + list_del(&slot->list); + kobject_del(&slot->kobj); + kobject_put(&slot->kobj); + } } +module_exit(remove_legacy); -module_init(dummyphp_init); -module_exit(dummyphp_exit); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Trent Piepho "); +MODULE_DESCRIPTION("Legacy version of the fakephp interface"); MODULE_LICENSE("GPL"); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -module_param(dup_slots, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dup_slots, "Force duplicate slot names for debugging"); diff --git a/trunk/drivers/pci/hotplug/pciehp.h b/trunk/drivers/pci/hotplug/pciehp.h index 39ae37589fda..0a368547e633 100644 --- a/trunk/drivers/pci/hotplug/pciehp.h +++ b/trunk/drivers/pci/hotplug/pciehp.h @@ -46,10 +46,10 @@ extern int pciehp_force; extern struct workqueue_struct *pciehp_wq; #define dbg(format, arg...) \ - do { \ - if (pciehp_debug) \ - printk("%s: " format, MY_NAME , ## arg); \ - } while (0) +do { \ + if (pciehp_debug) \ + printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); \ +} while (0) #define err(format, arg...) \ printk(KERN_ERR "%s: " format, MY_NAME , ## arg) #define info(format, arg...) \ @@ -60,7 +60,7 @@ extern struct workqueue_struct *pciehp_wq; #define ctrl_dbg(ctrl, format, arg...) \ do { \ if (pciehp_debug) \ - dev_printk(, &ctrl->pcie->device, \ + dev_printk(KERN_DEBUG, &ctrl->pcie->device, \ format, ## arg); \ } while (0) #define ctrl_err(ctrl, format, arg...) \ @@ -108,10 +108,11 @@ struct controller { u32 slot_cap; u8 cap_base; struct timer_list poll_timer; - int cmd_busy; + unsigned int cmd_busy:1; unsigned int no_cmd_complete:1; unsigned int link_active_reporting:1; unsigned int notification_enabled:1; + unsigned int power_fault_detected; }; #define INT_BUTTON_IGNORE 0 diff --git a/trunk/drivers/pci/hotplug/pciehp_acpi.c b/trunk/drivers/pci/hotplug/pciehp_acpi.c index 438d795f9fe3..96048010e7d9 100644 --- a/trunk/drivers/pci/hotplug/pciehp_acpi.c +++ b/trunk/drivers/pci/hotplug/pciehp_acpi.c @@ -67,37 +67,27 @@ static int __init parse_detect_mode(void) return PCIEHP_DETECT_DEFAULT; } -static struct pcie_port_service_id __initdata port_pci_ids[] = { - { - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .port_type = PCIE_ANY_PORT, - .service_type = PCIE_PORT_SERVICE_HP, - .driver_data = 0, - }, { /* end: all zeroes */ } -}; - static int __initdata dup_slot_id; static int __initdata acpi_slot_detected; static struct list_head __initdata dummy_slots = LIST_HEAD_INIT(dummy_slots); /* Dummy driver for dumplicate name detection */ -static int __init dummy_probe(struct pcie_device *dev, - const struct pcie_port_service_id *id) +static int __init dummy_probe(struct pcie_device *dev) { int pos; u32 slot_cap; struct slot *slot, *tmp; struct pci_dev *pdev = dev->port; struct pci_bus *pbus = pdev->subordinate; - if (!(slot = kzalloc(sizeof(*slot), GFP_KERNEL))) - return -ENOMEM; /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ if (pciehp_get_hp_hw_control_from_firmware(pdev)) return -ENODEV; if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP))) return -ENODEV; pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap); + slot = kzalloc(sizeof(*slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; slot->number = slot_cap >> 19; list_for_each_entry(tmp, &dummy_slots, slot_list) { if (tmp->number == slot->number) @@ -111,7 +101,8 @@ static int __init dummy_probe(struct pcie_device *dev, static struct pcie_port_service_driver __initdata dummy_driver = { .name = "pciehp_dummy", - .id_table = port_pci_ids, + .port_type = PCIE_ANY_PORT, + .service = PCIE_PORT_SERVICE_HP, .probe = dummy_probe, }; diff --git a/trunk/drivers/pci/hotplug/pciehp_core.c b/trunk/drivers/pci/hotplug/pciehp_core.c index 681e3912b821..fb254b2454de 100644 --- a/trunk/drivers/pci/hotplug/pciehp_core.c +++ b/trunk/drivers/pci/hotplug/pciehp_core.c @@ -401,7 +401,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe return 0; } -static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_id *id) +static int pciehp_probe(struct pcie_device *dev) { int rc; struct controller *ctrl; @@ -475,7 +475,7 @@ static void pciehp_remove (struct pcie_device *dev) } #ifdef CONFIG_PM -static int pciehp_suspend (struct pcie_device *dev, pm_message_t state) +static int pciehp_suspend (struct pcie_device *dev) { dev_info(&dev->device, "%s ENTRY\n", __func__); return 0; @@ -503,20 +503,12 @@ static int pciehp_resume (struct pcie_device *dev) } return 0; } -#endif - -static struct pcie_port_service_id port_pci_ids[] = { { - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .port_type = PCIE_ANY_PORT, - .service_type = PCIE_PORT_SERVICE_HP, - .driver_data = 0, - }, { /* end: all zeroes */ } -}; +#endif /* PM */ static struct pcie_port_service_driver hpdriver_portdrv = { .name = PCIE_MODULE_NAME, - .id_table = &port_pci_ids[0], + .port_type = PCIE_ANY_PORT, + .service = PCIE_PORT_SERVICE_HP, .probe = pciehp_probe, .remove = pciehp_remove, diff --git a/trunk/drivers/pci/hotplug/pciehp_hpc.c b/trunk/drivers/pci/hotplug/pciehp_hpc.c index 7a16c6897bb9..07bd32151146 100644 --- a/trunk/drivers/pci/hotplug/pciehp_hpc.c +++ b/trunk/drivers/pci/hotplug/pciehp_hpc.c @@ -548,23 +548,21 @@ static int hpc_power_on_slot(struct slot * slot) slot_cmd = POWER_ON; cmd_mask = PCI_EXP_SLTCTL_PCC; - /* Enable detection that we turned off at slot power-off time */ if (!pciehp_poll_mode) { - slot_cmd |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | - PCI_EXP_SLTCTL_PDCE); - cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | - PCI_EXP_SLTCTL_PDCE); + /* Enable power fault detection turned off at power off time */ + slot_cmd |= PCI_EXP_SLTCTL_PFDE; + cmd_mask |= PCI_EXP_SLTCTL_PFDE; } retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); - if (retval) { ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); - return -1; + return retval; } ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); + ctrl->power_fault_detected = 0; return retval; } @@ -621,18 +619,10 @@ static int hpc_power_off_slot(struct slot * slot) slot_cmd = POWER_OFF; cmd_mask = PCI_EXP_SLTCTL_PCC; - /* - * If we get MRL or presence detect interrupts now, the isr - * will notice the sticky power-fault bit too and issue power - * indicator change commands. This will lead to an endless loop - * of command completions, since the power-fault bit remains on - * till the slot is powered on again. - */ if (!pciehp_poll_mode) { - slot_cmd &= ~(PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | - PCI_EXP_SLTCTL_PDCE); - cmd_mask |= (PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | - PCI_EXP_SLTCTL_PDCE); + /* Disable power fault detection */ + slot_cmd &= ~PCI_EXP_SLTCTL_PFDE; + cmd_mask |= PCI_EXP_SLTCTL_PFDE; } retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); @@ -672,10 +662,11 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD | PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC); + detected &= ~intr_loc; intr_loc |= detected; if (!intr_loc) return IRQ_NONE; - if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, detected)) { + if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, intr_loc)) { ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n", __func__); return IRQ_NONE; @@ -709,9 +700,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) pciehp_handle_presence_change(p_slot); /* Check Power Fault Detected */ - if (intr_loc & PCI_EXP_SLTSTA_PFD) + if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) { + ctrl->power_fault_detected = 1; pciehp_handle_power_fault(p_slot); - + } return IRQ_HANDLED; } diff --git a/trunk/drivers/pci/hotplug/shpchp.h b/trunk/drivers/pci/hotplug/shpchp.h index 6aba0b6cf2e0..974e924ca96d 100644 --- a/trunk/drivers/pci/hotplug/shpchp.h +++ b/trunk/drivers/pci/hotplug/shpchp.h @@ -48,10 +48,10 @@ extern int shpchp_debug; extern struct workqueue_struct *shpchp_wq; #define dbg(format, arg...) \ - do { \ - if (shpchp_debug) \ - printk("%s: " format, MY_NAME , ## arg); \ - } while (0) +do { \ + if (shpchp_debug) \ + printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); \ +} while (0) #define err(format, arg...) \ printk(KERN_ERR "%s: " format, MY_NAME , ## arg) #define info(format, arg...) \ @@ -62,7 +62,7 @@ extern struct workqueue_struct *shpchp_wq; #define ctrl_dbg(ctrl, format, arg...) \ do { \ if (shpchp_debug) \ - dev_printk(, &ctrl->pci_dev->dev, \ + dev_printk(KERN_DEBUG, &ctrl->pci_dev->dev, \ format, ## arg); \ } while (0) #define ctrl_err(ctrl, format, arg...) \ diff --git a/trunk/drivers/pci/hotplug/shpchp_pci.c b/trunk/drivers/pci/hotplug/shpchp_pci.c index 138f161becc0..aa315e52529b 100644 --- a/trunk/drivers/pci/hotplug/shpchp_pci.c +++ b/trunk/drivers/pci/hotplug/shpchp_pci.c @@ -137,7 +137,7 @@ int __ref shpchp_configure_device(struct slot *p_slot) busnr)) break; } - if (busnr >= end) { + if (busnr > end) { ctrl_err(ctrl, "No free bus for hot-added bridge\n"); pci_dev_put(dev); diff --git a/trunk/drivers/pci/intel-iommu.c b/trunk/drivers/pci/intel-iommu.c index 49402c399232..23e56a564e05 100644 --- a/trunk/drivers/pci/intel-iommu.c +++ b/trunk/drivers/pci/intel-iommu.c @@ -164,7 +164,8 @@ static inline void context_clear_entry(struct context_entry *context) * 1: writable * 2-6: reserved * 7: super page - * 8-11: available + * 8-10: available + * 11: snoop behavior * 12-63: Host physcial address */ struct dma_pte { @@ -186,6 +187,11 @@ static inline void dma_set_pte_writable(struct dma_pte *pte) pte->val |= DMA_PTE_WRITE; } +static inline void dma_set_pte_snp(struct dma_pte *pte) +{ + pte->val |= DMA_PTE_SNP; +} + static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot) { pte->val = (pte->val & ~3) | (prot & 3); @@ -231,6 +237,7 @@ struct dmar_domain { int flags; /* flags to find out type of domain */ int iommu_coherency;/* indicate coherency of iommu access */ + int iommu_snooping; /* indicate snooping control feature*/ int iommu_count; /* reference count of iommu */ spinlock_t iommu_lock; /* protect iommu set in domain */ u64 max_addr; /* maximum mapped address */ @@ -421,7 +428,6 @@ static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) return g_iommus[iommu_id]; } -/* "Coherency" capability may be different across iommus */ static void domain_update_iommu_coherency(struct dmar_domain *domain) { int i; @@ -438,6 +444,29 @@ static void domain_update_iommu_coherency(struct dmar_domain *domain) } } +static void domain_update_iommu_snooping(struct dmar_domain *domain) +{ + int i; + + domain->iommu_snooping = 1; + + i = find_first_bit(&domain->iommu_bmp, g_num_of_iommus); + for (; i < g_num_of_iommus; ) { + if (!ecap_sc_support(g_iommus[i]->ecap)) { + domain->iommu_snooping = 0; + break; + } + i = find_next_bit(&domain->iommu_bmp, g_num_of_iommus, i+1); + } +} + +/* Some capabilities may be different across iommus */ +static void domain_update_iommu_cap(struct dmar_domain *domain) +{ + domain_update_iommu_coherency(domain); + domain_update_iommu_snooping(domain); +} + static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn) { struct dmar_drhd_unit *drhd = NULL; @@ -689,15 +718,17 @@ static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr) static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end) { int addr_width = agaw_to_width(domain->agaw); + int npages; start &= (((u64)1) << addr_width) - 1; end &= (((u64)1) << addr_width) - 1; /* in case it's partial page */ start = PAGE_ALIGN(start); end &= PAGE_MASK; + npages = (end - start) / VTD_PAGE_SIZE; /* we don't need lock here, nobody else touches the iova range */ - while (start < end) { + while (npages--) { dma_pte_clear_one(domain, start); start += VTD_PAGE_SIZE; } @@ -1241,6 +1272,11 @@ static int domain_init(struct dmar_domain *domain, int guest_width) else domain->iommu_coherency = 0; + if (ecap_sc_support(iommu->ecap)) + domain->iommu_snooping = 1; + else + domain->iommu_snooping = 0; + domain->iommu_count = 1; /* always allocate the top pgd */ @@ -1369,7 +1405,7 @@ static int domain_context_mapping_one(struct dmar_domain *domain, spin_lock_irqsave(&domain->iommu_lock, flags); if (!test_and_set_bit(iommu->seq_id, &domain->iommu_bmp)) { domain->iommu_count++; - domain_update_iommu_coherency(domain); + domain_update_iommu_cap(domain); } spin_unlock_irqrestore(&domain->iommu_lock, flags); return 0; @@ -1469,6 +1505,8 @@ domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova, BUG_ON(dma_pte_addr(pte)); dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT); dma_set_pte_prot(pte, prot); + if (prot & DMA_PTE_SNP) + dma_set_pte_snp(pte); domain_flush_cache(domain, pte, sizeof(*pte)); start_pfn++; index++; @@ -1782,7 +1820,7 @@ static inline void iommu_prepare_isa(void) ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024); if (ret) - printk("IOMMU: Failed to create 0-64M identity map, " + printk(KERN_ERR "IOMMU: Failed to create 0-64M identity map, " "floppy might not work\n"); } @@ -2119,7 +2157,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr, error: if (iova) __free_iova(&domain->iovad, iova); - printk(KERN_ERR"Device %s request: %lx@%llx dir %d --- failed\n", + printk(KERN_ERR"Device %s request: %zx@%llx dir %d --- failed\n", pci_name(pdev), size, (unsigned long long)paddr, dir); return 0; } @@ -2218,7 +2256,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, start_addr = iova->pfn_lo << PAGE_SHIFT; size = aligned_size((u64)dev_addr, size); - pr_debug("Device %s unmapping: %lx@%llx\n", + pr_debug("Device %s unmapping: %zx@%llx\n", pci_name(pdev), size, (unsigned long long)start_addr); /* clear the whole page */ @@ -2282,8 +2320,6 @@ static void intel_free_coherent(struct device *hwdev, size_t size, void *vaddr, free_pages((unsigned long)vaddr, order); } -#define SG_ENT_VIRT_ADDRESS(sg) (sg_virt((sg))) - static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, int nelems, enum dma_data_direction dir, struct dma_attrs *attrs) @@ -2294,7 +2330,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, unsigned long start_addr; struct iova *iova; size_t size = 0; - void *addr; + phys_addr_t addr; struct scatterlist *sg; struct intel_iommu *iommu; @@ -2310,7 +2346,7 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist, if (!iova) return; for_each_sg(sglist, sg, nelems, i) { - addr = SG_ENT_VIRT_ADDRESS(sg); + addr = page_to_phys(sg_page(sg)) + sg->offset; size += aligned_size((u64)addr, sg->length); } @@ -2337,7 +2373,7 @@ static int intel_nontranslate_map_sg(struct device *hddev, for_each_sg(sglist, sg, nelems, i) { BUG_ON(!sg_page(sg)); - sg->dma_address = virt_to_bus(SG_ENT_VIRT_ADDRESS(sg)); + sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset; sg->dma_length = sg->length; } return nelems; @@ -2346,7 +2382,7 @@ static int intel_nontranslate_map_sg(struct device *hddev, static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems, enum dma_data_direction dir, struct dma_attrs *attrs) { - void *addr; + phys_addr_t addr; int i; struct pci_dev *pdev = to_pci_dev(hwdev); struct dmar_domain *domain; @@ -2370,8 +2406,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne iommu = domain_get_iommu(domain); for_each_sg(sglist, sg, nelems, i) { - addr = SG_ENT_VIRT_ADDRESS(sg); - addr = (void *)virt_to_phys(addr); + addr = page_to_phys(sg_page(sg)) + sg->offset; size += aligned_size((u64)addr, sg->length); } @@ -2394,8 +2429,7 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne start_addr = iova->pfn_lo << PAGE_SHIFT; offset = 0; for_each_sg(sglist, sg, nelems, i) { - addr = SG_ENT_VIRT_ADDRESS(sg); - addr = (void *)virt_to_phys(addr); + addr = page_to_phys(sg_page(sg)) + sg->offset; size = aligned_size((u64)addr, sg->length); ret = domain_page_mapping(domain, start_addr + offset, ((u64)addr) & PAGE_MASK, @@ -2628,6 +2662,33 @@ static int vm_domain_add_dev_info(struct dmar_domain *domain, return 0; } +static void iommu_detach_dependent_devices(struct intel_iommu *iommu, + struct pci_dev *pdev) +{ + struct pci_dev *tmp, *parent; + + if (!iommu || !pdev) + return; + + /* dependent device detach */ + tmp = pci_find_upstream_pcie_bridge(pdev); + /* Secondary interface's bus number and devfn 0 */ + if (tmp) { + parent = pdev->bus->self; + while (parent != tmp) { + iommu_detach_dev(iommu, parent->bus->number, + parent->devfn); + parent = parent->bus->self; + } + if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ + iommu_detach_dev(iommu, + tmp->subordinate->number, 0); + else /* this is a legacy PCI bridge */ + iommu_detach_dev(iommu, + tmp->bus->number, tmp->devfn); + } +} + static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, struct pci_dev *pdev) { @@ -2653,6 +2714,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, spin_unlock_irqrestore(&device_domain_lock, flags); iommu_detach_dev(iommu, info->bus, info->devfn); + iommu_detach_dependent_devices(iommu, pdev); free_devinfo_mem(info); spin_lock_irqsave(&device_domain_lock, flags); @@ -2676,7 +2738,7 @@ static void vm_domain_remove_one_dev_info(struct dmar_domain *domain, spin_lock_irqsave(&domain->iommu_lock, tmp_flags); clear_bit(iommu->seq_id, &domain->iommu_bmp); domain->iommu_count--; - domain_update_iommu_coherency(domain); + domain_update_iommu_cap(domain); spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags); } @@ -2702,15 +2764,16 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain) iommu = device_to_iommu(info->bus, info->devfn); iommu_detach_dev(iommu, info->bus, info->devfn); + iommu_detach_dependent_devices(iommu, info->dev); /* clear this iommu in iommu_bmp, update iommu count - * and coherency + * and capabilities */ spin_lock_irqsave(&domain->iommu_lock, flags2); if (test_and_clear_bit(iommu->seq_id, &domain->iommu_bmp)) { domain->iommu_count--; - domain_update_iommu_coherency(domain); + domain_update_iommu_cap(domain); } spin_unlock_irqrestore(&domain->iommu_lock, flags2); @@ -2933,6 +2996,8 @@ static int intel_iommu_map_range(struct iommu_domain *domain, prot |= DMA_PTE_READ; if (iommu_prot & IOMMU_WRITE) prot |= DMA_PTE_WRITE; + if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping) + prot |= DMA_PTE_SNP; max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size); if (dmar_domain->max_addr < max_addr) { @@ -2986,6 +3051,17 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, return phys; } +static int intel_iommu_domain_has_cap(struct iommu_domain *domain, + unsigned long cap) +{ + struct dmar_domain *dmar_domain = domain->priv; + + if (cap == IOMMU_CAP_CACHE_COHERENCY) + return dmar_domain->iommu_snooping; + + return 0; +} + static struct iommu_ops intel_iommu_ops = { .domain_init = intel_iommu_domain_init, .domain_destroy = intel_iommu_domain_destroy, @@ -2994,6 +3070,7 @@ static struct iommu_ops intel_iommu_ops = { .map = intel_iommu_map_range, .unmap = intel_iommu_unmap_range, .iova_to_phys = intel_iommu_iova_to_phys, + .domain_has_cap = intel_iommu_domain_has_cap, }; static void __devinit quirk_iommu_rwbf(struct pci_dev *dev) diff --git a/trunk/drivers/pci/iov.c b/trunk/drivers/pci/iov.c new file mode 100644 index 000000000000..7227efc760db --- /dev/null +++ b/trunk/drivers/pci/iov.c @@ -0,0 +1,680 @@ +/* + * drivers/pci/iov.c + * + * Copyright (C) 2009 Intel Corporation, Yu Zhao + * + * PCI Express I/O Virtualization (IOV) support. + * Single Root IOV 1.0 + */ + +#include +#include +#include +#include +#include "pci.h" + +#define VIRTFN_ID_LEN 16 + +static inline u8 virtfn_bus(struct pci_dev *dev, int id) +{ + return dev->bus->number + ((dev->devfn + dev->sriov->offset + + dev->sriov->stride * id) >> 8); +} + +static inline u8 virtfn_devfn(struct pci_dev *dev, int id) +{ + return (dev->devfn + dev->sriov->offset + + dev->sriov->stride * id) & 0xff; +} + +static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) +{ + int rc; + struct pci_bus *child; + + if (bus->number == busnr) + return bus; + + child = pci_find_bus(pci_domain_nr(bus), busnr); + if (child) + return child; + + child = pci_add_new_bus(bus, NULL, busnr); + if (!child) + return NULL; + + child->subordinate = busnr; + child->dev.parent = bus->bridge; + rc = pci_bus_add_child(child); + if (rc) { + pci_remove_bus(child); + return NULL; + } + + return child; +} + +static void virtfn_remove_bus(struct pci_bus *bus, int busnr) +{ + struct pci_bus *child; + + if (bus->number == busnr) + return; + + child = pci_find_bus(pci_domain_nr(bus), busnr); + BUG_ON(!child); + + if (list_empty(&child->devices)) + pci_remove_bus(child); +} + +static int virtfn_add(struct pci_dev *dev, int id, int reset) +{ + int i; + int rc; + u64 size; + char buf[VIRTFN_ID_LEN]; + struct pci_dev *virtfn; + struct resource *res; + struct pci_sriov *iov = dev->sriov; + + virtfn = alloc_pci_dev(); + if (!virtfn) + return -ENOMEM; + + mutex_lock(&iov->dev->sriov->lock); + virtfn->bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id)); + if (!virtfn->bus) { + kfree(virtfn); + mutex_unlock(&iov->dev->sriov->lock); + return -ENOMEM; + } + virtfn->devfn = virtfn_devfn(dev, id); + virtfn->vendor = dev->vendor; + pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device); + pci_setup_device(virtfn); + virtfn->dev.parent = dev->dev.parent; + + for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { + res = dev->resource + PCI_IOV_RESOURCES + i; + if (!res->parent) + continue; + virtfn->resource[i].name = pci_name(virtfn); + virtfn->resource[i].flags = res->flags; + size = resource_size(res); + do_div(size, iov->total); + virtfn->resource[i].start = res->start + size * id; + virtfn->resource[i].end = virtfn->resource[i].start + size - 1; + rc = request_resource(res, &virtfn->resource[i]); + BUG_ON(rc); + } + + if (reset) + pci_execute_reset_function(virtfn); + + pci_device_add(virtfn, virtfn->bus); + mutex_unlock(&iov->dev->sriov->lock); + + virtfn->physfn = pci_dev_get(dev); + virtfn->is_virtfn = 1; + + rc = pci_bus_add_device(virtfn); + if (rc) + goto failed1; + sprintf(buf, "virtfn%u", id); + rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); + if (rc) + goto failed1; + rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn"); + if (rc) + goto failed2; + + kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE); + + return 0; + +failed2: + sysfs_remove_link(&dev->dev.kobj, buf); +failed1: + pci_dev_put(dev); + mutex_lock(&iov->dev->sriov->lock); + pci_remove_bus_device(virtfn); + virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); + mutex_unlock(&iov->dev->sriov->lock); + + return rc; +} + +static void virtfn_remove(struct pci_dev *dev, int id, int reset) +{ + char buf[VIRTFN_ID_LEN]; + struct pci_bus *bus; + struct pci_dev *virtfn; + struct pci_sriov *iov = dev->sriov; + + bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id)); + if (!bus) + return; + + virtfn = pci_get_slot(bus, virtfn_devfn(dev, id)); + if (!virtfn) + return; + + pci_dev_put(virtfn); + + if (reset) { + device_release_driver(&virtfn->dev); + pci_execute_reset_function(virtfn); + } + + sprintf(buf, "virtfn%u", id); + sysfs_remove_link(&dev->dev.kobj, buf); + sysfs_remove_link(&virtfn->dev.kobj, "physfn"); + + mutex_lock(&iov->dev->sriov->lock); + pci_remove_bus_device(virtfn); + virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); + mutex_unlock(&iov->dev->sriov->lock); + + pci_dev_put(dev); +} + +static int sriov_migration(struct pci_dev *dev) +{ + u16 status; + struct pci_sriov *iov = dev->sriov; + + if (!iov->nr_virtfn) + return 0; + + if (!(iov->cap & PCI_SRIOV_CAP_VFM)) + return 0; + + pci_read_config_word(dev, iov->pos + PCI_SRIOV_STATUS, &status); + if (!(status & PCI_SRIOV_STATUS_VFM)) + return 0; + + schedule_work(&iov->mtask); + + return 1; +} + +static void sriov_migration_task(struct work_struct *work) +{ + int i; + u8 state; + u16 status; + struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask); + + for (i = iov->initial; i < iov->nr_virtfn; i++) { + state = readb(iov->mstate + i); + if (state == PCI_SRIOV_VFM_MI) { + writeb(PCI_SRIOV_VFM_AV, iov->mstate + i); + state = readb(iov->mstate + i); + if (state == PCI_SRIOV_VFM_AV) + virtfn_add(iov->self, i, 1); + } else if (state == PCI_SRIOV_VFM_MO) { + virtfn_remove(iov->self, i, 1); + writeb(PCI_SRIOV_VFM_UA, iov->mstate + i); + state = readb(iov->mstate + i); + if (state == PCI_SRIOV_VFM_AV) + virtfn_add(iov->self, i, 0); + } + } + + pci_read_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, &status); + status &= ~PCI_SRIOV_STATUS_VFM; + pci_write_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, status); +} + +static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn) +{ + int bir; + u32 table; + resource_size_t pa; + struct pci_sriov *iov = dev->sriov; + + if (nr_virtfn <= iov->initial) + return 0; + + pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table); + bir = PCI_SRIOV_VFM_BIR(table); + if (bir > PCI_STD_RESOURCE_END) + return -EIO; + + table = PCI_SRIOV_VFM_OFFSET(table); + if (table + nr_virtfn > pci_resource_len(dev, bir)) + return -EIO; + + pa = pci_resource_start(dev, bir) + table; + iov->mstate = ioremap(pa, nr_virtfn); + if (!iov->mstate) + return -ENOMEM; + + INIT_WORK(&iov->mtask, sriov_migration_task); + + iov->ctrl |= PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR; + pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); + + return 0; +} + +static void sriov_disable_migration(struct pci_dev *dev) +{ + struct pci_sriov *iov = dev->sriov; + + iov->ctrl &= ~(PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); + + cancel_work_sync(&iov->mtask); + iounmap(iov->mstate); +} + +static int sriov_enable(struct pci_dev *dev, int nr_virtfn) +{ + int rc; + int i, j; + int nres; + u16 offset, stride, initial; + struct resource *res; + struct pci_dev *pdev; + struct pci_sriov *iov = dev->sriov; + + if (!nr_virtfn) + return 0; + + if (iov->nr_virtfn) + return -EINVAL; + + pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial); + if (initial > iov->total || + (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total))) + return -EIO; + + if (nr_virtfn < 0 || nr_virtfn > iov->total || + (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial))) + return -EINVAL; + + pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn); + pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &offset); + pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &stride); + if (!offset || (nr_virtfn > 1 && !stride)) + return -EIO; + + nres = 0; + for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { + res = dev->resource + PCI_IOV_RESOURCES + i; + if (res->parent) + nres++; + } + if (nres != iov->nres) { + dev_err(&dev->dev, "not enough MMIO resources for SR-IOV\n"); + return -ENOMEM; + } + + iov->offset = offset; + iov->stride = stride; + + if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->subordinate) { + dev_err(&dev->dev, "SR-IOV: bus number out of range\n"); + return -ENOMEM; + } + + if (iov->link != dev->devfn) { + pdev = pci_get_slot(dev->bus, iov->link); + if (!pdev) + return -ENODEV; + + pci_dev_put(pdev); + + if (!pdev->is_physfn) + return -ENODEV; + + rc = sysfs_create_link(&dev->dev.kobj, + &pdev->dev.kobj, "dep_link"); + if (rc) + return rc; + } + + iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; + pci_block_user_cfg_access(dev); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); + msleep(100); + pci_unblock_user_cfg_access(dev); + + iov->initial = initial; + if (nr_virtfn < initial) + initial = nr_virtfn; + + for (i = 0; i < initial; i++) { + rc = virtfn_add(dev, i, 0); + if (rc) + goto failed; + } + + if (iov->cap & PCI_SRIOV_CAP_VFM) { + rc = sriov_enable_migration(dev, nr_virtfn); + if (rc) + goto failed; + } + + kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE); + iov->nr_virtfn = nr_virtfn; + + return 0; + +failed: + for (j = 0; j < i; j++) + virtfn_remove(dev, j, 0); + + iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); + pci_block_user_cfg_access(dev); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); + ssleep(1); + pci_unblock_user_cfg_access(dev); + + if (iov->link != dev->devfn) + sysfs_remove_link(&dev->dev.kobj, "dep_link"); + + return rc; +} + +static void sriov_disable(struct pci_dev *dev) +{ + int i; + struct pci_sriov *iov = dev->sriov; + + if (!iov->nr_virtfn) + return; + + if (iov->cap & PCI_SRIOV_CAP_VFM) + sriov_disable_migration(dev); + + for (i = 0; i < iov->nr_virtfn; i++) + virtfn_remove(dev, i, 0); + + iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); + pci_block_user_cfg_access(dev); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); + ssleep(1); + pci_unblock_user_cfg_access(dev); + + if (iov->link != dev->devfn) + sysfs_remove_link(&dev->dev.kobj, "dep_link"); + + iov->nr_virtfn = 0; +} + +static int sriov_init(struct pci_dev *dev, int pos) +{ + int i; + int rc; + int nres; + u32 pgsz; + u16 ctrl, total, offset, stride; + struct pci_sriov *iov; + struct resource *res; + struct pci_dev *pdev; + + if (dev->pcie_type != PCI_EXP_TYPE_RC_END && + dev->pcie_type != PCI_EXP_TYPE_ENDPOINT) + return -ENODEV; + + pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl); + if (ctrl & PCI_SRIOV_CTRL_VFE) { + pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, 0); + ssleep(1); + } + + pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total); + if (!total) + return 0; + + ctrl = 0; + list_for_each_entry(pdev, &dev->bus->devices, bus_list) + if (pdev->is_physfn) + goto found; + + pdev = NULL; + if (pci_ari_enabled(dev->bus)) + ctrl |= PCI_SRIOV_CTRL_ARI; + +found: + pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl); + pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total); + pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset); + pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride); + if (!offset || (total > 1 && !stride)) + return -EIO; + + pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz); + i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0; + pgsz &= ~((1 << i) - 1); + if (!pgsz) + return -EIO; + + pgsz &= ~(pgsz - 1); + pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz); + + nres = 0; + for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { + res = dev->resource + PCI_IOV_RESOURCES + i; + i += __pci_read_base(dev, pci_bar_unknown, res, + pos + PCI_SRIOV_BAR + i * 4); + if (!res->flags) + continue; + if (resource_size(res) & (PAGE_SIZE - 1)) { + rc = -EIO; + goto failed; + } + res->end = res->start + resource_size(res) * total - 1; + nres++; + } + + iov = kzalloc(sizeof(*iov), GFP_KERNEL); + if (!iov) { + rc = -ENOMEM; + goto failed; + } + + iov->pos = pos; + iov->nres = nres; + iov->ctrl = ctrl; + iov->total = total; + iov->offset = offset; + iov->stride = stride; + iov->pgsz = pgsz; + iov->self = dev; + pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap); + pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); + + if (pdev) + iov->dev = pci_dev_get(pdev); + else { + iov->dev = dev; + mutex_init(&iov->lock); + } + + dev->sriov = iov; + dev->is_physfn = 1; + + return 0; + +failed: + for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { + res = dev->resource + PCI_IOV_RESOURCES + i; + res->flags = 0; + } + + return rc; +} + +static void sriov_release(struct pci_dev *dev) +{ + BUG_ON(dev->sriov->nr_virtfn); + + if (dev == dev->sriov->dev) + mutex_destroy(&dev->sriov->lock); + else + pci_dev_put(dev->sriov->dev); + + kfree(dev->sriov); + dev->sriov = NULL; +} + +static void sriov_restore_state(struct pci_dev *dev) +{ + int i; + u16 ctrl; + struct pci_sriov *iov = dev->sriov; + + pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &ctrl); + if (ctrl & PCI_SRIOV_CTRL_VFE) + return; + + for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) + pci_update_resource(dev, i); + + pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->nr_virtfn); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); + if (iov->ctrl & PCI_SRIOV_CTRL_VFE) + msleep(100); +} + +/** + * pci_iov_init - initialize the IOV capability + * @dev: the PCI device + * + * Returns 0 on success, or negative on failure. + */ +int pci_iov_init(struct pci_dev *dev) +{ + int pos; + + if (!dev->is_pcie) + return -ENODEV; + + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); + if (pos) + return sriov_init(dev, pos); + + return -ENODEV; +} + +/** + * pci_iov_release - release resources used by the IOV capability + * @dev: the PCI device + */ +void pci_iov_release(struct pci_dev *dev) +{ + if (dev->is_physfn) + sriov_release(dev); +} + +/** + * pci_iov_resource_bar - get position of the SR-IOV BAR + * @dev: the PCI device + * @resno: the resource number + * @type: the BAR type to be filled in + * + * Returns position of the BAR encapsulated in the SR-IOV capability. + */ +int pci_iov_resource_bar(struct pci_dev *dev, int resno, + enum pci_bar_type *type) +{ + if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END) + return 0; + + BUG_ON(!dev->is_physfn); + + *type = pci_bar_unknown; + + return dev->sriov->pos + PCI_SRIOV_BAR + + 4 * (resno - PCI_IOV_RESOURCES); +} + +/** + * pci_restore_iov_state - restore the state of the IOV capability + * @dev: the PCI device + */ +void pci_restore_iov_state(struct pci_dev *dev) +{ + if (dev->is_physfn) + sriov_restore_state(dev); +} + +/** + * pci_iov_bus_range - find bus range used by Virtual Function + * @bus: the PCI bus + * + * Returns max number of buses (exclude current one) used by Virtual + * Functions. + */ +int pci_iov_bus_range(struct pci_bus *bus) +{ + int max = 0; + u8 busnr; + struct pci_dev *dev; + + list_for_each_entry(dev, &bus->devices, bus_list) { + if (!dev->is_physfn) + continue; + busnr = virtfn_bus(dev, dev->sriov->total - 1); + if (busnr > max) + max = busnr; + } + + return max ? max - bus->number : 0; +} + +/** + * pci_enable_sriov - enable the SR-IOV capability + * @dev: the PCI device + * + * Returns 0 on success, or negative on failure. + */ +int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) +{ + might_sleep(); + + if (!dev->is_physfn) + return -ENODEV; + + return sriov_enable(dev, nr_virtfn); +} +EXPORT_SYMBOL_GPL(pci_enable_sriov); + +/** + * pci_disable_sriov - disable the SR-IOV capability + * @dev: the PCI device + */ +void pci_disable_sriov(struct pci_dev *dev) +{ + might_sleep(); + + if (!dev->is_physfn) + return; + + sriov_disable(dev); +} +EXPORT_SYMBOL_GPL(pci_disable_sriov); + +/** + * pci_sriov_migration - notify SR-IOV core of Virtual Function Migration + * @dev: the PCI device + * + * Returns IRQ_HANDLED if the IRQ is handled, or IRQ_NONE if not. + * + * Physical Function driver is responsible to register IRQ handler using + * VF Migration Interrupt Message Number, and call this function when the + * interrupt is generated by the hardware. + */ +irqreturn_t pci_sriov_migration(struct pci_dev *dev) +{ + if (!dev->is_physfn) + return IRQ_NONE; + + return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE; +} +EXPORT_SYMBOL_GPL(pci_sriov_migration); diff --git a/trunk/drivers/pci/msi.c b/trunk/drivers/pci/msi.c index baba2eb5367d..6f2e6295e773 100644 --- a/trunk/drivers/pci/msi.c +++ b/trunk/drivers/pci/msi.c @@ -27,48 +27,53 @@ static int pci_msi_enable = 1; /* Arch hooks */ -int __attribute__ ((weak)) -arch_msi_check_device(struct pci_dev *dev, int nvec, int type) +#ifndef arch_msi_check_device +int arch_msi_check_device(struct pci_dev *dev, int nvec, int type) { return 0; } +#endif -int __attribute__ ((weak)) -arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry) -{ - return 0; -} - -int __attribute__ ((weak)) -arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) +#ifndef arch_setup_msi_irqs +int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) { struct msi_desc *entry; int ret; + /* + * If an architecture wants to support multiple MSI, it needs to + * override arch_setup_msi_irqs() + */ + if (type == PCI_CAP_ID_MSI && nvec > 1) + return 1; + list_for_each_entry(entry, &dev->msi_list, list) { ret = arch_setup_msi_irq(dev, entry); - if (ret) + if (ret < 0) return ret; + if (ret > 0) + return -ENOSPC; } return 0; } +#endif -void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq) -{ - return; -} - -void __attribute__ ((weak)) -arch_teardown_msi_irqs(struct pci_dev *dev) +#ifndef arch_teardown_msi_irqs +void arch_teardown_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry; list_for_each_entry(entry, &dev->msi_list, list) { - if (entry->irq != 0) - arch_teardown_msi_irq(entry->irq); + int i, nvec; + if (entry->irq == 0) + continue; + nvec = 1 << entry->msi_attrib.multiple; + for (i = 0; i < nvec; i++) + arch_teardown_msi_irq(entry->irq + i); } } +#endif static void __msi_set_enable(struct pci_dev *dev, int pos, int enable) { @@ -111,27 +116,14 @@ static inline __attribute_const__ u32 msi_mask(unsigned x) return (1 << (1 << x)) - 1; } -static void msix_flush_writes(struct irq_desc *desc) +static inline __attribute_const__ u32 msi_capable_mask(u16 control) { - struct msi_desc *entry; + return msi_mask((control >> 1) & 7); +} - entry = get_irq_desc_msi(desc); - BUG_ON(!entry || !entry->dev); - switch (entry->msi_attrib.type) { - case PCI_CAP_ID_MSI: - /* nothing to do */ - break; - case PCI_CAP_ID_MSIX: - { - int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; - readl(entry->mask_base + offset); - break; - } - default: - BUG(); - break; - } +static inline __attribute_const__ u32 msi_enabled_mask(u16 control) +{ + return msi_mask((control >> 4) & 7); } /* @@ -143,49 +135,71 @@ static void msix_flush_writes(struct irq_desc *desc) * Returns 1 if it succeeded in masking the interrupt and 0 if the device * doesn't support MSI masking. */ -static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag) +static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) { - struct msi_desc *entry; + u32 mask_bits = desc->masked; - entry = get_irq_desc_msi(desc); - BUG_ON(!entry || !entry->dev); - switch (entry->msi_attrib.type) { - case PCI_CAP_ID_MSI: - if (entry->msi_attrib.maskbit) { - int pos; - u32 mask_bits; - - pos = (long)entry->mask_base; - pci_read_config_dword(entry->dev, pos, &mask_bits); - mask_bits &= ~(mask); - mask_bits |= flag & mask; - pci_write_config_dword(entry->dev, pos, mask_bits); - } else { - return 0; - } - break; - case PCI_CAP_ID_MSIX: - { - int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; - writel(flag, entry->mask_base + offset); - readl(entry->mask_base + offset); - break; - } - default: - BUG(); - break; + if (!desc->msi_attrib.maskbit) + return; + + mask_bits &= ~mask; + mask_bits |= flag; + pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits); + desc->masked = mask_bits; +} + +/* + * This internal function does not flush PCI writes to the device. + * All users must ensure that they read from the device before either + * assuming that the device state is up to date, or returning out of this + * file. This saves a few milliseconds when initialising devices with lots + * of MSI-X interrupts. + */ +static void msix_mask_irq(struct msi_desc *desc, u32 flag) +{ + u32 mask_bits = desc->masked; + unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; + mask_bits &= ~1; + mask_bits |= flag; + writel(mask_bits, desc->mask_base + offset); + desc->masked = mask_bits; +} + +static void msi_set_mask_bit(unsigned irq, u32 flag) +{ + struct msi_desc *desc = get_irq_msi(irq); + + if (desc->msi_attrib.is_msix) { + msix_mask_irq(desc, flag); + readl(desc->mask_base); /* Flush write to device */ + } else { + unsigned offset = irq - desc->dev->irq; + msi_mask_irq(desc, 1 << offset, flag << offset); } - entry->msi_attrib.masked = !!flag; - return 1; +} + +void mask_msi_irq(unsigned int irq) +{ + msi_set_mask_bit(irq, 1); +} + +void unmask_msi_irq(unsigned int irq) +{ + msi_set_mask_bit(irq, 0); } void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) { struct msi_desc *entry = get_irq_desc_msi(desc); - switch(entry->msi_attrib.type) { - case PCI_CAP_ID_MSI: - { + if (entry->msi_attrib.is_msix) { + void __iomem *base = entry->mask_base + + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; + + msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); + msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); + msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET); + } else { struct pci_dev *dev = entry->dev; int pos = entry->msi_attrib.pos; u16 data; @@ -201,21 +215,6 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) pci_read_config_word(dev, msi_data_reg(pos, 0), &data); } msg->data = data; - break; - } - case PCI_CAP_ID_MSIX: - { - void __iomem *base; - base = entry->mask_base + - entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; - - msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET); - break; - } - default: - BUG(); } } @@ -229,11 +228,25 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) { struct msi_desc *entry = get_irq_desc_msi(desc); - switch (entry->msi_attrib.type) { - case PCI_CAP_ID_MSI: - { + if (entry->msi_attrib.is_msix) { + void __iomem *base; + base = entry->mask_base + + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; + + writel(msg->address_lo, + base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); + writel(msg->address_hi, + base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); + writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET); + } else { struct pci_dev *dev = entry->dev; int pos = entry->msi_attrib.pos; + u16 msgctl; + + pci_read_config_word(dev, msi_control_reg(pos), &msgctl); + msgctl &= ~PCI_MSI_FLAGS_QSIZE; + msgctl |= entry->msi_attrib.multiple << 4; + pci_write_config_word(dev, msi_control_reg(pos), msgctl); pci_write_config_dword(dev, msi_lower_address_reg(pos), msg->address_lo); @@ -246,23 +259,6 @@ void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) pci_write_config_word(dev, msi_data_reg(pos, 0), msg->data); } - break; - } - case PCI_CAP_ID_MSIX: - { - void __iomem *base; - base = entry->mask_base + - entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE; - - writel(msg->address_lo, - base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); - writel(msg->address_hi, - base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); - writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET); - break; - } - default: - BUG(); } entry->msg = *msg; } @@ -274,37 +270,18 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) write_msi_msg_desc(desc, msg); } -void mask_msi_irq(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - - msi_set_mask_bits(desc, 1, 1); - msix_flush_writes(desc); -} - -void unmask_msi_irq(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - - msi_set_mask_bits(desc, 1, 0); - msix_flush_writes(desc); -} - static int msi_free_irqs(struct pci_dev* dev); -static struct msi_desc* alloc_msi_entry(void) +static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) { - struct msi_desc *entry; - - entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL); - if (!entry) + struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) return NULL; - INIT_LIST_HEAD(&entry->list); - entry->irq = 0; - entry->dev = NULL; + INIT_LIST_HEAD(&desc->list); + desc->dev = dev; - return entry; + return desc; } static void pci_intx_for_msi(struct pci_dev *dev, int enable) @@ -328,15 +305,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev) pci_intx_for_msi(dev, 0); msi_set_enable(dev, 0); write_msi_msg(dev->irq, &entry->msg); - if (entry->msi_attrib.maskbit) { - struct irq_desc *desc = irq_to_desc(dev->irq); - msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask, - entry->msi_attrib.masked); - } pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); + msi_mask_irq(entry, msi_capable_mask(control), entry->masked); control &= ~PCI_MSI_FLAGS_QSIZE; - control |= PCI_MSI_FLAGS_ENABLE; + control |= (entry->msi_attrib.multiple << 4) | PCI_MSI_FLAGS_ENABLE; pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); } @@ -354,9 +327,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev) msix_set_enable(dev, 0); list_for_each_entry(entry, &dev->msi_list, list) { - struct irq_desc *desc = irq_to_desc(entry->irq); write_msi_msg(entry->irq, &entry->msg); - msi_set_mask_bits(desc, 1, entry->msi_attrib.masked); + msix_mask_irq(entry, entry->masked); } BUG_ON(list_empty(&dev->msi_list)); @@ -378,52 +350,48 @@ EXPORT_SYMBOL_GPL(pci_restore_msi_state); /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function + * @nvec: number of interrupts to allocate * - * Setup the MSI capability structure of device function with a single - * MSI irq, regardless of device function is capable of handling - * multiple messages. A return of zero indicates the successful setup - * of an entry zero with the new MSI irq or non-zero for otherwise. - **/ -static int msi_capability_init(struct pci_dev *dev) + * Setup the MSI capability structure of the device with the requested + * number of interrupts. A return value of zero indicates the successful + * setup of an entry with the new MSI irq. A negative return value indicates + * an error, and a positive return value indicates the number of interrupts + * which could have been allocated. + */ +static int msi_capability_init(struct pci_dev *dev, int nvec) { struct msi_desc *entry; int pos, ret; u16 control; + unsigned mask; msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ - entry = alloc_msi_entry(); + entry = alloc_msi_entry(dev); if (!entry) return -ENOMEM; - entry->msi_attrib.type = PCI_CAP_ID_MSI; + entry->msi_attrib.is_msix = 0; entry->msi_attrib.is_64 = is_64bit_address(control); entry->msi_attrib.entry_nr = 0; entry->msi_attrib.maskbit = is_mask_bit_support(control); - entry->msi_attrib.masked = 1; entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ entry->msi_attrib.pos = pos; - entry->dev = dev; - if (entry->msi_attrib.maskbit) { - unsigned int base, maskbits, temp; - - base = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); - entry->mask_base = (void __iomem *)(long)base; - - /* All MSIs are unmasked by default, Mask them all */ - pci_read_config_dword(dev, base, &maskbits); - temp = msi_mask((control & PCI_MSI_FLAGS_QMASK) >> 1); - maskbits |= temp; - pci_write_config_dword(dev, base, maskbits); - entry->msi_attrib.maskbits_mask = temp; - } + + entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); + /* All MSIs are unmasked by default, Mask them all */ + if (entry->msi_attrib.maskbit) + pci_read_config_dword(dev, entry->mask_pos, &entry->masked); + mask = msi_capable_mask(control); + msi_mask_irq(entry, mask, mask); + list_add_tail(&entry->list, &dev->msi_list); /* Configure MSI capability structure */ - ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI); + ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI); if (ret) { msi_free_irqs(dev); return ret; @@ -476,26 +444,28 @@ static int msix_capability_init(struct pci_dev *dev, /* MSI-X Table Initialization */ for (i = 0; i < nvec; i++) { - entry = alloc_msi_entry(); + entry = alloc_msi_entry(dev); if (!entry) break; j = entries[i].entry; - entry->msi_attrib.type = PCI_CAP_ID_MSIX; + entry->msi_attrib.is_msix = 1; entry->msi_attrib.is_64 = 1; entry->msi_attrib.entry_nr = j; - entry->msi_attrib.maskbit = 1; - entry->msi_attrib.masked = 1; entry->msi_attrib.default_irq = dev->irq; entry->msi_attrib.pos = pos; - entry->dev = dev; entry->mask_base = base; + entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); + msix_mask_irq(entry, 1); list_add_tail(&entry->list, &dev->msi_list); } ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX); - if (ret) { + if (ret < 0) { + /* If we had some success report the number of irqs + * we succeeded in setting up. */ int avail = 0; list_for_each_entry(entry, &dev->msi_list, list) { if (entry->irq != 0) { @@ -503,14 +473,13 @@ static int msix_capability_init(struct pci_dev *dev, } } - msi_free_irqs(dev); + if (avail != 0) + ret = avail; + } - /* If we had some success report the number of irqs - * we succeeded in setting up. - */ - if (avail == 0) - avail = ret; - return avail; + if (ret) { + msi_free_irqs(dev); + return ret; } i = 0; @@ -575,39 +544,54 @@ static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type) } /** - * pci_enable_msi - configure device's MSI capability structure - * @dev: pointer to the pci_dev data structure of MSI device function + * pci_enable_msi_block - configure device's MSI capability structure + * @dev: device to configure + * @nvec: number of interrupts to configure * - * Setup the MSI capability structure of device function with - * a single MSI irq upon its software driver call to request for - * MSI mode enabled on its hardware device function. A return of zero - * indicates the successful setup of an entry zero with the new MSI - * irq or non-zero for otherwise. - **/ -int pci_enable_msi(struct pci_dev* dev) + * Allocate IRQs for a device with the MSI capability. + * This function returns a negative errno if an error occurs. If it + * is unable to allocate the number of interrupts requested, it returns + * the number of interrupts it might be able to allocate. If it successfully + * allocates at least the number of interrupts requested, it returns 0 and + * updates the @dev's irq member to the lowest new interrupt number; the + * other interrupt numbers allocated to this device are consecutive. + */ +int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) { - int status; + int status, pos, maxvec; + u16 msgctl; - status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (!pos) + return -EINVAL; + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &msgctl); + maxvec = 1 << ((msgctl & PCI_MSI_FLAGS_QMASK) >> 1); + if (nvec > maxvec) + return maxvec; + + status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSI); if (status) return status; WARN_ON(!!dev->msi_enabled); - /* Check whether driver already requested for MSI-X irqs */ + /* Check whether driver already requested MSI-X irqs */ if (dev->msix_enabled) { dev_info(&dev->dev, "can't enable MSI " "(MSI-X already enabled)\n"); return -EINVAL; } - status = msi_capability_init(dev); + + status = msi_capability_init(dev, nvec); return status; } -EXPORT_SYMBOL(pci_enable_msi); +EXPORT_SYMBOL(pci_enable_msi_block); -void pci_msi_shutdown(struct pci_dev* dev) +void pci_msi_shutdown(struct pci_dev *dev) { - struct msi_desc *entry; + struct msi_desc *desc; + u32 mask; + u16 ctrl; if (!pci_msi_enable || !dev || !dev->msi_enabled) return; @@ -617,19 +601,15 @@ void pci_msi_shutdown(struct pci_dev* dev) dev->msi_enabled = 0; BUG_ON(list_empty(&dev->msi_list)); - entry = list_entry(dev->msi_list.next, struct msi_desc, list); - /* Return the the pci reset with msi irqs unmasked */ - if (entry->msi_attrib.maskbit) { - u32 mask = entry->msi_attrib.maskbits_mask; - struct irq_desc *desc = irq_to_desc(dev->irq); - msi_set_mask_bits(desc, mask, ~mask); - } - if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) - return; + desc = list_first_entry(&dev->msi_list, struct msi_desc, list); + pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl); + mask = msi_capable_mask(ctrl); + msi_mask_irq(desc, mask, ~mask); /* Restore dev->irq to its default pin-assertion irq */ - dev->irq = entry->msi_attrib.default_irq; + dev->irq = desc->msi_attrib.default_irq; } + void pci_disable_msi(struct pci_dev* dev) { struct msi_desc *entry; @@ -640,7 +620,7 @@ void pci_disable_msi(struct pci_dev* dev) pci_msi_shutdown(dev); entry = list_entry(dev->msi_list.next, struct msi_desc, list); - if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) + if (entry->msi_attrib.is_msix) return; msi_free_irqs(dev); @@ -652,14 +632,18 @@ static int msi_free_irqs(struct pci_dev* dev) struct msi_desc *entry, *tmp; list_for_each_entry(entry, &dev->msi_list, list) { - if (entry->irq) - BUG_ON(irq_has_action(entry->irq)); + int i, nvec; + if (!entry->irq) + continue; + nvec = 1 << entry->msi_attrib.multiple; + for (i = 0; i < nvec; i++) + BUG_ON(irq_has_action(entry->irq + i)); } arch_teardown_msi_irqs(dev); list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { - if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) { + if (entry->msi_attrib.is_msix) { writel(1, entry->mask_base + entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); @@ -674,6 +658,23 @@ static int msi_free_irqs(struct pci_dev* dev) return 0; } +/** + * pci_msix_table_size - return the number of device's MSI-X table entries + * @dev: pointer to the pci_dev data structure of MSI-X device function + */ +int pci_msix_table_size(struct pci_dev *dev) +{ + int pos; + u16 control; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (!pos) + return 0; + + pci_read_config_word(dev, msi_control_reg(pos), &control); + return multi_msix_capable(control); +} + /** * pci_enable_msix - configure device's MSI-X capability structure * @dev: pointer to the pci_dev data structure of MSI-X device function @@ -691,9 +692,8 @@ static int msi_free_irqs(struct pci_dev* dev) **/ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) { - int status, pos, nr_entries; + int status, nr_entries; int i, j; - u16 control; if (!entries) return -EINVAL; @@ -702,9 +702,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) if (status) return status; - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - pci_read_config_word(dev, msi_control_reg(pos), &control); - nr_entries = multi_msix_capable(control); + nr_entries = pci_msix_table_size(dev); if (nvec > nr_entries) return -EINVAL; diff --git a/trunk/drivers/pci/msi.h b/trunk/drivers/pci/msi.h index 3898f5237144..71f4df2ef654 100644 --- a/trunk/drivers/pci/msi.h +++ b/trunk/drivers/pci/msi.h @@ -20,14 +20,8 @@ #define msi_mask_bits_reg(base, is64bit) \ ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4) #define msi_disable(control) control &= ~PCI_MSI_FLAGS_ENABLE -#define multi_msi_capable(control) \ - (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1)) -#define multi_msi_enable(control, num) \ - control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE); #define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT)) #define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT)) -#define msi_enable(control, num) multi_msi_enable(control, num); \ - control |= PCI_MSI_FLAGS_ENABLE #define msix_table_offset_reg(base) (base + 0x04) #define msix_pba_offset_reg(base) (base + 0x08) diff --git a/trunk/drivers/pci/pci-acpi.c b/trunk/drivers/pci/pci-acpi.c index deea8a187eb8..fac5eddcefd2 100644 --- a/trunk/drivers/pci/pci-acpi.c +++ b/trunk/drivers/pci/pci-acpi.c @@ -18,221 +18,6 @@ #include #include "pci.h" -struct acpi_osc_data { - acpi_handle handle; - u32 support_set; - u32 control_set; - u32 control_query; - int is_queried; - struct list_head sibiling; -}; -static LIST_HEAD(acpi_osc_data_list); - -struct acpi_osc_args { - u32 capbuf[3]; -}; - -static DEFINE_MUTEX(pci_acpi_lock); - -static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) -{ - struct acpi_osc_data *data; - - list_for_each_entry(data, &acpi_osc_data_list, sibiling) { - if (data->handle == handle) - return data; - } - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return NULL; - INIT_LIST_HEAD(&data->sibiling); - data->handle = handle; - list_add_tail(&data->sibiling, &acpi_osc_data_list); - return data; -} - -static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, - 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; - -static acpi_status acpi_run_osc(acpi_handle handle, - struct acpi_osc_args *osc_args, u32 *retval) -{ - acpi_status status; - struct acpi_object_list input; - union acpi_object in_params[4]; - struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; - union acpi_object *out_obj; - u32 errors, flags = osc_args->capbuf[OSC_QUERY_TYPE]; - - /* Setting up input parameters */ - input.count = 4; - input.pointer = in_params; - in_params[0].type = ACPI_TYPE_BUFFER; - in_params[0].buffer.length = 16; - in_params[0].buffer.pointer = OSC_UUID; - in_params[1].type = ACPI_TYPE_INTEGER; - in_params[1].integer.value = 1; - in_params[2].type = ACPI_TYPE_INTEGER; - in_params[2].integer.value = 3; - in_params[3].type = ACPI_TYPE_BUFFER; - in_params[3].buffer.length = 12; - in_params[3].buffer.pointer = (u8 *)osc_args->capbuf; - - status = acpi_evaluate_object(handle, "_OSC", &input, &output); - if (ACPI_FAILURE(status)) - return status; - - if (!output.length) - return AE_NULL_OBJECT; - - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_BUFFER) { - printk(KERN_DEBUG "Evaluate _OSC returns wrong type\n"); - status = AE_TYPE; - goto out_kfree; - } - /* Need to ignore the bit0 in result code */ - errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); - if (errors) { - if (errors & OSC_REQUEST_ERROR) - printk(KERN_DEBUG "_OSC request fails\n"); - if (errors & OSC_INVALID_UUID_ERROR) - printk(KERN_DEBUG "_OSC invalid UUID\n"); - if (errors & OSC_INVALID_REVISION_ERROR) - printk(KERN_DEBUG "_OSC invalid revision\n"); - if (errors & OSC_CAPABILITIES_MASK_ERROR) { - if (flags & OSC_QUERY_ENABLE) - goto out_success; - printk(KERN_DEBUG "_OSC FW not grant req. control\n"); - status = AE_SUPPORT; - goto out_kfree; - } - status = AE_ERROR; - goto out_kfree; - } -out_success: - *retval = *((u32 *)(out_obj->buffer.pointer + 8)); - status = AE_OK; - -out_kfree: - kfree(output.pointer); - return status; -} - -static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data) -{ - acpi_status status; - u32 support_set, result; - struct acpi_osc_args osc_args; - - /* do _OSC query for all possible controls */ - support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS); - osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; - osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; - osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; - - status = acpi_run_osc(osc_data->handle, &osc_args, &result); - if (ACPI_SUCCESS(status)) { - osc_data->support_set = support_set; - osc_data->control_query = result; - osc_data->is_queried = 1; - } - - return status; -} - -/* - * pci_acpi_osc_support: Invoke _OSC indicating support for the given feature - * @flags: Bitmask of flags to support - * - * See the ACPI spec for the definition of the flags - */ -int pci_acpi_osc_support(acpi_handle handle, u32 flags) -{ - acpi_status status; - acpi_handle tmp; - struct acpi_osc_data *osc_data; - int rc = 0; - - status = acpi_get_handle(handle, "_OSC", &tmp); - if (ACPI_FAILURE(status)) - return -ENOTTY; - - mutex_lock(&pci_acpi_lock); - osc_data = acpi_get_osc_data(handle); - if (!osc_data) { - printk(KERN_ERR "acpi osc data array is full\n"); - rc = -ENOMEM; - goto out; - } - - __acpi_query_osc(flags, osc_data); -out: - mutex_unlock(&pci_acpi_lock); - return rc; -} - -/** - * pci_osc_control_set - commit requested control to Firmware - * @handle: acpi_handle for the target ACPI object - * @flags: driver's requested control bits - * - * Attempt to take control from Firmware on requested control bits. - **/ -acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) -{ - acpi_status status; - u32 control_req, control_set, result; - acpi_handle tmp; - struct acpi_osc_data *osc_data; - struct acpi_osc_args osc_args; - - status = acpi_get_handle(handle, "_OSC", &tmp); - if (ACPI_FAILURE(status)) - return status; - - mutex_lock(&pci_acpi_lock); - osc_data = acpi_get_osc_data(handle); - if (!osc_data) { - printk(KERN_ERR "acpi osc data array is full\n"); - status = AE_ERROR; - goto out; - } - - control_req = (flags & OSC_CONTROL_MASKS); - if (!control_req) { - status = AE_TYPE; - goto out; - } - - /* No need to evaluate _OSC if the control was already granted. */ - if ((osc_data->control_set & control_req) == control_req) - goto out; - - if (!osc_data->is_queried) { - status = __acpi_query_osc(osc_data->support_set, osc_data); - if (ACPI_FAILURE(status)) - goto out; - } - - if ((osc_data->control_query & control_req) != control_req) { - status = AE_SUPPORT; - goto out; - } - - control_set = osc_data->control_set | control_req; - osc_args.capbuf[OSC_QUERY_TYPE] = 0; - osc_args.capbuf[OSC_SUPPORT_TYPE] = osc_data->support_set; - osc_args.capbuf[OSC_CONTROL_TYPE] = control_set; - status = acpi_run_osc(handle, &osc_args, &result); - if (ACPI_SUCCESS(status)) - osc_data->control_set = result; -out: - mutex_unlock(&pci_acpi_lock); - return status; -} -EXPORT_SYMBOL(pci_osc_control_set); - /* * _SxD returns the D-state with the highest power * (lowest D-state number) supported in the S-state "x". diff --git a/trunk/drivers/pci/pci-driver.c b/trunk/drivers/pci/pci-driver.c index 267de88551c9..c0cbbb5a245e 100644 --- a/trunk/drivers/pci/pci-driver.c +++ b/trunk/drivers/pci/pci-driver.c @@ -99,6 +99,52 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count) } static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); +/** + * store_remove_id - remove a PCI device ID from this driver + * @driver: target device driver + * @buf: buffer for scanning device ID data + * @count: input size + * + * Removes a dynamic pci device ID to this driver. + */ +static ssize_t +store_remove_id(struct device_driver *driver, const char *buf, size_t count) +{ + struct pci_dynid *dynid, *n; + struct pci_driver *pdrv = to_pci_driver(driver); + __u32 vendor, device, subvendor = PCI_ANY_ID, + subdevice = PCI_ANY_ID, class = 0, class_mask = 0; + int fields = 0; + int retval = -ENODEV; + + fields = sscanf(buf, "%x %x %x %x %x %x", + &vendor, &device, &subvendor, &subdevice, + &class, &class_mask); + if (fields < 2) + return -EINVAL; + + spin_lock(&pdrv->dynids.lock); + list_for_each_entry_safe(dynid, n, &pdrv->dynids.list, node) { + struct pci_device_id *id = &dynid->id; + if ((id->vendor == vendor) && + (id->device == device) && + (subvendor == PCI_ANY_ID || id->subvendor == subvendor) && + (subdevice == PCI_ANY_ID || id->subdevice == subdevice) && + !((id->class ^ class) & class_mask)) { + list_del(&dynid->node); + kfree(dynid); + retval = 0; + break; + } + } + spin_unlock(&pdrv->dynids.lock); + + if (retval) + return retval; + return count; +} +static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); + static void pci_free_dynids(struct pci_driver *drv) { @@ -125,6 +171,20 @@ static void pci_remove_newid_file(struct pci_driver *drv) { driver_remove_file(&drv->driver, &driver_attr_new_id); } + +static int +pci_create_removeid_file(struct pci_driver *drv) +{ + int error = 0; + if (drv->probe != NULL) + error = driver_create_file(&drv->driver,&driver_attr_remove_id); + return error; +} + +static void pci_remove_removeid_file(struct pci_driver *drv) +{ + driver_remove_file(&drv->driver, &driver_attr_remove_id); +} #else /* !CONFIG_HOTPLUG */ static inline void pci_free_dynids(struct pci_driver *drv) {} static inline int pci_create_newid_file(struct pci_driver *drv) @@ -132,6 +192,11 @@ static inline int pci_create_newid_file(struct pci_driver *drv) return 0; } static inline void pci_remove_newid_file(struct pci_driver *drv) {} +static inline int pci_create_removeid_file(struct pci_driver *drv) +{ + return 0; +} +static inline void pci_remove_removeid_file(struct pci_driver *drv) {} #endif /** @@ -899,13 +964,23 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, /* register with core */ error = driver_register(&drv->driver); if (error) - return error; + goto out; error = pci_create_newid_file(drv); if (error) - driver_unregister(&drv->driver); + goto out_newid; + error = pci_create_removeid_file(drv); + if (error) + goto out_removeid; +out: return error; + +out_removeid: + pci_remove_newid_file(drv); +out_newid: + driver_unregister(&drv->driver); + goto out; } /** @@ -921,6 +996,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, void pci_unregister_driver(struct pci_driver *drv) { + pci_remove_removeid_file(drv); pci_remove_newid_file(drv); driver_unregister(&drv->driver); pci_free_dynids(drv); @@ -1020,6 +1096,7 @@ struct bus_type pci_bus_type = { .remove = pci_device_remove, .shutdown = pci_device_shutdown, .dev_attrs = pci_dev_attrs, + .bus_attrs = pci_bus_attrs, .pm = PCI_PM_OPS_PTR, }; diff --git a/trunk/drivers/pci/pci-sysfs.c b/trunk/drivers/pci/pci-sysfs.c index dfc4e0ddf241..e9a8706a6401 100644 --- a/trunk/drivers/pci/pci-sysfs.c +++ b/trunk/drivers/pci/pci-sysfs.c @@ -219,6 +219,83 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, return count; } +#ifdef CONFIG_HOTPLUG +static DEFINE_MUTEX(pci_remove_rescan_mutex); +static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, + size_t count) +{ + unsigned long val; + struct pci_bus *b = NULL; + + if (strict_strtoul(buf, 0, &val) < 0) + return -EINVAL; + + if (val) { + mutex_lock(&pci_remove_rescan_mutex); + while ((b = pci_find_next_bus(b)) != NULL) + pci_rescan_bus(b); + mutex_unlock(&pci_remove_rescan_mutex); + } + return count; +} + +struct bus_attribute pci_bus_attrs[] = { + __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, bus_rescan_store), + __ATTR_NULL +}; + +static ssize_t +dev_rescan_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long val; + struct pci_dev *pdev = to_pci_dev(dev); + + if (strict_strtoul(buf, 0, &val) < 0) + return -EINVAL; + + if (val) { + mutex_lock(&pci_remove_rescan_mutex); + pci_rescan_bus(pdev->bus); + mutex_unlock(&pci_remove_rescan_mutex); + } + return count; +} + +static void remove_callback(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + mutex_lock(&pci_remove_rescan_mutex); + pci_remove_bus_device(pdev); + mutex_unlock(&pci_remove_rescan_mutex); +} + +static ssize_t +remove_store(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) +{ + int ret = 0; + unsigned long val; + struct pci_dev *pdev = to_pci_dev(dev); + + if (strict_strtoul(buf, 0, &val) < 0) + return -EINVAL; + + if (pci_is_root_bus(pdev->bus)) + return -EBUSY; + + /* An attribute cannot be unregistered by one of its own methods, + * so we have to use this roundabout approach. + */ + if (val) + ret = device_schedule_callback(dev, remove_callback); + if (ret) + count = ret; + return count; +} +#endif + struct device_attribute pci_dev_attrs[] = { __ATTR_RO(resource), __ATTR_RO(vendor), @@ -237,9 +314,24 @@ struct device_attribute pci_dev_attrs[] = { __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), broken_parity_status_show,broken_parity_status_store), __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), +#ifdef CONFIG_HOTPLUG + __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store), + __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store), +#endif __ATTR_NULL, }; +static ssize_t +boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return sprintf(buf, "%u\n", + !!(pdev->resource[PCI_ROM_RESOURCE].flags & + IORESOURCE_ROM_SHADOW)); +} +struct device_attribute vga_attr = __ATTR_RO(boot_vga); + static ssize_t pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) @@ -492,6 +584,19 @@ pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr, return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io); } +/** + * pci_adjust_legacy_attr - adjustment of legacy file attributes + * @b: bus to create files under + * @mmap_type: I/O port or memory + * + * Stub implementation. Can be overridden by arch if necessary. + */ +void __weak +pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type) +{ + return; +} + /** * pci_create_legacy_files - create legacy I/O port and memory files * @b: bus to create files under @@ -518,6 +623,7 @@ void pci_create_legacy_files(struct pci_bus *b) b->legacy_io->read = pci_read_legacy_io; b->legacy_io->write = pci_write_legacy_io; b->legacy_io->mmap = pci_mmap_legacy_io; + pci_adjust_legacy_attr(b, pci_mmap_io); error = device_create_bin_file(&b->dev, b->legacy_io); if (error) goto legacy_io_err; @@ -528,6 +634,7 @@ void pci_create_legacy_files(struct pci_bus *b) b->legacy_mem->size = 1024*1024; b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR; b->legacy_mem->mmap = pci_mmap_legacy_mem; + pci_adjust_legacy_attr(b, pci_mmap_mem); error = device_create_bin_file(&b->dev, b->legacy_mem); if (error) goto legacy_mem_err; @@ -719,8 +826,8 @@ static int pci_create_resource_files(struct pci_dev *pdev) return 0; } #else /* !HAVE_PCI_MMAP */ -static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; } -static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } +int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; } +void __weak pci_remove_resource_files(struct pci_dev *dev) { return; } #endif /* HAVE_PCI_MMAP */ /** @@ -884,18 +991,27 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) pdev->rom_attr = attr; } + if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { + retval = device_create_file(&pdev->dev, &vga_attr); + if (retval) + goto err_rom_file; + } + /* add platform-specific attributes */ retval = pcibios_add_platform_entries(pdev); if (retval) - goto err_rom_file; + goto err_vga_file; /* add sysfs entries for various capabilities */ retval = pci_create_capabilities_sysfs(pdev); if (retval) - goto err_rom_file; + goto err_vga_file; return 0; +err_vga_file: + if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) + device_remove_file(&pdev->dev, &vga_attr); err_rom_file: if (rom_size) { sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index 0195066251e5..fe7ac2cea7c9 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -20,6 +20,8 @@ #include #include #include /* isa_dma_bridge_buggy */ +#include +#include #include "pci.h" unsigned int pci_pm_d3_delay = PCI_PM_D3_WAIT; @@ -677,6 +679,8 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) EXPORT_SYMBOL(pci_choose_state); +#define PCI_EXP_SAVE_REGS 7 + static int pci_save_pcie_state(struct pci_dev *dev) { int pos, i = 0; @@ -689,7 +693,7 @@ static int pci_save_pcie_state(struct pci_dev *dev) save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); if (!save_state) { - dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__); + dev_err(&dev->dev, "buffer not found in %s\n", __func__); return -ENOMEM; } cap = (u16 *)&save_state->data[0]; @@ -698,6 +702,9 @@ static int pci_save_pcie_state(struct pci_dev *dev) pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &cap[i++]); + pci_read_config_word(dev, pos + PCI_EXP_LNKCTL2, &cap[i++]); + pci_read_config_word(dev, pos + PCI_EXP_SLTCTL2, &cap[i++]); return 0; } @@ -718,6 +725,9 @@ static void pci_restore_pcie_state(struct pci_dev *dev) pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]); pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]); pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]); + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, cap[i++]); + pci_write_config_word(dev, pos + PCI_EXP_LNKCTL2, cap[i++]); + pci_write_config_word(dev, pos + PCI_EXP_SLTCTL2, cap[i++]); } @@ -732,7 +742,7 @@ static int pci_save_pcix_state(struct pci_dev *dev) save_state = pci_find_saved_cap(dev, PCI_CAP_ID_PCIX); if (!save_state) { - dev_err(&dev->dev, "buffer not found in %s\n", __FUNCTION__); + dev_err(&dev->dev, "buffer not found in %s\n", __func__); return -ENOMEM; } @@ -805,6 +815,7 @@ pci_restore_state(struct pci_dev *dev) } pci_restore_pcix_state(dev); pci_restore_msi_state(dev); + pci_restore_iov_state(dev); return 0; } @@ -1401,7 +1412,8 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev) { int error; - error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP, 4 * sizeof(u16)); + error = pci_add_cap_save_buffer(dev, PCI_CAP_ID_EXP, + PCI_EXP_SAVE_REGS * sizeof(u16)); if (error) dev_err(&dev->dev, "unable to preallocate PCI Express save buffer\n"); @@ -1472,7 +1484,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) if (!pin) return -1; - while (dev->bus->self) { + while (dev->bus->parent) { pin = pci_swizzle_interrupt_pin(dev, pin); dev = dev->bus->self; } @@ -1492,7 +1504,7 @@ u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) { u8 pin = *pinp; - while (dev->bus->self) { + while (dev->bus->parent) { pin = pci_swizzle_interrupt_pin(dev, pin); dev = dev->bus->self; } @@ -2016,18 +2028,24 @@ static int __pcie_flr(struct pci_dev *dev, int probe) pci_block_user_cfg_access(dev); /* Wait for Transaction Pending bit clean */ + pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); + if (!(status & PCI_EXP_DEVSTA_TRPND)) + goto transaction_done; + msleep(100); pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); - if (status & PCI_EXP_DEVSTA_TRPND) { - dev_info(&dev->dev, "Busy after 100ms while trying to reset; " + if (!(status & PCI_EXP_DEVSTA_TRPND)) + goto transaction_done; + + dev_info(&dev->dev, "Busy after 100ms while trying to reset; " "sleeping for 1 second\n"); - ssleep(1); - pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); - if (status & PCI_EXP_DEVSTA_TRPND) - dev_info(&dev->dev, "Still busy after 1s; " + ssleep(1); + pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); + if (status & PCI_EXP_DEVSTA_TRPND) + dev_info(&dev->dev, "Still busy after 1s; " "proceeding with reset anyway\n"); - } +transaction_done: pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR); mdelay(100); @@ -2054,18 +2072,24 @@ static int __pci_af_flr(struct pci_dev *dev, int probe) pci_block_user_cfg_access(dev); /* Wait for Transaction Pending bit clean */ + pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); + if (!(status & PCI_AF_STATUS_TP)) + goto transaction_done; + msleep(100); pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); - if (status & PCI_AF_STATUS_TP) { - dev_info(&dev->dev, "Busy after 100ms while trying to" - " reset; sleeping for 1 second\n"); - ssleep(1); - pci_read_config_byte(dev, - cappos + PCI_AF_STATUS, &status); - if (status & PCI_AF_STATUS_TP) - dev_info(&dev->dev, "Still busy after 1s; " - "proceeding with reset anyway\n"); - } + if (!(status & PCI_AF_STATUS_TP)) + goto transaction_done; + + dev_info(&dev->dev, "Busy after 100ms while trying to" + " reset; sleeping for 1 second\n"); + ssleep(1); + pci_read_config_byte(dev, cappos + PCI_AF_STATUS, &status); + if (status & PCI_AF_STATUS_TP) + dev_info(&dev->dev, "Still busy after 1s; " + "proceeding with reset anyway\n"); + +transaction_done: pci_write_config_byte(dev, cappos + PCI_AF_CTRL, PCI_AF_CTRL_FLR); mdelay(100); @@ -2334,18 +2358,140 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags) */ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type) { + int reg; + if (resno < PCI_ROM_RESOURCE) { *type = pci_bar_unknown; return PCI_BASE_ADDRESS_0 + 4 * resno; } else if (resno == PCI_ROM_RESOURCE) { *type = pci_bar_mem32; return dev->rom_base_reg; + } else if (resno < PCI_BRIDGE_RESOURCES) { + /* device specific resource */ + reg = pci_iov_resource_bar(dev, resno, type); + if (reg) + return reg; } dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno); return 0; } +#define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE +static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0}; +spinlock_t resource_alignment_lock = SPIN_LOCK_UNLOCKED; + +/** + * pci_specified_resource_alignment - get resource alignment specified by user. + * @dev: the PCI device to get + * + * RETURNS: Resource alignment if it is specified. + * Zero if it is not specified. + */ +resource_size_t pci_specified_resource_alignment(struct pci_dev *dev) +{ + int seg, bus, slot, func, align_order, count; + resource_size_t align = 0; + char *p; + + spin_lock(&resource_alignment_lock); + p = resource_alignment_param; + while (*p) { + count = 0; + if (sscanf(p, "%d%n", &align_order, &count) == 1 && + p[count] == '@') { + p += count + 1; + } else { + align_order = -1; + } + if (sscanf(p, "%x:%x:%x.%x%n", + &seg, &bus, &slot, &func, &count) != 4) { + seg = 0; + if (sscanf(p, "%x:%x.%x%n", + &bus, &slot, &func, &count) != 3) { + /* Invalid format */ + printk(KERN_ERR "PCI: Can't parse resource_alignment parameter: %s\n", + p); + break; + } + } + p += count; + if (seg == pci_domain_nr(dev->bus) && + bus == dev->bus->number && + slot == PCI_SLOT(dev->devfn) && + func == PCI_FUNC(dev->devfn)) { + if (align_order == -1) { + align = PAGE_SIZE; + } else { + align = 1 << align_order; + } + /* Found */ + break; + } + if (*p != ';' && *p != ',') { + /* End of param or invalid format */ + break; + } + p++; + } + spin_unlock(&resource_alignment_lock); + return align; +} + +/** + * pci_is_reassigndev - check if specified PCI is target device to reassign + * @dev: the PCI device to check + * + * RETURNS: non-zero for PCI device is a target device to reassign, + * or zero is not. + */ +int pci_is_reassigndev(struct pci_dev *dev) +{ + return (pci_specified_resource_alignment(dev) != 0); +} + +ssize_t pci_set_resource_alignment_param(const char *buf, size_t count) +{ + if (count > RESOURCE_ALIGNMENT_PARAM_SIZE - 1) + count = RESOURCE_ALIGNMENT_PARAM_SIZE - 1; + spin_lock(&resource_alignment_lock); + strncpy(resource_alignment_param, buf, count); + resource_alignment_param[count] = '\0'; + spin_unlock(&resource_alignment_lock); + return count; +} + +ssize_t pci_get_resource_alignment_param(char *buf, size_t size) +{ + size_t count; + spin_lock(&resource_alignment_lock); + count = snprintf(buf, size, "%s", resource_alignment_param); + spin_unlock(&resource_alignment_lock); + return count; +} + +static ssize_t pci_resource_alignment_show(struct bus_type *bus, char *buf) +{ + return pci_get_resource_alignment_param(buf, PAGE_SIZE); +} + +static ssize_t pci_resource_alignment_store(struct bus_type *bus, + const char *buf, size_t count) +{ + return pci_set_resource_alignment_param(buf, count); +} + +BUS_ATTR(resource_alignment, 0644, pci_resource_alignment_show, + pci_resource_alignment_store); + +static int __init pci_resource_alignment_sysfs_init(void) +{ + return bus_create_file(&pci_bus_type, + &bus_attr_resource_alignment); +} + +late_initcall(pci_resource_alignment_sysfs_init); + static void __devinit pci_no_domains(void) { #ifdef CONFIG_PCI_DOMAINS @@ -2394,6 +2540,9 @@ static int __init pci_setup(char *str) pci_cardbus_io_size = memparse(str + 9, &str); } else if (!strncmp(str, "cbmemsize=", 10)) { pci_cardbus_mem_size = memparse(str + 10, &str); + } else if (!strncmp(str, "resource_alignment=", 19)) { + pci_set_resource_alignment_param(str + 19, + strlen(str + 19)); } else { printk(KERN_ERR "PCI: Unknown option `%s'\n", str); diff --git a/trunk/drivers/pci/pci.h b/trunk/drivers/pci/pci.h index 149fff65891f..d03f6b99f292 100644 --- a/trunk/drivers/pci/pci.h +++ b/trunk/drivers/pci/pci.h @@ -1,6 +1,8 @@ #ifndef DRIVERS_PCI_H #define DRIVERS_PCI_H +#include + #define PCI_CFG_SPACE_SIZE 256 #define PCI_CFG_SPACE_EXP_SIZE 4096 @@ -135,6 +137,12 @@ extern int pcie_mch_quirk; extern struct device_attribute pci_dev_attrs[]; extern struct device_attribute dev_attr_cpuaffinity; extern struct device_attribute dev_attr_cpulistaffinity; +#ifdef CONFIG_HOTPLUG +extern struct bus_attribute pci_bus_attrs[]; +#else +#define pci_bus_attrs NULL +#endif + /** * pci_match_one_device - Tell if a PCI device structure has a matching @@ -177,6 +185,7 @@ enum pci_bar_type { pci_bar_mem64, /* A 64-bit memory BAR */ }; +extern int pci_setup_device(struct pci_dev *dev); extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, struct resource *res, unsigned int reg); extern int pci_resource_bar(struct pci_dev *dev, int resno, @@ -194,4 +203,60 @@ static inline int pci_ari_enabled(struct pci_bus *bus) return bus->self && bus->self->ari_enabled; } +#ifdef CONFIG_PCI_QUIRKS +extern int pci_is_reassigndev(struct pci_dev *dev); +resource_size_t pci_specified_resource_alignment(struct pci_dev *dev); +extern void pci_disable_bridge_window(struct pci_dev *dev); +#endif + +/* Single Root I/O Virtualization */ +struct pci_sriov { + int pos; /* capability position */ + int nres; /* number of resources */ + u32 cap; /* SR-IOV Capabilities */ + u16 ctrl; /* SR-IOV Control */ + u16 total; /* total VFs associated with the PF */ + u16 initial; /* initial VFs associated with the PF */ + u16 nr_virtfn; /* number of VFs available */ + u16 offset; /* first VF Routing ID offset */ + u16 stride; /* following VF stride */ + u32 pgsz; /* page size for BAR alignment */ + u8 link; /* Function Dependency Link */ + struct pci_dev *dev; /* lowest numbered PF */ + struct pci_dev *self; /* this PF */ + struct mutex lock; /* lock for VF bus */ + struct work_struct mtask; /* VF Migration task */ + u8 __iomem *mstate; /* VF Migration State Array */ +}; + +#ifdef CONFIG_PCI_IOV +extern int pci_iov_init(struct pci_dev *dev); +extern void pci_iov_release(struct pci_dev *dev); +extern int pci_iov_resource_bar(struct pci_dev *dev, int resno, + enum pci_bar_type *type); +extern void pci_restore_iov_state(struct pci_dev *dev); +extern int pci_iov_bus_range(struct pci_bus *bus); +#else +static inline int pci_iov_init(struct pci_dev *dev) +{ + return -ENODEV; +} +static inline void pci_iov_release(struct pci_dev *dev) + +{ +} +static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno, + enum pci_bar_type *type) +{ + return 0; +} +static inline void pci_restore_iov_state(struct pci_dev *dev) +{ +} +static inline int pci_iov_bus_range(struct pci_bus *bus) +{ + return 0; +} +#endif /* CONFIG_PCI_IOV */ + #endif /* DRIVERS_PCI_H */ diff --git a/trunk/drivers/pci/pcie/aer/aerdrv.c b/trunk/drivers/pci/pcie/aer/aerdrv.c index e390707661dd..32ade5af927e 100644 --- a/trunk/drivers/pci/pcie/aer/aerdrv.c +++ b/trunk/drivers/pci/pcie/aer/aerdrv.c @@ -38,30 +38,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -static int __devinit aer_probe (struct pcie_device *dev, - const struct pcie_port_service_id *id ); +static int __devinit aer_probe (struct pcie_device *dev); static void aer_remove(struct pcie_device *dev); -static int aer_suspend(struct pcie_device *dev, pm_message_t state) -{return 0;} -static int aer_resume(struct pcie_device *dev) {return 0;} static pci_ers_result_t aer_error_detected(struct pci_dev *dev, enum pci_channel_state error); static void aer_error_resume(struct pci_dev *dev); static pci_ers_result_t aer_root_reset(struct pci_dev *dev); -/* - * PCI Express bus's AER Root service driver data structure - */ -static struct pcie_port_service_id aer_id[] = { - { - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .port_type = PCIE_RC_PORT, - .service_type = PCIE_PORT_SERVICE_AER, - }, - { /* end: all zeroes */ } -}; - static struct pci_error_handlers aer_error_handlers = { .error_detected = aer_error_detected, .resume = aer_error_resume, @@ -69,14 +52,12 @@ static struct pci_error_handlers aer_error_handlers = { static struct pcie_port_service_driver aerdriver = { .name = "aer", - .id_table = &aer_id[0], + .port_type = PCIE_ANY_PORT, + .service = PCIE_PORT_SERVICE_AER, .probe = aer_probe, .remove = aer_remove, - .suspend = aer_suspend, - .resume = aer_resume, - .err_handler = &aer_error_handlers, .reset_link = aer_root_reset, @@ -207,8 +188,7 @@ static void aer_remove(struct pcie_device *dev) * * Invoked when PCI Express bus loads AER service driver. **/ -static int __devinit aer_probe (struct pcie_device *dev, - const struct pcie_port_service_id *id ) +static int __devinit aer_probe (struct pcie_device *dev) { int status; struct aer_rpc *rpc; diff --git a/trunk/drivers/pci/pcie/aer/aerdrv_acpi.c b/trunk/drivers/pci/pcie/aer/aerdrv_acpi.c index ebce26c37049..8edb2f300e8f 100644 --- a/trunk/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/trunk/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -38,7 +38,7 @@ int aer_osc_setup(struct pcie_device *pciedev) handle = acpi_find_root_bridge_handle(pdev); if (handle) { - status = pci_osc_control_set(handle, + status = acpi_pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL | OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); } diff --git a/trunk/drivers/pci/pcie/aer/aerdrv_core.c b/trunk/drivers/pci/pcie/aer/aerdrv_core.c index 382575007382..307452f30035 100644 --- a/trunk/drivers/pci/pcie/aer/aerdrv_core.c +++ b/trunk/drivers/pci/pcie/aer/aerdrv_core.c @@ -351,21 +351,21 @@ static int find_aer_service_iter(struct device *device, void *data) { struct device_driver *driver; struct pcie_port_service_driver *service_driver; - struct pcie_device *pcie_dev; struct find_aer_service_data *result; result = (struct find_aer_service_data *) data; if (device->bus == &pcie_port_bus_type) { - pcie_dev = to_pcie_device(device); - if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT) + struct pcie_port_data *port_data; + + port_data = pci_get_drvdata(to_pcie_device(device)->port); + if (port_data->port_type == PCIE_SW_DOWNSTREAM_PORT) result->is_downstream = 1; driver = device->driver; if (driver) { service_driver = to_service_driver(driver); - if (service_driver->id_table->service_type == - PCIE_PORT_SERVICE_AER) { + if (service_driver->service == PCIE_PORT_SERVICE_AER) { result->aer_driver = service_driver; return 1; } diff --git a/trunk/drivers/pci/pcie/portdrv.h b/trunk/drivers/pci/pcie/portdrv.h index 2529f3f2ea5a..17ad53868f9f 100644 --- a/trunk/drivers/pci/pcie/portdrv.h +++ b/trunk/drivers/pci/pcie/portdrv.h @@ -25,19 +25,21 @@ #define PCIE_CAPABILITIES_REG 0x2 #define PCIE_SLOT_CAPABILITIES_REG 0x14 #define PCIE_PORT_DEVICE_MAXSERVICES 4 +#define PCIE_PORT_MSI_VECTOR_MASK 0x1f +/* + * According to the PCI Express Base Specification 2.0, the indices of the MSI-X + * table entires used by port services must not exceed 31 + */ +#define PCIE_PORT_MAX_MSIX_ENTRIES 32 #define get_descriptor_id(type, service) (((type - 4) << 4) | service) -struct pcie_port_device_ext { - int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */ -}; - extern struct bus_type pcie_port_bus_type; extern int pcie_port_device_probe(struct pci_dev *dev); extern int pcie_port_device_register(struct pci_dev *dev); #ifdef CONFIG_PM -extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state); -extern int pcie_port_device_resume(struct pci_dev *dev); +extern int pcie_port_device_suspend(struct device *dev); +extern int pcie_port_device_resume(struct device *dev); #endif extern void pcie_port_device_remove(struct pci_dev *dev); extern int __must_check pcie_port_bus_register(void); diff --git a/trunk/drivers/pci/pcie/portdrv_bus.c b/trunk/drivers/pci/pcie/portdrv_bus.c index eec89b767f9f..ef3a4eeaebb4 100644 --- a/trunk/drivers/pci/pcie/portdrv_bus.c +++ b/trunk/drivers/pci/pcie/portdrv_bus.c @@ -26,20 +26,22 @@ EXPORT_SYMBOL_GPL(pcie_port_bus_type); static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) { struct pcie_device *pciedev; + struct pcie_port_data *port_data; struct pcie_port_service_driver *driver; if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) return 0; - + pciedev = to_pcie_device(dev); driver = to_service_driver(drv); - if ( (driver->id_table->vendor != PCI_ANY_ID && - driver->id_table->vendor != pciedev->id.vendor) || - (driver->id_table->device != PCI_ANY_ID && - driver->id_table->device != pciedev->id.device) || - (driver->id_table->port_type != PCIE_ANY_PORT && - driver->id_table->port_type != pciedev->id.port_type) || - driver->id_table->service_type != pciedev->id.service_type ) + + if (driver->service != pciedev->service) + return 0; + + port_data = pci_get_drvdata(pciedev->port); + + if (driver->port_type != PCIE_ANY_PORT + && driver->port_type != port_data->port_type) return 0; return 1; diff --git a/trunk/drivers/pci/pcie/portdrv_core.c b/trunk/drivers/pci/pcie/portdrv_core.c index 8b3f8c18032f..e39982503863 100644 --- a/trunk/drivers/pci/pcie/portdrv_core.c +++ b/trunk/drivers/pci/pcie/portdrv_core.c @@ -15,10 +15,9 @@ #include #include +#include "../pci.h" #include "portdrv.h" -extern int pcie_mch_quirk; /* MSI-quirk Indicator */ - /** * release_pcie_device - free PCI Express port service device structure * @dev: Port service device to release @@ -31,26 +30,150 @@ static void release_pcie_device(struct device *dev) kfree(to_pcie_device(dev)); } -static int is_msi_quirked(struct pci_dev *dev) +/** + * pcie_port_msix_add_entry - add entry to given array of MSI-X entries + * @entries: Array of MSI-X entries + * @new_entry: Index of the entry to add to the array + * @nr_entries: Number of entries aleady in the array + * + * Return value: Position of the added entry in the array + */ +static int pcie_port_msix_add_entry( + struct msix_entry *entries, int new_entry, int nr_entries) { - int port_type, quirk = 0; + int j; + + for (j = 0; j < nr_entries; j++) + if (entries[j].entry == new_entry) + return j; + + entries[j].entry = new_entry; + return j; +} + +/** + * pcie_port_enable_msix - try to set up MSI-X as interrupt mode for given port + * @dev: PCI Express port to handle + * @vectors: Array of interrupt vectors to populate + * @mask: Bitmask of port capabilities returned by get_port_device_capability() + * + * Return value: 0 on success, error code on failure + */ +static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask) +{ + struct msix_entry *msix_entries; + int idx[PCIE_PORT_DEVICE_MAXSERVICES]; + int nr_entries, status, pos, i, nvec; u16 reg16; + u32 reg32; - pci_read_config_word(dev, - pci_find_capability(dev, PCI_CAP_ID_EXP) + - PCIE_CAPABILITIES_REG, ®16); - port_type = (reg16 >> 4) & PORT_TYPE_MASK; - switch(port_type) { - case PCIE_RC_PORT: - if (pcie_mch_quirk == 1) - quirk = 1; - break; - case PCIE_SW_UPSTREAM_PORT: - case PCIE_SW_DOWNSTREAM_PORT: - default: - break; + nr_entries = pci_msix_table_size(dev); + if (!nr_entries) + return -EINVAL; + if (nr_entries > PCIE_PORT_MAX_MSIX_ENTRIES) + nr_entries = PCIE_PORT_MAX_MSIX_ENTRIES; + + msix_entries = kzalloc(sizeof(*msix_entries) * nr_entries, GFP_KERNEL); + if (!msix_entries) + return -ENOMEM; + + /* + * Allocate as many entries as the port wants, so that we can check + * which of them will be useful. Moreover, if nr_entries is correctly + * equal to the number of entries this port actually uses, we'll happily + * go through without any tricks. + */ + for (i = 0; i < nr_entries; i++) + msix_entries[i].entry = i; + + status = pci_enable_msix(dev, msix_entries, nr_entries); + if (status) + goto Exit; + + for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) + idx[i] = -1; + status = -EIO; + nvec = 0; + + if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) { + int entry; + + /* + * The code below follows the PCI Express Base Specification 2.0 + * stating in Section 6.1.6 that "PME and Hot-Plug Event + * interrupts (when both are implemented) always share the same + * MSI or MSI-X vector, as indicated by the Interrupt Message + * Number field in the PCI Express Capabilities register", where + * according to Section 7.8.2 of the specification "For MSI-X, + * the value in this field indicates which MSI-X Table entry is + * used to generate the interrupt message." + */ + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); + pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, ®16); + entry = (reg16 >> 9) & PCIE_PORT_MSI_VECTOR_MASK; + if (entry >= nr_entries) + goto Error; + + i = pcie_port_msix_add_entry(msix_entries, entry, nvec); + if (i == nvec) + nvec++; + + idx[PCIE_PORT_SERVICE_PME_SHIFT] = i; + idx[PCIE_PORT_SERVICE_HP_SHIFT] = i; + } + + if (mask & PCIE_PORT_SERVICE_AER) { + int entry; + + /* + * The code below follows Section 7.10.10 of the PCI Express + * Base Specification 2.0 stating that bits 31-27 of the Root + * Error Status Register contain a value indicating which of the + * MSI/MSI-X vectors assigned to the port is going to be used + * for AER, where "For MSI-X, the value in this register + * indicates which MSI-X Table entry is used to generate the + * interrupt message." + */ + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); + pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32); + entry = reg32 >> 27; + if (entry >= nr_entries) + goto Error; + + i = pcie_port_msix_add_entry(msix_entries, entry, nvec); + if (i == nvec) + nvec++; + + idx[PCIE_PORT_SERVICE_AER_SHIFT] = i; } - return quirk; + + /* + * If nvec is equal to the allocated number of entries, we can just use + * what we have. Otherwise, the port has some extra entries not for the + * services we know and we need to work around that. + */ + if (nvec == nr_entries) { + status = 0; + } else { + /* Drop the temporary MSI-X setup */ + pci_disable_msix(dev); + + /* Now allocate the MSI-X vectors for real */ + status = pci_enable_msix(dev, msix_entries, nvec); + if (status) + goto Exit; + } + + for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) + vectors[i] = idx[i] >= 0 ? msix_entries[idx[i]].vector : -1; + + Exit: + kfree(msix_entries); + return status; + + Error: + pci_disable_msix(dev); + goto Exit; } /** @@ -64,47 +187,32 @@ static int is_msi_quirked(struct pci_dev *dev) */ static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) { - int i, pos, nvec, status = -EINVAL; - int interrupt_mode = PCIE_PORT_INTx_MODE; + struct pcie_port_data *port_data = pci_get_drvdata(dev); + int irq, interrupt_mode = PCIE_PORT_NO_IRQ; + int i; - /* Set INTx as default */ - for (i = 0, nvec = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { - if (mask & (1 << i)) - nvec++; - vectors[i] = dev->irq; - } - /* Check MSI quirk */ - if (is_msi_quirked(dev)) - return interrupt_mode; - - /* Select MSI-X over MSI if supported */ - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos) { - struct msix_entry msix_entries[PCIE_PORT_DEVICE_MAXSERVICES] = - {{0, 0}, {0, 1}, {0, 2}, {0, 3}}; - status = pci_enable_msix(dev, msix_entries, nvec); - if (!status) { - int j = 0; - - interrupt_mode = PCIE_PORT_MSIX_MODE; - for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { - if (mask & (1 << i)) - vectors[i] = msix_entries[j++].vector; - } - } - } - if (status) { - pos = pci_find_capability(dev, PCI_CAP_ID_MSI); - if (pos) { - status = pci_enable_msi(dev); - if (!status) { - interrupt_mode = PCIE_PORT_MSI_MODE; - for (i = 0;i < PCIE_PORT_DEVICE_MAXSERVICES;i++) - vectors[i] = dev->irq; - } - } - } + if (port_data->port_type == PCIE_RC_PORT && pcie_mch_quirk) + goto Fallback; + + /* Try to use MSI-X if supported */ + if (!pcie_port_enable_msix(dev, vectors, mask)) + return PCIE_PORT_MSIX_MODE; + + /* We're not going to use MSI-X, so try MSI and fall back to INTx */ + if (!pci_enable_msi(dev)) + interrupt_mode = PCIE_PORT_MSI_MODE; + + Fallback: + if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin) + interrupt_mode = PCIE_PORT_INTx_MODE; + + irq = interrupt_mode != PCIE_PORT_NO_IRQ ? dev->irq : -1; + for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) + vectors[i] = irq; + + vectors[PCIE_PORT_SERVICE_VC_SHIFT] = -1; + return interrupt_mode; } @@ -132,13 +240,11 @@ static int get_port_device_capability(struct pci_dev *dev) pos + PCIE_SLOT_CAPABILITIES_REG, ®32); if (reg32 & SLOT_HP_CAPABLE_MASK) services |= PCIE_PORT_SERVICE_HP; - } - /* PME Capable - root port capability */ - if (((reg16 >> 4) & PORT_TYPE_MASK) == PCIE_RC_PORT) - services |= PCIE_PORT_SERVICE_PME; - + } + /* AER capable */ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR)) services |= PCIE_PORT_SERVICE_AER; + /* VC support */ if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) services |= PCIE_PORT_SERVICE_VC; @@ -152,20 +258,17 @@ static int get_port_device_capability(struct pci_dev *dev) * @port_type: Type of the port * @service_type: Type of service to associate with the service device * @irq: Interrupt vector to associate with the service device - * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI) */ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, - int port_type, int service_type, int irq, int irq_mode) + int service_type, int irq) { + struct pcie_port_data *port_data = pci_get_drvdata(parent); struct device *device; + int port_type = port_data->port_type; dev->port = parent; - dev->interrupt_mode = irq_mode; dev->irq = irq; - dev->id.vendor = parent->vendor; - dev->id.device = parent->device; - dev->id.port_type = port_type; - dev->id.service_type = (1 << service_type); + dev->service = service_type; /* Initialize generic device interface */ device = &dev->device; @@ -185,10 +288,9 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, * @port_type: Type of the port * @service_type: Type of service to associate with the service device * @irq: Interrupt vector to associate with the service device - * @irq_mode: Interrupt mode of the service (INTx, MSI-X, MSI) */ static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, - int port_type, int service_type, int irq, int irq_mode) + int service_type, int irq) { struct pcie_device *device; @@ -196,7 +298,7 @@ static struct pcie_device* alloc_pcie_device(struct pci_dev *parent, if (!device) return NULL; - pcie_device_init(parent, device, port_type, service_type, irq,irq_mode); + pcie_device_init(parent, device, service_type, irq); return device; } @@ -230,63 +332,90 @@ int pcie_port_device_probe(struct pci_dev *dev) */ int pcie_port_device_register(struct pci_dev *dev) { - struct pcie_port_device_ext *p_ext; - int status, type, capabilities, irq_mode, i; + struct pcie_port_data *port_data; + int status, capabilities, irq_mode, i, nr_serv; int vectors[PCIE_PORT_DEVICE_MAXSERVICES]; u16 reg16; - /* Allocate port device extension */ - if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL))) + port_data = kzalloc(sizeof(*port_data), GFP_KERNEL); + if (!port_data) return -ENOMEM; - - pci_set_drvdata(dev, p_ext); + pci_set_drvdata(dev, port_data); /* Get port type */ pci_read_config_word(dev, pci_find_capability(dev, PCI_CAP_ID_EXP) + PCIE_CAPABILITIES_REG, ®16); - type = (reg16 >> 4) & PORT_TYPE_MASK; + port_data->port_type = (reg16 >> 4) & PORT_TYPE_MASK; - /* Now get port services */ capabilities = get_port_device_capability(dev); + /* Root ports are capable of generating PME too */ + if (port_data->port_type == PCIE_RC_PORT) + capabilities |= PCIE_PORT_SERVICE_PME; + irq_mode = assign_interrupt_mode(dev, vectors, capabilities); - p_ext->interrupt_mode = irq_mode; + if (irq_mode == PCIE_PORT_NO_IRQ) { + /* + * Don't use service devices that require interrupts if there is + * no way to generate them. + */ + if (!(capabilities & PCIE_PORT_SERVICE_VC)) { + status = -ENODEV; + goto Error; + } + capabilities = PCIE_PORT_SERVICE_VC; + } + port_data->port_irq_mode = irq_mode; + + status = pci_enable_device(dev); + if (status) + goto Error; + pci_set_master(dev); /* Allocate child services if any */ - for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { + for (i = 0, nr_serv = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { struct pcie_device *child; + int service = 1 << i; + + if (!(capabilities & service)) + continue; - if (capabilities & (1 << i)) { - child = alloc_pcie_device( - dev, /* parent */ - type, /* port type */ - i, /* service type */ - vectors[i], /* irq */ - irq_mode /* interrupt mode */); - if (child) { - status = device_register(&child->device); - if (status) { - kfree(child); - continue; - } - get_device(&child->device); - } + child = alloc_pcie_device(dev, service, vectors[i]); + if (!child) + continue; + + status = device_register(&child->device); + if (status) { + kfree(child); + continue; } + + get_device(&child->device); + nr_serv++; + } + if (!nr_serv) { + pci_disable_device(dev); + status = -ENODEV; + goto Error; } + return 0; + + Error: + kfree(port_data); + return status; } #ifdef CONFIG_PM static int suspend_iter(struct device *dev, void *data) { struct pcie_port_service_driver *service_driver; - pm_message_t state = * (pm_message_t *) data; if ((dev->bus == &pcie_port_bus_type) && (dev->driver)) { service_driver = to_service_driver(dev->driver); if (service_driver->suspend) - service_driver->suspend(to_pcie_device(dev), state); + service_driver->suspend(to_pcie_device(dev)); } return 0; } @@ -294,11 +423,10 @@ static int suspend_iter(struct device *dev, void *data) /** * pcie_port_device_suspend - suspend port services associated with a PCIe port * @dev: PCI Express port to handle - * @state: Representation of system power management transition in progress */ -int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) +int pcie_port_device_suspend(struct device *dev) { - return device_for_each_child(&dev->dev, &state, suspend_iter); + return device_for_each_child(dev, NULL, suspend_iter); } static int resume_iter(struct device *dev, void *data) @@ -318,24 +446,17 @@ static int resume_iter(struct device *dev, void *data) * pcie_port_device_suspend - resume port services associated with a PCIe port * @dev: PCI Express port to handle */ -int pcie_port_device_resume(struct pci_dev *dev) +int pcie_port_device_resume(struct device *dev) { - return device_for_each_child(&dev->dev, NULL, resume_iter); + return device_for_each_child(dev, NULL, resume_iter); } -#endif +#endif /* PM */ static int remove_iter(struct device *dev, void *data) { - struct pcie_port_service_driver *service_driver; - if (dev->bus == &pcie_port_bus_type) { - if (dev->driver) { - service_driver = to_service_driver(dev->driver); - if (service_driver->remove) - service_driver->remove(to_pcie_device(dev)); - } - *(unsigned long*)data = (unsigned long)dev; - return 1; + put_device(dev); + device_unregister(dev); } return 0; } @@ -349,25 +470,21 @@ static int remove_iter(struct device *dev, void *data) */ void pcie_port_device_remove(struct pci_dev *dev) { - struct device *device; - unsigned long device_addr; - int interrupt_mode = PCIE_PORT_INTx_MODE; - int status; + struct pcie_port_data *port_data = pci_get_drvdata(dev); - do { - status = device_for_each_child(&dev->dev, &device_addr, remove_iter); - if (status) { - device = (struct device*)device_addr; - interrupt_mode = (to_pcie_device(device))->interrupt_mode; - put_device(device); - device_unregister(device); - } - } while (status); - /* Switch to INTx by default if MSI enabled */ - if (interrupt_mode == PCIE_PORT_MSIX_MODE) + device_for_each_child(&dev->dev, NULL, remove_iter); + pci_disable_device(dev); + + switch (port_data->port_irq_mode) { + case PCIE_PORT_MSIX_MODE: pci_disable_msix(dev); - else if (interrupt_mode == PCIE_PORT_MSI_MODE) + break; + case PCIE_PORT_MSI_MODE: pci_disable_msi(dev); + break; + } + + kfree(port_data); } /** @@ -392,7 +509,7 @@ static int pcie_port_probe_service(struct device *dev) return -ENODEV; pciedev = to_pcie_device(dev); - status = driver->probe(pciedev, driver->id_table); + status = driver->probe(pciedev); if (!status) { dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n", driver->name); diff --git a/trunk/drivers/pci/pcie/portdrv_pci.c b/trunk/drivers/pci/pcie/portdrv_pci.c index 5ea566e20b37..b924e2463f85 100644 --- a/trunk/drivers/pci/pcie/portdrv_pci.c +++ b/trunk/drivers/pci/pcie/portdrv_pci.c @@ -32,11 +32,6 @@ MODULE_LICENSE("GPL"); /* global data */ static const char device_name[] = "pcieport-driver"; -static int pcie_portdrv_save_config(struct pci_dev *dev) -{ - return pci_save_state(dev); -} - static int pcie_portdrv_restore_config(struct pci_dev *dev) { int retval; @@ -49,21 +44,21 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev) } #ifdef CONFIG_PM -static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) -{ - return pcie_port_device_suspend(dev, state); +static struct dev_pm_ops pcie_portdrv_pm_ops = { + .suspend = pcie_port_device_suspend, + .resume = pcie_port_device_resume, + .freeze = pcie_port_device_suspend, + .thaw = pcie_port_device_resume, + .poweroff = pcie_port_device_suspend, + .restore = pcie_port_device_resume, +}; -} +#define PCIE_PORTDRV_PM_OPS (&pcie_portdrv_pm_ops) -static int pcie_portdrv_resume(struct pci_dev *dev) -{ - pci_set_master(dev); - return pcie_port_device_resume(dev); -} -#else -#define pcie_portdrv_suspend NULL -#define pcie_portdrv_resume NULL -#endif +#else /* !PM */ + +#define PCIE_PORTDRV_PM_OPS NULL +#endif /* !PM */ /* * pcie_portdrv_probe - Probe PCI-Express port devices @@ -82,20 +77,15 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev, if (status) return status; - if (pci_enable_device(dev) < 0) - return -ENODEV; - - pci_set_master(dev); if (!dev->irq && dev->pin) { dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; " "check vendor BIOS\n", dev->vendor, dev->device); } - if (pcie_port_device_register(dev)) { - pci_disable_device(dev); - return -ENOMEM; - } + status = pcie_port_device_register(dev); + if (status) + return status; - pcie_portdrv_save_config(dev); + pci_save_state(dev); return 0; } @@ -104,7 +94,6 @@ static void pcie_portdrv_remove (struct pci_dev *dev) { pcie_port_device_remove(dev); pci_disable_device(dev); - kfree(pci_get_drvdata(dev)); } static int error_detected_iter(struct device *device, void *data) @@ -278,10 +267,9 @@ static struct pci_driver pcie_portdriver = { .probe = pcie_portdrv_probe, .remove = pcie_portdrv_remove, - .suspend = pcie_portdrv_suspend, - .resume = pcie_portdrv_resume, - .err_handler = &pcie_portdrv_err_handler, + + .driver.pm = PCIE_PORTDRV_PM_OPS, }; static int __init pcie_portdrv_init(void) diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index 55ec44a27e89..e2f3dd098cfa 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -287,7 +287,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child) struct resource *res; int i; - if (!dev) /* It's a host bus, nothing to read */ + if (!child->parent) /* It's a host bus, nothing to read */ return; if (dev->transparent) { @@ -511,21 +511,21 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, /* * If we already got to this bus through a different bridge, - * ignore it. This can happen with the i450NX chipset. + * don't re-add it. This can happen with the i450NX chipset. + * + * However, we continue to descend down the hierarchy and + * scan remaining child buses. */ - if (pci_find_bus(pci_domain_nr(bus), busnr)) { - dev_info(&dev->dev, "bus %04x:%02x already known\n", - pci_domain_nr(bus), busnr); - goto out; + child = pci_find_bus(pci_domain_nr(bus), busnr); + if (!child) { + child = pci_add_new_bus(bus, dev, busnr); + if (!child) + goto out; + child->primary = buses & 0xFF; + child->subordinate = (buses >> 16) & 0xFF; + child->bridge_ctl = bctl; } - child = pci_add_new_bus(bus, dev, busnr); - if (!child) - goto out; - child->primary = buses & 0xFF; - child->subordinate = (buses >> 16) & 0xFF; - child->bridge_ctl = bctl; - cmax = pci_scan_child_bus(child); if (cmax > max) max = cmax; @@ -674,6 +674,19 @@ static void pci_read_irq(struct pci_dev *dev) dev->irq = irq; } +static void set_pcie_port_type(struct pci_dev *pdev) +{ + int pos; + u16 reg16; + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!pos) + return; + pdev->is_pcie = 1; + pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16); + pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; +} + #define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) /** @@ -683,12 +696,33 @@ static void pci_read_irq(struct pci_dev *dev) * Initialize the device structure with information about the device's * vendor,class,memory and IO-space addresses,IRQ lines etc. * Called at initialisation of the PCI subsystem and by CardBus services. - * Returns 0 on success and -1 if unknown type of device (not normal, bridge - * or CardBus). + * Returns 0 on success and negative if unknown type of device (not normal, + * bridge or CardBus). */ -static int pci_setup_device(struct pci_dev * dev) +int pci_setup_device(struct pci_dev *dev) { u32 class; + u8 hdr_type; + struct pci_slot *slot; + + if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type)) + return -EIO; + + dev->sysdata = dev->bus->sysdata; + dev->dev.parent = dev->bus->bridge; + dev->dev.bus = &pci_bus_type; + dev->hdr_type = hdr_type & 0x7f; + dev->multifunction = !!(hdr_type & 0x80); + dev->error_state = pci_channel_io_normal; + set_pcie_port_type(dev); + + list_for_each_entry(slot, &dev->bus->slots, list) + if (PCI_SLOT(dev->devfn) == slot->number) + dev->slot = slot; + + /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) + set this higher, assuming the system even supports it. */ + dev->dma_mask = 0xffffffff; dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn), @@ -703,12 +737,14 @@ static int pci_setup_device(struct pci_dev * dev) dev_dbg(&dev->dev, "found [%04x:%04x] class %06x header type %02x\n", dev->vendor, dev->device, class, dev->hdr_type); + /* need to have dev->class ready */ + dev->cfg_size = pci_cfg_space_size(dev); + /* "Unknown power state" */ dev->current_state = PCI_UNKNOWN; /* Early fixups, before probing the BARs */ pci_fixup_device(pci_fixup_early, dev); - class = dev->class >> 8; switch (dev->hdr_type) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ @@ -770,7 +806,7 @@ static int pci_setup_device(struct pci_dev * dev) default: /* unknown header */ dev_err(&dev->dev, "unknown header type %02x, " "ignoring device\n", dev->hdr_type); - return -1; + return -EIO; bad: dev_err(&dev->dev, "ignoring class %02x (doesn't match header " @@ -785,6 +821,7 @@ static int pci_setup_device(struct pci_dev * dev) static void pci_release_capabilities(struct pci_dev *dev) { pci_vpd_release(dev); + pci_iov_release(dev); } /** @@ -803,19 +840,6 @@ static void pci_release_dev(struct device *dev) kfree(pci_dev); } -static void set_pcie_port_type(struct pci_dev *pdev) -{ - int pos; - u16 reg16; - - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (!pos) - return; - pdev->is_pcie = 1; - pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16); - pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; -} - /** * pci_cfg_space_size - get the configuration space size of the PCI device. * @dev: PCI device @@ -847,6 +871,11 @@ int pci_cfg_space_size(struct pci_dev *dev) { int pos; u32 status; + u16 class; + + class = dev->class >> 8; + if (class == PCI_CLASS_BRIDGE_HOST) + return pci_cfg_space_size_ext(dev); pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (!pos) { @@ -891,9 +920,7 @@ EXPORT_SYMBOL(alloc_pci_dev); static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) { struct pci_dev *dev; - struct pci_slot *slot; u32 l; - u8 hdr_type; int delay = 1; if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l)) @@ -920,34 +947,16 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn) } } - if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type)) - return NULL; - dev = alloc_pci_dev(); if (!dev) return NULL; dev->bus = bus; - dev->sysdata = bus->sysdata; - dev->dev.parent = bus->bridge; - dev->dev.bus = &pci_bus_type; dev->devfn = devfn; - dev->hdr_type = hdr_type & 0x7f; - dev->multifunction = !!(hdr_type & 0x80); dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; - dev->cfg_size = pci_cfg_space_size(dev); - dev->error_state = pci_channel_io_normal; - set_pcie_port_type(dev); - - list_for_each_entry(slot, &bus->slots, list) - if (PCI_SLOT(devfn) == slot->number) - dev->slot = slot; - /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) - set this higher, assuming the system even supports it. */ - dev->dma_mask = 0xffffffff; - if (pci_setup_device(dev) < 0) { + if (pci_setup_device(dev)) { kfree(dev); return NULL; } @@ -972,6 +981,9 @@ static void pci_init_capabilities(struct pci_dev *dev) /* Alternative Routing-ID Forwarding */ pci_enable_ari(dev); + + /* Single Root I/O Virtualization */ + pci_iov_init(dev); } void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) @@ -1006,6 +1018,12 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) { struct pci_dev *dev; + dev = pci_get_slot(bus, devfn); + if (dev) { + pci_dev_put(dev); + return dev; + } + dev = pci_scan_device(bus, devfn); if (!dev) return NULL; @@ -1024,35 +1042,27 @@ EXPORT_SYMBOL(pci_scan_single_device); * Scan a PCI slot on the specified PCI bus for devices, adding * discovered devices to the @bus->devices list. New devices * will not have is_added set. + * + * Returns the number of new devices found. */ int pci_scan_slot(struct pci_bus *bus, int devfn) { - int func, nr = 0; - int scan_all_fns; - - scan_all_fns = pcibios_scan_all_fns(bus, devfn); - - for (func = 0; func < 8; func++, devfn++) { - struct pci_dev *dev; - - dev = pci_scan_single_device(bus, devfn); - if (dev) { - nr++; + int fn, nr = 0; + struct pci_dev *dev; - /* - * If this is a single function device, - * don't scan past the first function. - */ - if (!dev->multifunction) { - if (func > 0) { - dev->multifunction = 1; - } else { - break; - } + dev = pci_scan_single_device(bus, devfn); + if (dev && !dev->is_added) /* new device? */ + nr++; + + if ((dev && dev->multifunction) || + (!dev && pcibios_scan_all_fns(bus, devfn))) { + for (fn = 1; fn < 8; fn++) { + dev = pci_scan_single_device(bus, devfn + fn); + if (dev) { + if (!dev->is_added) + nr++; + dev->multifunction = 1; } - } else { - if (func == 0 && !scan_all_fns) - break; } } @@ -1074,12 +1084,21 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) for (devfn = 0; devfn < 0x100; devfn += 8) pci_scan_slot(bus, devfn); + /* Reserve buses for SR-IOV capability. */ + max += pci_iov_bus_range(bus); + /* * After performing arch-dependent fixup of the bus, look behind * all PCI-to-PCI bridges on this bus. */ - pr_debug("PCI: Fixups for bus %04x:%02x\n", pci_domain_nr(bus), bus->number); - pcibios_fixup_bus(bus); + if (!bus->is_added) { + pr_debug("PCI: Fixups for bus %04x:%02x\n", + pci_domain_nr(bus), bus->number); + pcibios_fixup_bus(bus); + if (pci_is_root_bus(bus)) + bus->is_added = 1; + } + for (pass=0; pass < 2; pass++) list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || @@ -1114,7 +1133,7 @@ struct pci_bus * pci_create_bus(struct device *parent, if (!b) return NULL; - dev = kmalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev){ kfree(b); return NULL; @@ -1133,7 +1152,6 @@ struct pci_bus * pci_create_bus(struct device *parent, list_add_tail(&b->node, &pci_root_buses); up_write(&pci_bus_sem); - memset(dev, 0, sizeof(*dev)); dev->parent = parent; dev->release = pci_release_bus_bridge_dev; dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus); @@ -1193,6 +1211,38 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, EXPORT_SYMBOL(pci_scan_bus_parented); #ifdef CONFIG_HOTPLUG +/** + * pci_rescan_bus - scan a PCI bus for devices. + * @bus: PCI bus to scan + * + * Scan a PCI bus and child buses for new devices, adds them, + * and enables them. + * + * Returns the max number of subordinate bus discovered. + */ +unsigned int __devinit pci_rescan_bus(struct pci_bus *bus) +{ + unsigned int max; + struct pci_dev *dev; + + max = pci_scan_child_bus(bus); + + down_read(&pci_bus_sem); + list_for_each_entry(dev, &bus->devices, bus_list) + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + if (dev->subordinate) + pci_bus_size_bridges(dev->subordinate); + up_read(&pci_bus_sem); + + pci_bus_assign_resources(bus); + pci_enable_bridges(bus); + pci_bus_add_devices(bus); + + return max; +} +EXPORT_SYMBOL_GPL(pci_rescan_bus); + EXPORT_SYMBOL(pci_add_new_bus); EXPORT_SYMBOL(pci_scan_slot); EXPORT_SYMBOL(pci_scan_bridge); diff --git a/trunk/drivers/pci/quirks.c b/trunk/drivers/pci/quirks.c index 92b9efe9bcaf..9b2f0d96900d 100644 --- a/trunk/drivers/pci/quirks.c +++ b/trunk/drivers/pci/quirks.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "pci.h" int isa_dma_bridge_buggy; @@ -34,6 +35,65 @@ int pcie_mch_quirk; EXPORT_SYMBOL(pcie_mch_quirk); #ifdef CONFIG_PCI_QUIRKS +/* + * This quirk function disables the device and releases resources + * which is specified by kernel's boot parameter 'pci=resource_alignment='. + * It also rounds up size to specified alignment. + * Later on, the kernel will assign page-aligned memory resource back + * to that device. + */ +static void __devinit quirk_resource_alignment(struct pci_dev *dev) +{ + int i; + struct resource *r; + resource_size_t align, size; + + if (!pci_is_reassigndev(dev)) + return; + + if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL && + (dev->class >> 8) == PCI_CLASS_BRIDGE_HOST) { + dev_warn(&dev->dev, + "Can't reassign resources to host bridge.\n"); + return; + } + + dev_info(&dev->dev, "Disabling device and release resources.\n"); + pci_disable_device(dev); + + align = pci_specified_resource_alignment(dev); + for (i=0; i < PCI_BRIDGE_RESOURCES; i++) { + r = &dev->resource[i]; + if (!(r->flags & IORESOURCE_MEM)) + continue; + size = resource_size(r); + if (size < align) { + size = align; + dev_info(&dev->dev, + "Rounding up size of resource #%d to %#llx.\n", + i, (unsigned long long)size); + } + r->end = size - 1; + r->start = 0; + } + /* Need to disable bridge's resource window, + * to enable the kernel to reassign new resource + * window later on. + */ + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) { + r = &dev->resource[i]; + if (!(r->flags & IORESOURCE_MEM)) + continue; + r->end = resource_size(r) - 1; + r->start = 0; + } + pci_disable_bridge_window(dev); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_resource_alignment); + /* The Mellanox Tavor device gives false positive parity errors * Mark this device with a broken_parity_status, to allow * PCI scanning code to "skip" this now blacklisted device. @@ -1126,10 +1186,15 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) * its on-board VGA controller */ asus_hides_smbus = 1; } - else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_IG) + else if (dev->device == PCI_DEVICE_ID_INTEL_82801DB_2) switch(dev->subsystem_device) { case 0x00b8: /* Compaq Evo D510 CMT */ case 0x00b9: /* Compaq Evo D510 SFF */ + /* Motherboard doesn't have Host bridge + * subvendor/subdevice IDs and on-board VGA + * controller is disabled if an AGP card is + * inserted, therefore checking USB UHCI + * Controller #1 */ asus_hides_smbus = 1; } else if (dev->device == PCI_DEVICE_ID_INTEL_82815_CGC) @@ -1154,7 +1219,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, as DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, asus_hides_smbus_hostbridge); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_IG, asus_hides_smbus_hostbridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_2, asus_hides_smbus_hostbridge); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, asus_hides_smbus_hostbridge); static void asus_hides_smbus_lpc(struct pci_dev *dev) @@ -1664,9 +1729,13 @@ static void __devinit quirk_netmos(struct pci_dev *dev) * of parallel ports and is the number of serial ports. */ switch (dev->device) { + case PCI_DEVICE_ID_NETMOS_9835: + /* Well, this rule doesn't hold for the following 9835 device */ + if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM && + dev->subsystem_device == 0x0299) + return; case PCI_DEVICE_ID_NETMOS_9735: case PCI_DEVICE_ID_NETMOS_9745: - case PCI_DEVICE_ID_NETMOS_9835: case PCI_DEVICE_ID_NETMOS_9845: case PCI_DEVICE_ID_NETMOS_9855: if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_SERIAL && @@ -2078,6 +2147,92 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15, nvenet_msi_disable); +static int __devinit ht_check_msi_mapping(struct pci_dev *dev) +{ + int pos, ttl = 48; + int found = 0; + + /* check if there is HT MSI cap or enabled on this device */ + pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); + while (pos && ttl--) { + u8 flags; + + if (found < 1) + found = 1; + if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, + &flags) == 0) { + if (flags & HT_MSI_FLAGS_ENABLE) { + if (found < 2) { + found = 2; + break; + } + } + } + pos = pci_find_next_ht_capability(dev, pos, + HT_CAPTYPE_MSI_MAPPING); + } + + return found; +} + +static int __devinit host_bridge_with_leaf(struct pci_dev *host_bridge) +{ + struct pci_dev *dev; + int pos; + int i, dev_no; + int found = 0; + + dev_no = host_bridge->devfn >> 3; + for (i = dev_no + 1; i < 0x20; i++) { + dev = pci_get_slot(host_bridge->bus, PCI_DEVFN(i, 0)); + if (!dev) + continue; + + /* found next host bridge ?*/ + pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE); + if (pos != 0) { + pci_dev_put(dev); + break; + } + + if (ht_check_msi_mapping(dev)) { + found = 1; + pci_dev_put(dev); + break; + } + pci_dev_put(dev); + } + + return found; +} + +#define PCI_HT_CAP_SLAVE_CTRL0 4 /* link control */ +#define PCI_HT_CAP_SLAVE_CTRL1 8 /* link control to */ + +static int __devinit is_end_of_ht_chain(struct pci_dev *dev) +{ + int pos, ctrl_off; + int end = 0; + u16 flags, ctrl; + + pos = pci_find_ht_capability(dev, HT_CAPTYPE_SLAVE); + + if (!pos) + goto out; + + pci_read_config_word(dev, pos + PCI_CAP_FLAGS, &flags); + + ctrl_off = ((flags >> 10) & 1) ? + PCI_HT_CAP_SLAVE_CTRL0 : PCI_HT_CAP_SLAVE_CTRL1; + pci_read_config_word(dev, pos + ctrl_off, &ctrl); + + if (ctrl & (1 << 6)) + end = 1; + +out: + return end; +} + static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) { struct pci_dev *host_bridge; @@ -2102,6 +2257,11 @@ static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev) if (!found) return; + /* don't enable end_device/host_bridge with leaf directly here */ + if (host_bridge == dev && is_end_of_ht_chain(host_bridge) && + host_bridge_with_leaf(host_bridge)) + goto out; + /* root did that ! */ if (msi_ht_cap_enabled(host_bridge)) goto out; @@ -2132,44 +2292,12 @@ static void __devinit ht_disable_msi_mapping(struct pci_dev *dev) } } -static int __devinit ht_check_msi_mapping(struct pci_dev *dev) -{ - int pos, ttl = 48; - int found = 0; - - /* check if there is HT MSI cap or enabled on this device */ - pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING); - while (pos && ttl--) { - u8 flags; - - if (found < 1) - found = 1; - if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS, - &flags) == 0) { - if (flags & HT_MSI_FLAGS_ENABLE) { - if (found < 2) { - found = 2; - break; - } - } - } - pos = pci_find_next_ht_capability(dev, pos, - HT_CAPTYPE_MSI_MAPPING); - } - - return found; -} - -static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) +static void __devinit __nv_msi_ht_cap_quirk(struct pci_dev *dev, int all) { struct pci_dev *host_bridge; int pos; int found; - /* Enabling HT MSI mapping on this device breaks MCP51 */ - if (dev->device == 0x270) - return; - /* check if there is HT MSI cap or enabled on this device */ found = ht_check_msi_mapping(dev); @@ -2193,7 +2321,10 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) /* Host bridge is to HT */ if (found == 1) { /* it is not enabled, try to enable it */ - nv_ht_enable_msi_mapping(dev); + if (all) + ht_enable_msi_mapping(dev); + else + nv_ht_enable_msi_mapping(dev); } return; } @@ -2205,8 +2336,20 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev) /* Host bridge is not to HT, disable HT MSI mapping on this device */ ht_disable_msi_mapping(dev); } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk); + +static void __devinit nv_msi_ht_cap_quirk_all(struct pci_dev *dev) +{ + return __nv_msi_ht_cap_quirk(dev, 1); +} + +static void __devinit nv_msi_ht_cap_quirk_leaf(struct pci_dev *dev) +{ + return __nv_msi_ht_cap_quirk(dev, 0); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk_leaf); + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all); static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) { diff --git a/trunk/drivers/pci/remove.c b/trunk/drivers/pci/remove.c index 042e08924421..86503c14ce7e 100644 --- a/trunk/drivers/pci/remove.c +++ b/trunk/drivers/pci/remove.c @@ -71,6 +71,9 @@ void pci_remove_bus(struct pci_bus *pci_bus) down_write(&pci_bus_sem); list_del(&pci_bus->node); up_write(&pci_bus_sem); + if (!pci_bus->is_added) + return; + pci_remove_legacy_files(pci_bus); device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity); device_remove_file(&pci_bus->dev, &dev_attr_cpulistaffinity); @@ -92,6 +95,7 @@ EXPORT_SYMBOL(pci_remove_bus); */ void pci_remove_bus_device(struct pci_dev *dev) { + pci_stop_bus_device(dev); if (dev->subordinate) { struct pci_bus *b = dev->subordinate; diff --git a/trunk/drivers/pci/search.c b/trunk/drivers/pci/search.c index 5af8bd538149..710d4ea69568 100644 --- a/trunk/drivers/pci/search.c +++ b/trunk/drivers/pci/search.c @@ -29,7 +29,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev) if (pdev->is_pcie) return NULL; while (1) { - if (!pdev->bus->self) + if (!pdev->bus->parent) break; pdev = pdev->bus->self; /* a p2p bridge */ diff --git a/trunk/drivers/pci/setup-bus.c b/trunk/drivers/pci/setup-bus.c index 704608945780..334285a8e237 100644 --- a/trunk/drivers/pci/setup-bus.c +++ b/trunk/drivers/pci/setup-bus.c @@ -27,7 +27,7 @@ #include -static void pbus_assign_resources_sorted(struct pci_bus *bus) +static void pbus_assign_resources_sorted(const struct pci_bus *bus) { struct pci_dev *dev; struct resource *res; @@ -144,6 +144,9 @@ static void pci_setup_bridge(struct pci_bus *bus) struct pci_bus_region region; u32 l, bu, lu, io_upper16; + if (!pci_is_root_bus(bus) && bus->is_added) + return; + dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n", pci_domain_nr(bus), bus->number); @@ -495,7 +498,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_size_bridges); -void __ref pci_bus_assign_resources(struct pci_bus *bus) +void __ref pci_bus_assign_resources(const struct pci_bus *bus) { struct pci_bus *b; struct pci_dev *dev; diff --git a/trunk/drivers/pci/setup-res.c b/trunk/drivers/pci/setup-res.c index 32e8d88a4619..3039fcb86afc 100644 --- a/trunk/drivers/pci/setup-res.c +++ b/trunk/drivers/pci/setup-res.c @@ -120,6 +120,21 @@ int pci_claim_resource(struct pci_dev *dev, int resource) return err; } +#ifdef CONFIG_PCI_QUIRKS +void pci_disable_bridge_window(struct pci_dev *dev) +{ + dev_dbg(&dev->dev, "Disabling bridge window.\n"); + + /* MMIO Base/Limit */ + pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0); + + /* Prefetchable MMIO Base/Limit */ + pci_write_config_dword(dev, PCI_PREF_LIMIT_UPPER32, 0); + pci_write_config_dword(dev, PCI_PREF_MEMORY_BASE, 0x0000fff0); + pci_write_config_dword(dev, PCI_PREF_BASE_UPPER32, 0xffffffff); +} +#endif /* CONFIG_PCI_QUIRKS */ + int pci_assign_resource(struct pci_dev *dev, int resno) { struct pci_bus *bus = dev->bus; diff --git a/trunk/drivers/pci/slot.c b/trunk/drivers/pci/slot.c index 5a8ccb4f604d..21189447e545 100644 --- a/trunk/drivers/pci/slot.c +++ b/trunk/drivers/pci/slot.c @@ -1,8 +1,8 @@ /* * drivers/pci/slot.c * Copyright (C) 2006 Matthew Wilcox - * Copyright (C) 2006-2008 Hewlett-Packard Development Company, L.P. - * Alex Chiang + * Copyright (C) 2006-2009 Hewlett-Packard Development Company, L.P. + * Alex Chiang */ #include @@ -52,8 +52,8 @@ static void pci_slot_release(struct kobject *kobj) struct pci_dev *dev; struct pci_slot *slot = to_pci_slot(kobj); - pr_debug("%s: releasing pci_slot on %x:%d\n", __func__, - slot->bus->number, slot->number); + dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n", + slot->number, pci_slot_name(slot)); list_for_each_entry(dev, &slot->bus->devices, bus_list) if (PCI_SLOT(dev->devfn) == slot->number) @@ -248,9 +248,8 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, if (PCI_SLOT(dev->devfn) == slot_nr) dev->slot = slot; - /* Don't care if debug printk has a -1 for slot_nr */ - pr_debug("%s: created pci_slot on %04x:%02x:%02x\n", - __func__, pci_domain_nr(parent), parent->number, slot_nr); + dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n", + slot_nr, pci_slot_name(slot)); out: kfree(slot_name); @@ -299,9 +298,8 @@ EXPORT_SYMBOL_GPL(pci_renumber_slot); */ void pci_destroy_slot(struct pci_slot *slot) { - pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__, - atomic_read(&slot->kobj.kref.refcount) - 1, - pci_domain_nr(slot->bus), slot->bus->number, slot->number); + dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n", + slot->number, atomic_read(&slot->kobj.kref.refcount) - 1); down_write(&pci_bus_sem); kobject_put(&slot->kobj); diff --git a/trunk/drivers/pcmcia/pxa2xx_cm_x255.c b/trunk/drivers/pcmcia/pxa2xx_cm_x255.c index 4ed64d8e95e7..5143a760153b 100644 --- a/trunk/drivers/pcmcia/pxa2xx_cm_x255.c +++ b/trunk/drivers/pcmcia/pxa2xx_cm_x255.c @@ -63,7 +63,7 @@ static void cmx255_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) { int cd = skt->nr ? GPIO_PCMCIA_S1_CD_VALID : GPIO_PCMCIA_S0_CD_VALID; - int rdy = skt->nr ? GPIO_PCMCIA_S0_RDYINT : GPIO_PCMCIA_S1_RDYINT; + int rdy = skt->nr ? GPIO_PCMCIA_S1_RDYINT : GPIO_PCMCIA_S0_RDYINT; state->detect = !gpio_get_value(cd); state->ready = !!gpio_get_value(rdy); diff --git a/trunk/drivers/pnp/pnpbios/core.c b/trunk/drivers/pnp/pnpbios/core.c index 996f64838079..cfe86853feb2 100644 --- a/trunk/drivers/pnp/pnpbios/core.c +++ b/trunk/drivers/pnp/pnpbios/core.c @@ -94,7 +94,6 @@ struct pnp_dev_node_info node_info; #ifdef CONFIG_HOTPLUG -static int unloading = 0; static struct completion unload_sem; /* @@ -158,7 +157,7 @@ static int pnp_dock_thread(void *unused) int docked = -1, d = 0; set_freezable(); - while (!unloading) { + while (1) { int status; /* @@ -575,8 +574,6 @@ fs_initcall(pnpbios_init); static int __init pnpbios_thread_init(void) { - struct task_struct *task; - #if defined(CONFIG_PPC) if (check_legacy_ioport(PNPBIOS_BASE)) return 0; @@ -584,10 +581,13 @@ static int __init pnpbios_thread_init(void) if (pnpbios_disabled) return 0; #ifdef CONFIG_HOTPLUG - init_completion(&unload_sem); - task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd"); - if (!IS_ERR(task)) - unloading = 0; + { + struct task_struct *task; + init_completion(&unload_sem); + task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd"); + if (IS_ERR(task)) + return PTR_ERR(task); + } #endif return 0; } diff --git a/trunk/drivers/rtc/Kconfig b/trunk/drivers/rtc/Kconfig index 81450fbd8b12..ffe34a12f446 100644 --- a/trunk/drivers/rtc/Kconfig +++ b/trunk/drivers/rtc/Kconfig @@ -129,13 +129,14 @@ comment "I2C RTC drivers" if I2C config RTC_DRV_DS1307 - tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" + tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025" help If you say yes here you get support for various compatible RTC chips (often with battery backup) connected with I2C. This driver should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00, - and probably other chips. In some cases the RTC must already - have been initialized (by manufacturing or a bootloader). + EPSON RX-8025 and probably other chips. In some cases the RTC + must already have been initialized (by manufacturing or a + bootloader). The first seven registers on these chips hold an RTC, and other registers may add features such as NVRAM, a trickle charger for @@ -224,11 +225,11 @@ config RTC_DRV_PCF8583 will be called rtc-pcf8583. config RTC_DRV_M41T80 - tristate "ST M41T65/M41T80/81/82/83/84/85/87" + tristate "ST M41T62/65/M41T80/81/82/83/84/85/87" help If you say Y here you will get support for the ST M41T60 and M41T80 RTC chips series. Currently, the following chips are - supported: M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, + supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, M41ST85, and M41ST87. This driver can also be built as a module. If so, the module @@ -440,6 +441,16 @@ config RTC_DRV_DS1742 This driver can also be built as a module. If so, the module will be called rtc-ds1742. +config RTC_DRV_EFI + tristate "EFI RTC" + depends on IA64 + help + If you say yes here you will get support for the EFI + Real Time Clock. + + This driver can also be built as a module. If so, the module + will be called rtc-efi. + config RTC_DRV_STK17TA8 tristate "Simtek STK17TA8" depends on RTC_CLASS @@ -677,22 +688,16 @@ config RTC_DRV_RS5C313 help If you say yes here you get support for the Ricoh RS5C313 RTC chips. -config RTC_DRV_PARISC - tristate "PA-RISC firmware RTC support" - depends on PARISC +config RTC_DRV_GENERIC + tristate "Generic RTC support" + # Please consider writing a new RTC driver instead of using the generic + # RTC abstraction + depends on PARISC || M68K || PPC help - Say Y or M here to enable RTC support on PA-RISC systems using - firmware calls. If you do not know what you are doing, you should + Say Y or M here to enable RTC support on systems using the generic + RTC abstraction. If you do not know what you are doing, you should just say Y. -config RTC_DRV_PPC - tristate "PowerPC machine dependent RTC support" - depends on PPC - help - The PowerPC kernel has machine-specific functions for accessing - the RTC. This exposes that functionality through the generic RTC - class. - config RTC_DRV_PXA tristate "PXA27x/PXA3xx" depends on ARCH_PXA @@ -736,4 +741,13 @@ config RTC_DRV_MV This driver can also be built as a module. If so, the module will be called rtc-mv. +config RTC_DRV_PS3 + tristate "PS3 RTC" + depends on PPC_PS3 + help + If you say yes here you will get support for the RTC on PS3. + + This driver can also be built as a module. If so, the module + will be called rtc-ps3. + endif # RTC_CLASS diff --git a/trunk/drivers/rtc/Makefile b/trunk/drivers/rtc/Makefile index 0e697aa51caa..6c0639a14f09 100644 --- a/trunk/drivers/rtc/Makefile +++ b/trunk/drivers/rtc/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o +obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o @@ -55,8 +56,7 @@ obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o -obj-$(CONFIG_RTC_DRV_PARISC) += rtc-parisc.o -obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o +obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o @@ -76,3 +76,4 @@ obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o +obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o diff --git a/trunk/drivers/rtc/rtc-ds1307.c b/trunk/drivers/rtc/rtc-ds1307.c index 7e5155e88ac7..2c4a65302a9d 100644 --- a/trunk/drivers/rtc/rtc-ds1307.c +++ b/trunk/drivers/rtc/rtc-ds1307.c @@ -3,6 +3,7 @@ * * Copyright (C) 2005 James Chapman (ds1337 core) * Copyright (C) 2006 David Brownell + * Copyright (C) 2009 Matthias Fuchs (rx8025 support) * * 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 @@ -31,6 +32,7 @@ enum ds_type { ds_1339, ds_1340, m41t00, + rx_8025, // rs5c372 too? different address... }; @@ -83,6 +85,12 @@ enum ds_type { #define DS1339_REG_ALARM1_SECS 0x07 #define DS1339_REG_TRICKLE 0x10 +#define RX8025_REG_CTRL1 0x0e +# define RX8025_BIT_2412 0x20 +#define RX8025_REG_CTRL2 0x0f +# define RX8025_BIT_PON 0x10 +# define RX8025_BIT_VDET 0x40 +# define RX8025_BIT_XST 0x20 struct ds1307 { @@ -94,6 +102,10 @@ struct ds1307 { struct i2c_client *client; struct rtc_device *rtc; struct work_struct work; + s32 (*read_block_data)(struct i2c_client *client, u8 command, + u8 length, u8 *values); + s32 (*write_block_data)(struct i2c_client *client, u8 command, + u8 length, const u8 *values); }; struct chip_desc { @@ -117,6 +129,8 @@ static const struct chip_desc chips[] = { [ds_1340] = { }, [m41t00] = { +}, +[rx_8025] = { }, }; static const struct i2c_device_id ds1307_id[] = { @@ -126,12 +140,86 @@ static const struct i2c_device_id ds1307_id[] = { { "ds1339", ds_1339 }, { "ds1340", ds_1340 }, { "m41t00", m41t00 }, + { "rx8025", rx_8025 }, { } }; MODULE_DEVICE_TABLE(i2c, ds1307_id); /*----------------------------------------------------------------------*/ +#define BLOCK_DATA_MAX_TRIES 10 + +static s32 ds1307_read_block_data_once(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + s32 i, data; + + for (i = 0; i < length; i++) { + data = i2c_smbus_read_byte_data(client, command + i); + if (data < 0) + return data; + values[i] = data; + } + return i; +} + +static s32 ds1307_read_block_data(struct i2c_client *client, u8 command, + u8 length, u8 *values) +{ + u8 oldvalues[I2C_SMBUS_BLOCK_MAX]; + s32 ret; + int tries = 0; + + dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length); + ret = ds1307_read_block_data_once(client, command, length, values); + if (ret < 0) + return ret; + do { + if (++tries > BLOCK_DATA_MAX_TRIES) { + dev_err(&client->dev, + "ds1307_read_block_data failed\n"); + return -EIO; + } + memcpy(oldvalues, values, length); + ret = ds1307_read_block_data_once(client, command, length, + values); + if (ret < 0) + return ret; + } while (memcmp(oldvalues, values, length)); + return length; +} + +static s32 ds1307_write_block_data(struct i2c_client *client, u8 command, + u8 length, const u8 *values) +{ + u8 currvalues[I2C_SMBUS_BLOCK_MAX]; + int tries = 0; + + dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length); + do { + s32 i, ret; + + if (++tries > BLOCK_DATA_MAX_TRIES) { + dev_err(&client->dev, + "ds1307_write_block_data failed\n"); + return -EIO; + } + for (i = 0; i < length; i++) { + ret = i2c_smbus_write_byte_data(client, command + i, + values[i]); + if (ret < 0) + return ret; + } + ret = ds1307_read_block_data_once(client, command, length, + currvalues); + if (ret < 0) + return ret; + } while (memcmp(currvalues, values, length)); + return length; +} + +/*----------------------------------------------------------------------*/ + /* * The IRQ logic includes a "real" handler running in IRQ context just * long enough to schedule this workqueue entry. We need a task context @@ -202,7 +290,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) int tmp; /* read the RTC date and time registers all at once */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1307_REG_SECS, 7, ds1307->regs); if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); @@ -279,7 +367,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); + result = ds1307->write_block_data(ds1307->client, 0, 7, buf); if (result < 0) { dev_err(dev, "%s error %d\n", "write", result); return result; @@ -297,7 +385,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, ds1307->regs); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm read", ret); @@ -356,7 +444,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) t->enabled, t->pending); /* read current status of both alarms and the chip */ - ret = i2c_smbus_read_i2c_block_data(client, + ret = ds1307->read_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm write", ret); @@ -391,7 +479,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) } buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ret = i2c_smbus_write_i2c_block_data(client, + ret = ds1307->write_block_data(client, DS1339_REG_ALARM1_SECS, 9, buf); if (ret < 0) { dev_err(dev, "can't set alarm time\n"); @@ -479,7 +567,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, if (unlikely(!count)) return count; - result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->read_block_data(client, 8 + off, count, buf); if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); return result; @@ -490,9 +578,11 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct i2c_client *client; + struct ds1307 *ds1307; int result; client = kobj_to_i2c_client(kobj); + ds1307 = i2c_get_clientdata(client); if (unlikely(off >= NVRAM_SIZE)) return -EFBIG; @@ -501,7 +591,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, if (unlikely(!count)) return count; - result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); + result = ds1307->write_block_data(client, 8 + off, count, buf); if (result < 0) { dev_err(&client->dev, "%s error %d\n", "nvram write", result); return result; @@ -535,9 +625,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, int want_irq = false; unsigned char *buf; - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA) + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) @@ -547,6 +636,13 @@ static int __devinit ds1307_probe(struct i2c_client *client, i2c_set_clientdata(client, ds1307); ds1307->type = id->driver_data; buf = ds1307->regs; + if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + ds1307->read_block_data = i2c_smbus_read_i2c_block_data; + ds1307->write_block_data = i2c_smbus_write_i2c_block_data; + } else { + ds1307->read_block_data = ds1307_read_block_data; + ds1307->write_block_data = ds1307_write_block_data; + } switch (ds1307->type) { case ds_1337: @@ -557,7 +653,7 @@ static int __devinit ds1307_probe(struct i2c_client *client, want_irq = true; } /* get registers that the "rtc" read below won't read... */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + tmp = ds1307->read_block_data(ds1307->client, DS1337_REG_CONTROL, 2, buf); if (tmp != 2) { pr_debug("read error %d\n", tmp); @@ -589,13 +685,79 @@ static int __devinit ds1307_probe(struct i2c_client *client, dev_warn(&client->dev, "SET TIME!\n"); } break; + + case rx_8025: + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + RX8025_REG_CTRL1 << 4 | 0x08, 2, buf); + if (tmp != 2) { + pr_debug("read error %d\n", tmp); + err = -EIO; + goto exit_free; + } + + /* oscillator off? turn it on, so clock can tick. */ + if (!(ds1307->regs[1] & RX8025_BIT_XST)) { + ds1307->regs[1] |= RX8025_BIT_XST; + i2c_smbus_write_byte_data(client, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(&client->dev, + "oscillator stop detected - SET TIME!\n"); + } + + if (ds1307->regs[1] & RX8025_BIT_PON) { + ds1307->regs[1] &= ~RX8025_BIT_PON; + i2c_smbus_write_byte_data(client, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(&client->dev, "power-on detected\n"); + } + + if (ds1307->regs[1] & RX8025_BIT_VDET) { + ds1307->regs[1] &= ~RX8025_BIT_VDET; + i2c_smbus_write_byte_data(client, + RX8025_REG_CTRL2 << 4 | 0x08, + ds1307->regs[1]); + dev_warn(&client->dev, "voltage drop detected\n"); + } + + /* make sure we are running in 24hour mode */ + if (!(ds1307->regs[0] & RX8025_BIT_2412)) { + u8 hour; + + /* switch to 24 hour mode */ + i2c_smbus_write_byte_data(client, + RX8025_REG_CTRL1 << 4 | 0x08, + ds1307->regs[0] | + RX8025_BIT_2412); + + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + RX8025_REG_CTRL1 << 4 | 0x08, 2, buf); + if (tmp != 2) { + pr_debug("read error %d\n", tmp); + err = -EIO; + goto exit_free; + } + + /* correct hour */ + hour = bcd2bin(ds1307->regs[DS1307_REG_HOUR]); + if (hour == 12) + hour = 0; + if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM) + hour += 12; + + i2c_smbus_write_byte_data(client, + DS1307_REG_HOUR << 4 | 0x08, + hour); + } + break; default: break; } read_rtc: /* read RTC registers */ - tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); + tmp = ds1307->read_block_data(ds1307->client, 0, 8, buf); if (tmp != 8) { pr_debug("read error %d\n", tmp); err = -EIO; @@ -649,6 +811,7 @@ static int __devinit ds1307_probe(struct i2c_client *client, dev_warn(&client->dev, "SET TIME!\n"); } break; + case rx_8025: case ds_1337: case ds_1339: break; @@ -662,6 +825,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, * systems that will run through year 2100. */ break; + case rx_8025: + break; default: if (!(tmp & DS1307_BIT_12HR)) break; diff --git a/trunk/drivers/rtc/rtc-ds1374.c b/trunk/drivers/rtc/rtc-ds1374.c index a5b0fc09f0c6..4d32e328f6cd 100644 --- a/trunk/drivers/rtc/rtc-ds1374.c +++ b/trunk/drivers/rtc/rtc-ds1374.c @@ -222,16 +222,16 @@ static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) rtc_tm_to_time(&alarm->time, &new_alarm); rtc_tm_to_time(&now, &itime); - new_alarm -= itime; - /* This can happen due to races, in addition to dates that are * truly in the past. To avoid requiring the caller to check for * races, dates in the past are assumed to be in the recent past * (i.e. not something that we'd rather the caller know about via * an error), and the alarm is set to go off as soon as possible. */ - if (new_alarm <= 0) + if (time_before_eq(new_alarm, itime)) new_alarm = 1; + else + new_alarm -= itime; mutex_lock(&ds1374->mutex); diff --git a/trunk/drivers/rtc/rtc-efi.c b/trunk/drivers/rtc/rtc-efi.c new file mode 100644 index 000000000000..550292304b0f --- /dev/null +++ b/trunk/drivers/rtc/rtc-efi.c @@ -0,0 +1,235 @@ +/* + * rtc-efi: RTC Class Driver for EFI-based systems + * + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. + * + * Author: dann frazier + * Based on efirtc.c by Stephane Eranian + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +#define EFI_ISDST (EFI_TIME_ADJUST_DAYLIGHT|EFI_TIME_IN_DAYLIGHT) +/* + * EFI Epoch is 1/1/1998 + */ +#define EFI_RTC_EPOCH 1998 + +/* + * returns day of the year [0-365] + */ +static inline int +compute_yday(efi_time_t *eft) +{ + /* efi_time_t.month is in the [1-12] so, we need -1 */ + return rtc_year_days(eft->day - 1, eft->month - 1, eft->year); +} +/* + * returns day of the week [0-6] 0=Sunday + * + * Don't try to provide a year that's before 1998, please ! + */ +static int +compute_wday(efi_time_t *eft) +{ + int y; + int ndays = 0; + + if (eft->year < 1998) { + printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n"); + return -1; + } + + for (y = EFI_RTC_EPOCH; y < eft->year; y++) + ndays += 365 + (is_leap_year(y) ? 1 : 0); + + ndays += compute_yday(eft); + + /* + * 4=1/1/1998 was a Thursday + */ + return (ndays + 4) % 7; +} + +static void +convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft) +{ + eft->year = wtime->tm_year + 1900; + eft->month = wtime->tm_mon + 1; + eft->day = wtime->tm_mday; + eft->hour = wtime->tm_hour; + eft->minute = wtime->tm_min; + eft->second = wtime->tm_sec; + eft->nanosecond = 0; + eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0; + eft->timezone = EFI_UNSPECIFIED_TIMEZONE; +} + +static void +convert_from_efi_time(efi_time_t *eft, struct rtc_time *wtime) +{ + memset(wtime, 0, sizeof(*wtime)); + wtime->tm_sec = eft->second; + wtime->tm_min = eft->minute; + wtime->tm_hour = eft->hour; + wtime->tm_mday = eft->day; + wtime->tm_mon = eft->month - 1; + wtime->tm_year = eft->year - 1900; + + /* day of the week [0-6], Sunday=0 */ + wtime->tm_wday = compute_wday(eft); + + /* day in the year [1-365]*/ + wtime->tm_yday = compute_yday(eft); + + + switch (eft->daylight & EFI_ISDST) { + case EFI_ISDST: + wtime->tm_isdst = 1; + break; + case EFI_TIME_ADJUST_DAYLIGHT: + wtime->tm_isdst = 0; + break; + default: + wtime->tm_isdst = -1; + } +} + +static int efi_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + efi_time_t eft; + efi_status_t status; + + /* + * As of EFI v1.10, this call always returns an unsupported status + */ + status = efi.get_wakeup_time((efi_bool_t *)&wkalrm->enabled, + (efi_bool_t *)&wkalrm->pending, &eft); + + if (status != EFI_SUCCESS) + return -EINVAL; + + convert_from_efi_time(&eft, &wkalrm->time); + + return rtc_valid_tm(&wkalrm->time); +} + +static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + efi_time_t eft; + efi_status_t status; + + convert_to_efi_time(&wkalrm->time, &eft); + + /* + * XXX Fixme: + * As of EFI 0.92 with the firmware I have on my + * machine this call does not seem to work quite + * right + * + * As of v1.10, this call always returns an unsupported status + */ + status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft); + + printk(KERN_WARNING "write status is %d\n", (int)status); + + return status == EFI_SUCCESS ? 0 : -EINVAL; +} + +static int efi_read_time(struct device *dev, struct rtc_time *tm) +{ + efi_status_t status; + efi_time_t eft; + efi_time_cap_t cap; + + status = efi.get_time(&eft, &cap); + + if (status != EFI_SUCCESS) { + /* should never happen */ + printk(KERN_ERR "efitime: can't read time\n"); + return -EINVAL; + } + + convert_from_efi_time(&eft, tm); + + return rtc_valid_tm(tm); +} + +static int efi_set_time(struct device *dev, struct rtc_time *tm) +{ + efi_status_t status; + efi_time_t eft; + + convert_to_efi_time(tm, &eft); + + status = efi.set_time(&eft); + + return status == EFI_SUCCESS ? 0 : -EINVAL; +} + +static const struct rtc_class_ops efi_rtc_ops = { + .read_time = efi_read_time, + .set_time = efi_set_time, + .read_alarm = efi_read_alarm, + .set_alarm = efi_set_alarm, +}; + +static int __init efi_rtc_probe(struct platform_device *dev) +{ + struct rtc_device *rtc; + + rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(dev, rtc); + + return 0; +} + +static int __exit efi_rtc_remove(struct platform_device *dev) +{ + struct rtc_device *rtc = platform_get_drvdata(dev); + + rtc_device_unregister(rtc); + + return 0; +} + +static struct platform_driver efi_rtc_driver = { + .driver = { + .name = "rtc-efi", + .owner = THIS_MODULE, + }, + .probe = efi_rtc_probe, + .remove = __exit_p(efi_rtc_remove), +}; + +static int __init efi_rtc_init(void) +{ + return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe); +} + +static void __exit efi_rtc_exit(void) +{ + platform_driver_unregister(&efi_rtc_driver); +} + +module_init(efi_rtc_init); +module_exit(efi_rtc_exit); + +MODULE_AUTHOR("dann frazier "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("EFI RTC driver"); diff --git a/trunk/drivers/rtc/rtc-generic.c b/trunk/drivers/rtc/rtc-generic.c new file mode 100644 index 000000000000..98322004ad2e --- /dev/null +++ b/trunk/drivers/rtc/rtc-generic.c @@ -0,0 +1,84 @@ +/* rtc-generic: RTC driver using the generic RTC abstraction + * + * Copyright (C) 2008 Kyle McMartin + */ + +#include +#include +#include +#include +#include + +#include + +static int generic_get_time(struct device *dev, struct rtc_time *tm) +{ + unsigned int ret = get_rtc_time(tm); + + if (ret & RTC_BATT_BAD) + return -EOPNOTSUPP; + + return rtc_valid_tm(tm); +} + +static int generic_set_time(struct device *dev, struct rtc_time *tm) +{ + if (set_rtc_time(tm) < 0) + return -EOPNOTSUPP; + + return 0; +} + +static const struct rtc_class_ops generic_rtc_ops = { + .read_time = generic_get_time, + .set_time = generic_set_time, +}; + +static int __init generic_rtc_probe(struct platform_device *dev) +{ + struct rtc_device *rtc; + + rtc = rtc_device_register("rtc-generic", &dev->dev, &generic_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(dev, rtc); + + return 0; +} + +static int __exit generic_rtc_remove(struct platform_device *dev) +{ + struct rtc_device *rtc = platform_get_drvdata(dev); + + rtc_device_unregister(rtc); + + return 0; +} + +static struct platform_driver generic_rtc_driver = { + .driver = { + .name = "rtc-generic", + .owner = THIS_MODULE, + }, + .remove = __exit_p(generic_rtc_remove), +}; + +static int __init generic_rtc_init(void) +{ + return platform_driver_probe(&generic_rtc_driver, generic_rtc_probe); +} + +static void __exit generic_rtc_fini(void) +{ + platform_driver_unregister(&generic_rtc_driver); +} + +module_init(generic_rtc_init); +module_exit(generic_rtc_fini); + +MODULE_AUTHOR("Kyle McMartin "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic RTC driver"); +MODULE_ALIAS("platform:rtc-generic"); diff --git a/trunk/drivers/rtc/rtc-lib.c b/trunk/drivers/rtc/rtc-lib.c index dd70bf73ce9d..773851f338b8 100644 --- a/trunk/drivers/rtc/rtc-lib.c +++ b/trunk/drivers/rtc/rtc-lib.c @@ -26,14 +26,13 @@ static const unsigned short rtc_ydays[2][13] = { }; #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) -#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) /* * The number of days in the month. */ int rtc_month_days(unsigned int month, unsigned int year) { - return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1); + return rtc_days_in_month[month] + (is_leap_year(year) && month == 1); } EXPORT_SYMBOL(rtc_month_days); @@ -42,7 +41,7 @@ EXPORT_SYMBOL(rtc_month_days); */ int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) { - return rtc_ydays[LEAP_YEAR(year)][month] + day-1; + return rtc_ydays[is_leap_year(year)][month] + day-1; } EXPORT_SYMBOL(rtc_year_days); @@ -66,7 +65,7 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) - LEAPS_THRU_END_OF(1970 - 1); if (days < 0) { year -= 1; - days += 365 + LEAP_YEAR(year); + days += 365 + is_leap_year(year); } tm->tm_year = year - 1900; tm->tm_yday = days + 1; diff --git a/trunk/drivers/rtc/rtc-m41t80.c b/trunk/drivers/rtc/rtc-m41t80.c index 893f7dece239..60fe266f0f49 100644 --- a/trunk/drivers/rtc/rtc-m41t80.c +++ b/trunk/drivers/rtc/rtc-m41t80.c @@ -64,10 +64,12 @@ #define M41T80_FEATURE_BL (1 << 1) /* Battery low indicator */ #define M41T80_FEATURE_SQ (1 << 2) /* Squarewave feature */ #define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */ +#define M41T80_FEATURE_SQ_ALT (1 << 4) /* RSx bits are in reg 4 */ #define DRV_VERSION "0.05" static const struct i2c_device_id m41t80_id[] = { + { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT }, { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD }, { "m41t80", M41T80_FEATURE_SQ }, { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ}, @@ -393,12 +395,15 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct m41t80_data *clientdata = i2c_get_clientdata(client); - int val; + int val, reg_sqw; if (!(clientdata->features & M41T80_FEATURE_SQ)) return -EINVAL; - val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); + reg_sqw = M41T80_REG_SQW; + if (clientdata->features & M41T80_FEATURE_SQ_ALT) + reg_sqw = M41T80_REG_WDAY; + val = i2c_smbus_read_byte_data(client, reg_sqw); if (val < 0) return -EIO; val = (val >> 4) & 0xf; @@ -419,7 +424,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct m41t80_data *clientdata = i2c_get_clientdata(client); - int almon, sqw; + int almon, sqw, reg_sqw; int val = simple_strtoul(buf, NULL, 0); if (!(clientdata->features & M41T80_FEATURE_SQ)) @@ -440,13 +445,16 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev, almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); if (almon < 0) return -EIO; - sqw = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); + reg_sqw = M41T80_REG_SQW; + if (clientdata->features & M41T80_FEATURE_SQ_ALT) + reg_sqw = M41T80_REG_WDAY; + sqw = i2c_smbus_read_byte_data(client, reg_sqw); if (sqw < 0) return -EIO; sqw = (sqw & 0x0f) | (val << 4); if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, almon & ~M41T80_ALMON_SQWE) < 0 || - i2c_smbus_write_byte_data(client, M41T80_REG_SQW, sqw) < 0) + i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0) return -EIO; if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, almon | M41T80_ALMON_SQWE) < 0) diff --git a/trunk/drivers/rtc/rtc-parisc.c b/trunk/drivers/rtc/rtc-parisc.c deleted file mode 100644 index c6bfa6fe1a2a..000000000000 --- a/trunk/drivers/rtc/rtc-parisc.c +++ /dev/null @@ -1,112 +0,0 @@ -/* rtc-parisc: RTC for HP PA-RISC firmware - * - * Copyright (C) 2008 Kyle McMartin - */ - -#include -#include -#include -#include - -#include - -/* as simple as can be, and no simpler. */ -struct parisc_rtc { - struct rtc_device *rtc; - spinlock_t lock; -}; - -static int parisc_get_time(struct device *dev, struct rtc_time *tm) -{ - struct parisc_rtc *p = dev_get_drvdata(dev); - unsigned long flags, ret; - - spin_lock_irqsave(&p->lock, flags); - ret = get_rtc_time(tm); - spin_unlock_irqrestore(&p->lock, flags); - - if (ret & RTC_BATT_BAD) - return -EOPNOTSUPP; - - return 0; -} - -static int parisc_set_time(struct device *dev, struct rtc_time *tm) -{ - struct parisc_rtc *p = dev_get_drvdata(dev); - unsigned long flags; - int ret; - - spin_lock_irqsave(&p->lock, flags); - ret = set_rtc_time(tm); - spin_unlock_irqrestore(&p->lock, flags); - - if (ret < 0) - return -EOPNOTSUPP; - - return 0; -} - -static const struct rtc_class_ops parisc_rtc_ops = { - .read_time = parisc_get_time, - .set_time = parisc_set_time, -}; - -static int __devinit parisc_rtc_probe(struct platform_device *dev) -{ - struct parisc_rtc *p; - - p = kzalloc(sizeof (*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - spin_lock_init(&p->lock); - - p->rtc = rtc_device_register("rtc-parisc", &dev->dev, &parisc_rtc_ops, - THIS_MODULE); - if (IS_ERR(p->rtc)) { - int err = PTR_ERR(p->rtc); - kfree(p); - return err; - } - - platform_set_drvdata(dev, p); - - return 0; -} - -static int __devexit parisc_rtc_remove(struct platform_device *dev) -{ - struct parisc_rtc *p = platform_get_drvdata(dev); - - rtc_device_unregister(p->rtc); - kfree(p); - - return 0; -} - -static struct platform_driver parisc_rtc_driver = { - .driver = { - .name = "rtc-parisc", - .owner = THIS_MODULE, - }, - .probe = parisc_rtc_probe, - .remove = __devexit_p(parisc_rtc_remove), -}; - -static int __init parisc_rtc_init(void) -{ - return platform_driver_register(&parisc_rtc_driver); -} - -static void __exit parisc_rtc_fini(void) -{ - platform_driver_unregister(&parisc_rtc_driver); -} - -module_init(parisc_rtc_init); -module_exit(parisc_rtc_fini); - -MODULE_AUTHOR("Kyle McMartin "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("HP PA-RISC RTC driver"); diff --git a/trunk/drivers/rtc/rtc-ppc.c b/trunk/drivers/rtc/rtc-ppc.c deleted file mode 100644 index c8e97e25ef7e..000000000000 --- a/trunk/drivers/rtc/rtc-ppc.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * RTC driver for ppc_md RTC functions - * - * © 2007 Red Hat, Inc. - * - * Author: David Woodhouse - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - - -#include -#include -#include -#include -#include - -static int ppc_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - ppc_md.get_rtc_time(tm); - return 0; -} - -static int ppc_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - return ppc_md.set_rtc_time(tm); -} - -static const struct rtc_class_ops ppc_rtc_ops = { - .set_time = ppc_rtc_set_time, - .read_time = ppc_rtc_read_time, -}; - -static struct rtc_device *rtc; -static struct platform_device *ppc_rtc_pdev; - -static int __init ppc_rtc_init(void) -{ - if (!ppc_md.get_rtc_time || !ppc_md.set_rtc_time) - return -ENODEV; - - ppc_rtc_pdev = platform_device_register_simple("ppc-rtc", 0, NULL, 0); - if (IS_ERR(ppc_rtc_pdev)) - return PTR_ERR(ppc_rtc_pdev); - - rtc = rtc_device_register("ppc_md", &ppc_rtc_pdev->dev, - &ppc_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - platform_device_unregister(ppc_rtc_pdev); - return PTR_ERR(rtc); - } - - return 0; -} - -static void __exit ppc_rtc_exit(void) -{ - rtc_device_unregister(rtc); - platform_device_unregister(ppc_rtc_pdev); -} - -module_init(ppc_rtc_init); -module_exit(ppc_rtc_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Woodhouse "); -MODULE_DESCRIPTION("Generic RTC class driver for PowerPC"); diff --git a/trunk/drivers/rtc/rtc-ps3.c b/trunk/drivers/rtc/rtc-ps3.c new file mode 100644 index 000000000000..968133ce1ee8 --- /dev/null +++ b/trunk/drivers/rtc/rtc-ps3.c @@ -0,0 +1,104 @@ +/* + * PS3 RTC Driver + * + * Copyright 2009 Sony 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; version 2 of the License. + * + * 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, see . + */ + +#include +#include +#include +#include + +#include +#include + + +static u64 read_rtc(void) +{ + int result; + u64 rtc_val; + u64 tb_val; + + result = lv1_get_rtc(&rtc_val, &tb_val); + BUG_ON(result); + + return rtc_val; +} + +static int ps3_get_time(struct device *dev, struct rtc_time *tm) +{ + rtc_time_to_tm(read_rtc() + ps3_os_area_get_rtc_diff(), tm); + return rtc_valid_tm(tm); +} + +static int ps3_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long now; + + rtc_tm_to_time(tm, &now); + ps3_os_area_set_rtc_diff(now - read_rtc()); + return 0; +} + +static const struct rtc_class_ops ps3_rtc_ops = { + .read_time = ps3_get_time, + .set_time = ps3_set_time, +}; + +static int __init ps3_rtc_probe(struct platform_device *dev) +{ + struct rtc_device *rtc; + + rtc = rtc_device_register("rtc-ps3", &dev->dev, &ps3_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + platform_set_drvdata(dev, rtc); + return 0; +} + +static int __exit ps3_rtc_remove(struct platform_device *dev) +{ + rtc_device_unregister(platform_get_drvdata(dev)); + return 0; +} + +static struct platform_driver ps3_rtc_driver = { + .driver = { + .name = "rtc-ps3", + .owner = THIS_MODULE, + }, + .remove = __exit_p(ps3_rtc_remove), +}; + +static int __init ps3_rtc_init(void) +{ + return platform_driver_probe(&ps3_rtc_driver, ps3_rtc_probe); +} + +static void __exit ps3_rtc_fini(void) +{ + platform_driver_unregister(&ps3_rtc_driver); +} + +module_init(ps3_rtc_init); +module_exit(ps3_rtc_fini); + +MODULE_AUTHOR("Sony Corporation"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ps3 RTC driver"); +MODULE_ALIAS("platform:rtc-ps3"); diff --git a/trunk/drivers/rtc/rtc-v3020.c b/trunk/drivers/rtc/rtc-v3020.c index 14d4f036a768..ad164056feb6 100644 --- a/trunk/drivers/rtc/rtc-v3020.c +++ b/trunk/drivers/rtc/rtc-v3020.c @@ -27,17 +27,162 @@ #include #include #include +#include -#include +#include #undef DEBUG +struct v3020; + +struct v3020_chip_ops { + int (*map_io)(struct v3020 *chip, struct platform_device *pdev, + struct v3020_platform_data *pdata); + void (*unmap_io)(struct v3020 *chip); + unsigned char (*read_bit)(struct v3020 *chip); + void (*write_bit)(struct v3020 *chip, unsigned char bit); +}; + +#define V3020_CS 0 +#define V3020_WR 1 +#define V3020_RD 2 +#define V3020_IO 3 + +struct v3020_gpio { + const char *name; + unsigned int gpio; +}; + struct v3020 { + /* MMIO access */ void __iomem *ioaddress; int leftshift; + + /* GPIO access */ + struct v3020_gpio *gpio; + + struct v3020_chip_ops *ops; + struct rtc_device *rtc; }; + +static int v3020_mmio_map(struct v3020 *chip, struct platform_device *pdev, + struct v3020_platform_data *pdata) +{ + if (pdev->num_resources != 1) + return -EBUSY; + + if (pdev->resource[0].flags != IORESOURCE_MEM) + return -EBUSY; + + chip->leftshift = pdata->leftshift; + chip->ioaddress = ioremap(pdev->resource[0].start, 1); + if (chip->ioaddress == NULL) + return -EBUSY; + + return 0; +} + +static void v3020_mmio_unmap(struct v3020 *chip) +{ + iounmap(chip->ioaddress); +} + +static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit) +{ + writel(bit << chip->leftshift, chip->ioaddress); +} + +static unsigned char v3020_mmio_read_bit(struct v3020 *chip) +{ + return readl(chip->ioaddress) & (1 << chip->leftshift); +} + +static struct v3020_chip_ops v3020_mmio_ops = { + .map_io = v3020_mmio_map, + .unmap_io = v3020_mmio_unmap, + .read_bit = v3020_mmio_read_bit, + .write_bit = v3020_mmio_write_bit, +}; + +static struct v3020_gpio v3020_gpio[] = { + { "RTC CS", 0 }, + { "RTC WR", 0 }, + { "RTC RD", 0 }, + { "RTC IO", 0 }, +}; + +static int v3020_gpio_map(struct v3020 *chip, struct platform_device *pdev, + struct v3020_platform_data *pdata) +{ + int i, err; + + v3020_gpio[V3020_CS].gpio = pdata->gpio_cs; + v3020_gpio[V3020_WR].gpio = pdata->gpio_wr; + v3020_gpio[V3020_RD].gpio = pdata->gpio_rd; + v3020_gpio[V3020_IO].gpio = pdata->gpio_io; + + for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) { + err = gpio_request(v3020_gpio[i].gpio, v3020_gpio[i].name); + if (err) + goto err_request; + + gpio_direction_output(v3020_gpio[i].gpio, 1); + } + + chip->gpio = v3020_gpio; + + return 0; + +err_request: + while (--i >= 0) + gpio_free(v3020_gpio[i].gpio); + + return err; +} + +static void v3020_gpio_unmap(struct v3020 *chip) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(v3020_gpio); i++) + gpio_free(v3020_gpio[i].gpio); +} + +static void v3020_gpio_write_bit(struct v3020 *chip, unsigned char bit) +{ + gpio_direction_output(chip->gpio[V3020_IO].gpio, bit); + gpio_set_value(chip->gpio[V3020_CS].gpio, 0); + gpio_set_value(chip->gpio[V3020_WR].gpio, 0); + udelay(1); + gpio_set_value(chip->gpio[V3020_WR].gpio, 1); + gpio_set_value(chip->gpio[V3020_CS].gpio, 1); +} + +static unsigned char v3020_gpio_read_bit(struct v3020 *chip) +{ + int bit; + + gpio_direction_input(chip->gpio[V3020_IO].gpio); + gpio_set_value(chip->gpio[V3020_CS].gpio, 0); + gpio_set_value(chip->gpio[V3020_RD].gpio, 0); + udelay(1); + bit = !!gpio_get_value(chip->gpio[V3020_IO].gpio); + udelay(1); + gpio_set_value(chip->gpio[V3020_RD].gpio, 1); + gpio_set_value(chip->gpio[V3020_CS].gpio, 1); + + return bit; +} + +static struct v3020_chip_ops v3020_gpio_ops = { + .map_io = v3020_gpio_map, + .unmap_io = v3020_gpio_unmap, + .read_bit = v3020_gpio_read_bit, + .write_bit = v3020_gpio_write_bit, +}; + static void v3020_set_reg(struct v3020 *chip, unsigned char address, unsigned char data) { @@ -46,7 +191,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address, tmp = address; for (i = 0; i < 4; i++) { - writel((tmp & 1) << chip->leftshift, chip->ioaddress); + chip->ops->write_bit(chip, (tmp & 1)); tmp >>= 1; udelay(1); } @@ -54,7 +199,7 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address, /* Commands dont have data */ if (!V3020_IS_COMMAND(address)) { for (i = 0; i < 8; i++) { - writel((data & 1) << chip->leftshift, chip->ioaddress); + chip->ops->write_bit(chip, (data & 1)); data >>= 1; udelay(1); } @@ -63,18 +208,18 @@ static void v3020_set_reg(struct v3020 *chip, unsigned char address, static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address) { - unsigned int data=0; + unsigned int data = 0; int i; for (i = 0; i < 4; i++) { - writel((address & 1) << chip->leftshift, chip->ioaddress); + chip->ops->write_bit(chip, (address & 1)); address >>= 1; udelay(1); } for (i = 0; i < 8; i++) { data >>= 1; - if (readl(chip->ioaddress) & (1 << chip->leftshift)) + if (chip->ops->read_bit(chip)) data |= 0x80; udelay(1); } @@ -106,16 +251,14 @@ static int v3020_read_time(struct device *dev, struct rtc_time *dt) tmp = v3020_get_reg(chip, V3020_YEAR); dt->tm_year = bcd2bin(tmp)+100; -#ifdef DEBUG - printk("\n%s : Read RTC values\n",__func__); - printk("tm_hour: %i\n",dt->tm_hour); - printk("tm_min : %i\n",dt->tm_min); - printk("tm_sec : %i\n",dt->tm_sec); - printk("tm_year: %i\n",dt->tm_year); - printk("tm_mon : %i\n",dt->tm_mon); - printk("tm_mday: %i\n",dt->tm_mday); - printk("tm_wday: %i\n",dt->tm_wday); -#endif + dev_dbg(dev, "\n%s : Read RTC values\n", __func__); + dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); + dev_dbg(dev, "tm_min : %i\n", dt->tm_min); + dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); + dev_dbg(dev, "tm_year: %i\n", dt->tm_year); + dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon); + dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); + dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); return 0; } @@ -125,15 +268,13 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt) { struct v3020 *chip = dev_get_drvdata(dev); -#ifdef DEBUG - printk("\n%s : Setting RTC values\n",__func__); - printk("tm_sec : %i\n",dt->tm_sec); - printk("tm_min : %i\n",dt->tm_min); - printk("tm_hour: %i\n",dt->tm_hour); - printk("tm_mday: %i\n",dt->tm_mday); - printk("tm_wday: %i\n",dt->tm_wday); - printk("tm_year: %i\n",dt->tm_year); -#endif + dev_dbg(dev, "\n%s : Setting RTC values\n", __func__); + dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec); + dev_dbg(dev, "tm_min : %i\n", dt->tm_min); + dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour); + dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday); + dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday); + dev_dbg(dev, "tm_year: %i\n", dt->tm_year); /* Write all the values to ram... */ v3020_set_reg(chip, V3020_SECONDS, bin2bcd(dt->tm_sec)); @@ -168,30 +309,28 @@ static int rtc_probe(struct platform_device *pdev) int i; int temp; - if (pdev->num_resources != 1) - return -EBUSY; - - if (pdev->resource[0].flags != IORESOURCE_MEM) - return -EBUSY; - chip = kzalloc(sizeof *chip, GFP_KERNEL); if (!chip) return -ENOMEM; - chip->leftshift = pdata->leftshift; - chip->ioaddress = ioremap(pdev->resource[0].start, 1); - if (chip->ioaddress == NULL) + if (pdata->use_gpio) + chip->ops = &v3020_gpio_ops; + else + chip->ops = &v3020_mmio_ops; + + retval = chip->ops->map_io(chip, pdev, pdata); + if (retval) goto err_chip; /* Make sure the v3020 expects a communication cycle * by reading 8 times */ for (i = 0; i < 8; i++) - temp = readl(chip->ioaddress); + temp = chip->ops->read_bit(chip); /* Test chip by doing a write/read sequence * to the chip ram */ v3020_set_reg(chip, V3020_SECONDS, 0x33); - if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) { + if (v3020_get_reg(chip, V3020_SECONDS) != 0x33) { retval = -ENODEV; goto err_io; } @@ -200,10 +339,17 @@ static int rtc_probe(struct platform_device *pdev) * are all disabled */ v3020_set_reg(chip, V3020_STATUS_0, 0x0); - dev_info(&pdev->dev, "Chip available at physical address 0x%llx," - "data connected to D%d\n", - (unsigned long long)pdev->resource[0].start, - chip->leftshift); + if (pdata->use_gpio) + dev_info(&pdev->dev, "Chip available at GPIOs " + "%d, %d, %d, %d\n", + chip->gpio[V3020_CS].gpio, chip->gpio[V3020_WR].gpio, + chip->gpio[V3020_RD].gpio, chip->gpio[V3020_IO].gpio); + else + dev_info(&pdev->dev, "Chip available at " + "physical address 0x%llx," + "data connected to D%d\n", + (unsigned long long)pdev->resource[0].start, + chip->leftshift); platform_set_drvdata(pdev, chip); @@ -218,7 +364,7 @@ static int rtc_probe(struct platform_device *pdev) return 0; err_io: - iounmap(chip->ioaddress); + chip->ops->unmap_io(chip); err_chip: kfree(chip); @@ -233,7 +379,7 @@ static int rtc_remove(struct platform_device *dev) if (rtc) rtc_device_unregister(rtc); - iounmap(chip->ioaddress); + chip->ops->unmap_io(chip); kfree(chip); return 0; diff --git a/trunk/drivers/rtc/rtc-wm8350.c b/trunk/drivers/rtc/rtc-wm8350.c index 5c5e3aa91385..c91edc572eb6 100644 --- a/trunk/drivers/rtc/rtc-wm8350.c +++ b/trunk/drivers/rtc/rtc-wm8350.c @@ -122,7 +122,7 @@ static int wm8350_rtc_settime(struct device *dev, struct rtc_time *tm) do { rtc_ctrl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); schedule_timeout_uninterruptible(msecs_to_jiffies(1)); - } while (retries-- && !(rtc_ctrl & WM8350_RTC_STS)); + } while (--retries && !(rtc_ctrl & WM8350_RTC_STS)); if (!retries) { dev_err(dev, "timed out on set confirmation\n"); @@ -236,6 +236,17 @@ static int wm8350_rtc_start_alarm(struct wm8350 *wm8350) return 0; } +static int wm8350_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct wm8350 *wm8350 = dev_get_drvdata(dev); + + if (enabled) + return wm8350_rtc_start_alarm(wm8350); + else + return wm8350_rtc_stop_alarm(wm8350); +} + static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct wm8350 *wm8350 = dev_get_drvdata(dev); @@ -291,30 +302,15 @@ static int wm8350_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -/* - * Handle commands from user-space - */ -static int wm8350_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) +static int wm8350_rtc_update_irq_enable(struct device *dev, + unsigned int enabled) { struct wm8350 *wm8350 = dev_get_drvdata(dev); - switch (cmd) { - case RTC_AIE_OFF: - return wm8350_rtc_stop_alarm(wm8350); - case RTC_AIE_ON: - return wm8350_rtc_start_alarm(wm8350); - - case RTC_UIE_OFF: - wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); - break; - case RTC_UIE_ON: + if (enabled) wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_SEC); - break; - - default: - return -ENOIOCTLCMD; - } + else + wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); return 0; } @@ -345,11 +341,12 @@ static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq, } static const struct rtc_class_ops wm8350_rtc_ops = { - .ioctl = wm8350_rtc_ioctl, .read_time = wm8350_rtc_readtime, .set_time = wm8350_rtc_settime, .read_alarm = wm8350_rtc_readalarm, .set_alarm = wm8350_rtc_setalarm, + .alarm_irq_enable = wm8350_rtc_alarm_irq_enable, + .update_irq_enable = wm8350_rtc_update_irq_enable, }; #ifdef CONFIG_PM @@ -440,7 +437,7 @@ static int wm8350_rtc_probe(struct platform_device *pdev) do { timectl = wm8350_reg_read(wm8350, WM8350_RTC_TIME_CONTROL); - } while (timectl & WM8350_RTC_STS && retries--); + } while (timectl & WM8350_RTC_STS && --retries); if (retries == 0) { dev_err(&pdev->dev, "failed to start: timeout\n"); diff --git a/trunk/drivers/s390/block/dasd.c b/trunk/drivers/s390/block/dasd.c index 2fd64e5a9ab2..0570794ccf1c 100644 --- a/trunk/drivers/s390/block/dasd.c +++ b/trunk/drivers/s390/block/dasd.c @@ -2363,6 +2363,7 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) ret = 0; switch (event) { case CIO_GONE: + case CIO_BOXED: case CIO_NO_PATH: /* First of all call extended error reporting. */ dasd_eer_write(device, NULL, DASD_EER_NOPATH); diff --git a/trunk/drivers/s390/cio/device.c b/trunk/drivers/s390/cio/device.c index c4d2f667a2f6..35441fa16be1 100644 --- a/trunk/drivers/s390/cio/device.c +++ b/trunk/drivers/s390/cio/device.c @@ -310,8 +310,6 @@ static void ccw_device_remove_orphan_cb(struct work_struct *work) put_device(&cdev->dev); } -static void ccw_device_call_sch_unregister(struct work_struct *work); - static void ccw_device_remove_disconnected(struct ccw_device *cdev) { @@ -335,11 +333,10 @@ ccw_device_remove_disconnected(struct ccw_device *cdev) spin_unlock_irqrestore(cdev->ccwlock, flags); PREPARE_WORK(&cdev->private->kick_work, ccw_device_remove_orphan_cb); + queue_work(slow_path_wq, &cdev->private->kick_work); } else /* Deregister subchannel, which will kill the ccw device. */ - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(slow_path_wq, &cdev->private->kick_work); + ccw_device_schedule_sch_unregister(cdev); } /** @@ -471,7 +468,7 @@ static int online_store_recog_and_online(struct ccw_device *cdev) int ret; /* Do device recognition, if needed. */ - if (cdev->id.cu_type == 0) { + if (cdev->private->state == DEV_STATE_BOXED) { ret = ccw_device_recognition(cdev); if (ret) { CIO_MSG_EVENT(0, "Couldn't start recognition " @@ -482,17 +479,21 @@ static int online_store_recog_and_online(struct ccw_device *cdev) } wait_event(cdev->private->wait_q, cdev->private->flags.recog_done); + if (cdev->private->state != DEV_STATE_OFFLINE) + /* recognition failed */ + return -EAGAIN; } if (cdev->drv && cdev->drv->set_online) ccw_device_set_online(cdev); return 0; } + static int online_store_handle_online(struct ccw_device *cdev, int force) { int ret; ret = online_store_recog_and_online(cdev); - if (ret) + if (ret && !force) return ret; if (force && cdev->private->state == DEV_STATE_BOXED) { ret = ccw_device_stlck(cdev); @@ -500,7 +501,9 @@ static int online_store_handle_online(struct ccw_device *cdev, int force) return ret; if (cdev->id.cu_type == 0) cdev->private->state = DEV_STATE_NOT_OPER; - online_store_recog_and_online(cdev); + ret = online_store_recog_and_online(cdev); + if (ret) + return ret; } return 0; } @@ -512,7 +515,11 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, int force, ret; unsigned long i; - if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) + if ((cdev->private->state != DEV_STATE_OFFLINE && + cdev->private->state != DEV_STATE_ONLINE && + cdev->private->state != DEV_STATE_BOXED && + cdev->private->state != DEV_STATE_DISCONNECTED) || + atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) return -EAGAIN; if (cdev->drv && !try_module_get(cdev->drv->owner)) { @@ -1014,6 +1021,13 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) put_device(&sch->dev); } +void ccw_device_schedule_sch_unregister(struct ccw_device *cdev) +{ + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_call_sch_unregister); + queue_work(slow_path_wq, &cdev->private->kick_work); +} + /* * subchannel recognition done. Called from the state machine. */ @@ -1025,19 +1039,17 @@ io_subchannel_recog_done(struct ccw_device *cdev) return; } switch (cdev->private->state) { + case DEV_STATE_BOXED: + /* Device did not respond in time. */ case DEV_STATE_NOT_OPER: cdev->private->flags.recog_done = 1; /* Remove device found not operational. */ if (!get_device(&cdev->dev)) break; - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_call_sch_unregister); - queue_work(slow_path_wq, &cdev->private->kick_work); + ccw_device_schedule_sch_unregister(cdev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); break; - case DEV_STATE_BOXED: - /* Device did not respond in time. */ case DEV_STATE_OFFLINE: /* * We can't register the device in interrupt context so @@ -1551,8 +1563,7 @@ static int purge_fn(struct device *dev, void *data) goto out; CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", priv->dev_id.ssid, priv->dev_id.devno); - PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); - queue_work(slow_path_wq, &cdev->private->kick_work); + ccw_device_schedule_sch_unregister(cdev); out: /* Abort loop in case of pending signal. */ diff --git a/trunk/drivers/s390/cio/device.h b/trunk/drivers/s390/cio/device.h index 85e01846ca65..f1cbbd94ad4e 100644 --- a/trunk/drivers/s390/cio/device.h +++ b/trunk/drivers/s390/cio/device.h @@ -87,6 +87,7 @@ int ccw_device_is_orphan(struct ccw_device *); int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); +void ccw_device_schedule_sch_unregister(struct ccw_device *); int ccw_purge_blacklisted(void); /* Function prototypes for device status and basic sense stuff. */ diff --git a/trunk/drivers/s390/cio/device_fsm.c b/trunk/drivers/s390/cio/device_fsm.c index 87b4bfca080f..e46049261561 100644 --- a/trunk/drivers/s390/cio/device_fsm.c +++ b/trunk/drivers/s390/cio/device_fsm.c @@ -256,13 +256,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) old_lpm = 0; if (sch->lpm != old_lpm) __recover_lost_chpids(sch, old_lpm); - if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) { - if (state == DEV_STATE_NOT_OPER) { - cdev->private->flags.recog_done = 1; - cdev->private->state = DEV_STATE_DISCONNECTED; - return; - } - /* Boxed devices don't need extra treatment. */ + if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID && + (state == DEV_STATE_NOT_OPER || state == DEV_STATE_BOXED)) { + cdev->private->flags.recog_done = 1; + cdev->private->state = DEV_STATE_DISCONNECTED; + wake_up(&cdev->private->wait_q); + return; } notify = 0; same_dev = 0; /* Keep the compiler quiet... */ @@ -274,7 +273,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) sch->schid.ssid, sch->schid.sch_no); break; case DEV_STATE_OFFLINE: - if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) { + if (cdev->online) { same_dev = ccw_device_handle_oper(cdev); notify = 1; } @@ -307,12 +306,17 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) " subchannel 0.%x.%04x\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); + if (cdev->id.cu_type != 0) { /* device was recognized before */ + cdev->private->flags.recog_done = 1; + cdev->private->state = DEV_STATE_BOXED; + wake_up(&cdev->private->wait_q); + return; + } break; } cdev->private->state = state; io_subchannel_recog_done(cdev); - if (state != DEV_STATE_NOT_OPER) - wake_up(&cdev->private->wait_q); + wake_up(&cdev->private->wait_q); } /* @@ -390,10 +394,13 @@ ccw_device_done(struct ccw_device *cdev, int state) cdev->private->state = state; - - if (state == DEV_STATE_BOXED) + if (state == DEV_STATE_BOXED) { CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n", cdev->private->dev_id.devno, sch->schid.sch_no); + if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED)) + ccw_device_schedule_sch_unregister(cdev); + cdev->private->flags.donotify = 0; + } if (cdev->private->flags.donotify) { cdev->private->flags.donotify = 0; diff --git a/trunk/drivers/s390/net/qeth_core_offl.c b/trunk/drivers/s390/net/qeth_core_offl.c deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/trunk/drivers/s390/net/qeth_core_offl.h b/trunk/drivers/s390/net/qeth_core_offl.h deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/trunk/drivers/s390/scsi/zfcp_ccw.c b/trunk/drivers/s390/scsi/zfcp_ccw.c index 1fe1e2eda512..cfb0dcb6e3ff 100644 --- a/trunk/drivers/s390/scsi/zfcp_ccw.c +++ b/trunk/drivers/s390/scsi/zfcp_ccw.c @@ -176,6 +176,11 @@ static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event) zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, "ccnoti4", NULL); break; + case CIO_BOXED: + dev_warn(&adapter->ccw_device->dev, + "The ccw device did not respond in time.\n"); + zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL); + break; } return 1; } diff --git a/trunk/drivers/s390/scsi/zfcp_fc.c b/trunk/drivers/s390/scsi/zfcp_fc.c index aab8123c5966..e8d032b9dfbd 100644 --- a/trunk/drivers/s390/scsi/zfcp_fc.c +++ b/trunk/drivers/s390/scsi/zfcp_fc.c @@ -94,7 +94,7 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port) static void zfcp_wka_port_offline(struct work_struct *work) { - struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct delayed_work *dw = to_delayed_work(work); struct zfcp_wka_port *wka_port = container_of(dw, struct zfcp_wka_port, work); diff --git a/trunk/drivers/serial/mcf.c b/trunk/drivers/serial/mcf.c index 56841fe5f483..0eefb07bebaf 100644 --- a/trunk/drivers/serial/mcf.c +++ b/trunk/drivers/serial/mcf.c @@ -513,7 +513,7 @@ static int __init mcf_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - if ((co->index >= 0) && (co->index <= MCF_MAXPORTS)) + if ((co->index < 0) || (co->index >= MCF_MAXPORTS)) co->index = 0; port = &mcf_ports[co->index].port; if (port->membase == 0) diff --git a/trunk/drivers/serial/serial_core.c b/trunk/drivers/serial/serial_core.c index 42f4e66fccaf..b0bb29d804ae 100644 --- a/trunk/drivers/serial/serial_core.c +++ b/trunk/drivers/serial/serial_core.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -1682,20 +1684,20 @@ static const char *uart_type(struct uart_port *port) #ifdef CONFIG_PROC_FS -static int uart_line_info(char *buf, struct uart_driver *drv, int i) +static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) { struct uart_state *state = drv->state + i; int pm_state; struct uart_port *port = state->port; char stat_buf[32]; unsigned int status; - int mmio, ret; + int mmio; if (!port) - return 0; + return; mmio = port->iotype >= UPIO_MEM; - ret = sprintf(buf, "%d: uart:%s %s%08llX irq:%d", + seq_printf(m, "%d: uart:%s %s%08llX irq:%d", port->line, uart_type(port), mmio ? "mmio:0x" : "port:", mmio ? (unsigned long long)port->mapbase @@ -1703,8 +1705,8 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) port->irq); if (port->type == PORT_UNKNOWN) { - strcat(buf, "\n"); - return ret + 1; + seq_putc(m, '\n'); + return; } if (capable(CAP_SYS_ADMIN)) { @@ -1719,19 +1721,19 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) uart_change_pm(state, pm_state); mutex_unlock(&state->mutex); - ret += sprintf(buf + ret, " tx:%d rx:%d", + seq_printf(m, " tx:%d rx:%d", port->icount.tx, port->icount.rx); if (port->icount.frame) - ret += sprintf(buf + ret, " fe:%d", + seq_printf(m, " fe:%d", port->icount.frame); if (port->icount.parity) - ret += sprintf(buf + ret, " pe:%d", + seq_printf(m, " pe:%d", port->icount.parity); if (port->icount.brk) - ret += sprintf(buf + ret, " brk:%d", + seq_printf(m, " brk:%d", port->icount.brk); if (port->icount.overrun) - ret += sprintf(buf + ret, " oe:%d", + seq_printf(m, " oe:%d", port->icount.overrun); #define INFOBIT(bit, str) \ @@ -1753,45 +1755,39 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) STATBIT(TIOCM_RNG, "|RI"); if (stat_buf[0]) stat_buf[0] = ' '; - strcat(stat_buf, "\n"); - ret += sprintf(buf + ret, stat_buf); - } else { - strcat(buf, "\n"); - ret++; + seq_puts(m, stat_buf); } + seq_putc(m, '\n'); #undef STATBIT #undef INFOBIT - return ret; } -static int uart_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int uart_proc_show(struct seq_file *m, void *v) { - struct tty_driver *ttydrv = data; + struct tty_driver *ttydrv = m->private; struct uart_driver *drv = ttydrv->driver_state; - int i, len = 0, l; - off_t begin = 0; + int i; - len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", + seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", ""); - for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) { - l = uart_line_info(page + len, drv, i); - len += l; - if (len + begin > off + count) - goto done; - if (len + begin < off) { - begin += len; - len = 0; - } - } - *eof = 1; - done: - if (off >= len + begin) - return 0; - *start = page + (off - begin); - return (count < begin + len - off) ? count : (begin + len - off); + for (i = 0; i < drv->nr; i++) + uart_line_info(m, drv, i); + return 0; } + +static int uart_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, uart_proc_show, PDE(inode)->data); +} + +static const struct file_operations uart_proc_fops = { + .owner = THIS_MODULE, + .open = uart_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) @@ -2299,7 +2295,7 @@ static const struct tty_operations uart_ops = { .break_ctl = uart_break_ctl, .wait_until_sent= uart_wait_until_sent, #ifdef CONFIG_PROC_FS - .read_proc = uart_read_proc, + .proc_fops = &uart_proc_fops, #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, diff --git a/trunk/drivers/spi/spi_gpio.c b/trunk/drivers/spi/spi_gpio.c index d2866c293dee..26bd03e61855 100644 --- a/trunk/drivers/spi/spi_gpio.c +++ b/trunk/drivers/spi/spi_gpio.c @@ -178,8 +178,10 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active) if (is_active) setsck(spi, spi->mode & SPI_CPOL); - /* SPI is normally active-low */ - gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); + if (cs != SPI_GPIO_NO_CHIPSELECT) { + /* SPI is normally active-low */ + gpio_set_value(cs, (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); + } } static int spi_gpio_setup(struct spi_device *spi) @@ -191,15 +193,17 @@ static int spi_gpio_setup(struct spi_device *spi) return -EINVAL; if (!spi->controller_state) { - status = gpio_request(cs, dev_name(&spi->dev)); - if (status) - return status; - status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH); + if (cs != SPI_GPIO_NO_CHIPSELECT) { + status = gpio_request(cs, dev_name(&spi->dev)); + if (status) + return status; + status = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH); + } } if (!status) status = spi_bitbang_setup(spi); if (status) { - if (!spi->controller_state) + if (!spi->controller_state && cs != SPI_GPIO_NO_CHIPSELECT) gpio_free(cs); } return status; @@ -209,7 +213,8 @@ static void spi_gpio_cleanup(struct spi_device *spi) { unsigned long cs = (unsigned long) spi->controller_data; - gpio_free(cs); + if (cs != SPI_GPIO_NO_CHIPSELECT) + gpio_free(cs); spi_bitbang_cleanup(spi); } diff --git a/trunk/drivers/spi/spi_mpc83xx.c b/trunk/drivers/spi/spi_mpc83xx.c index 44a2b46ccb79..f4573a96af24 100644 --- a/trunk/drivers/spi/spi_mpc83xx.c +++ b/trunk/drivers/spi/spi_mpc83xx.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,7 +25,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -79,7 +87,7 @@ struct mpc83xx_spi { u32(*get_tx) (struct mpc83xx_spi *); unsigned int count; - int irq; + unsigned int irq; unsigned nsecs; /* (clock cycle time)/2 */ @@ -89,9 +97,6 @@ struct mpc83xx_spi { bool qe_mode; - void (*activate_cs) (u8 cs, u8 polarity); - void (*deactivate_cs) (u8 cs, u8 polarity); - u8 busy; struct workqueue_struct *workqueue; @@ -123,6 +128,7 @@ static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg) } #define MPC83XX_SPI_RX_BUF(type) \ +static \ void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \ { \ type * rx = mpc83xx_spi->rx; \ @@ -131,6 +137,7 @@ void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \ } #define MPC83XX_SPI_TX_BUF(type) \ +static \ u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \ { \ u32 data; \ @@ -151,15 +158,14 @@ MPC83XX_SPI_TX_BUF(u32) static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) { - struct mpc83xx_spi *mpc83xx_spi; - u8 pol = spi->mode & SPI_CS_HIGH ? 1 : 0; + struct mpc83xx_spi *mpc83xx_spi = spi_master_get_devdata(spi->master); + struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data; + bool pol = spi->mode & SPI_CS_HIGH; struct spi_mpc83xx_cs *cs = spi->controller_state; - mpc83xx_spi = spi_master_get_devdata(spi->master); - if (value == BITBANG_CS_INACTIVE) { - if (mpc83xx_spi->deactivate_cs) - mpc83xx_spi->deactivate_cs(spi->chip_select, pol); + if (pdata->cs_control) + pdata->cs_control(spi, !pol); } if (value == BITBANG_CS_ACTIVE) { @@ -172,7 +178,7 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) if (cs->hw_mode != regval) { unsigned long flags; - void *tmp_ptr = &mpc83xx_spi->base->mode; + __be32 __iomem *mode = &mpc83xx_spi->base->mode; regval = cs->hw_mode; /* Turn off IRQs locally to minimize time that @@ -180,12 +186,12 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value) */ local_irq_save(flags); /* Turn off SPI unit prior changing mode */ - mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE); - mpc83xx_spi_write_reg(tmp_ptr, regval); + mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE); + mpc83xx_spi_write_reg(mode, regval); local_irq_restore(flags); } - if (mpc83xx_spi->activate_cs) - mpc83xx_spi->activate_cs(spi->chip_select, pol); + if (pdata->cs_control) + pdata->cs_control(spi, pol); } } @@ -284,7 +290,7 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode); if (cs->hw_mode != regval) { unsigned long flags; - void *tmp_ptr = &mpc83xx_spi->base->mode; + __be32 __iomem *mode = &mpc83xx_spi->base->mode; regval = cs->hw_mode; /* Turn off IRQs locally to minimize time @@ -292,8 +298,8 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) */ local_irq_save(flags); /* Turn off SPI unit prior changing mode */ - mpc83xx_spi_write_reg(tmp_ptr, regval & ~SPMODE_ENABLE); - mpc83xx_spi_write_reg(tmp_ptr, regval); + mpc83xx_spi_write_reg(mode, regval & ~SPMODE_ENABLE); + mpc83xx_spi_write_reg(mode, regval); local_irq_restore(flags); } return 0; @@ -483,7 +489,7 @@ static int mpc83xx_spi_setup(struct spi_device *spi) return 0; } -irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data) +static irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data) { struct mpc83xx_spi *mpc83xx_spi = context_data; u32 event; @@ -545,43 +551,28 @@ static void mpc83xx_spi_cleanup(struct spi_device *spi) kfree(spi->controller_state); } -static int __init mpc83xx_spi_probe(struct platform_device *dev) +static struct spi_master * __devinit +mpc83xx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) { + struct fsl_spi_platform_data *pdata = dev->platform_data; struct spi_master *master; struct mpc83xx_spi *mpc83xx_spi; - struct fsl_spi_platform_data *pdata; - struct resource *r; u32 regval; int ret = 0; - /* Get resources(memory, IRQ) associated with the device */ - master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi)); - + master = spi_alloc_master(dev, sizeof(struct mpc83xx_spi)); if (master == NULL) { ret = -ENOMEM; goto err; } - platform_set_drvdata(dev, master); - pdata = dev->dev.platform_data; + dev_set_drvdata(dev, master); - if (pdata == NULL) { - ret = -ENODEV; - goto free_master; - } - - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (r == NULL) { - ret = -ENODEV; - goto free_master; - } master->setup = mpc83xx_spi_setup; master->transfer = mpc83xx_spi_transfer; master->cleanup = mpc83xx_spi_cleanup; mpc83xx_spi = spi_master_get_devdata(master); - mpc83xx_spi->activate_cs = pdata->activate_cs; - mpc83xx_spi->deactivate_cs = pdata->deactivate_cs; mpc83xx_spi->qe_mode = pdata->qe_mode; mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8; mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8; @@ -596,18 +587,13 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev) init_completion(&mpc83xx_spi->done); - mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1); + mpc83xx_spi->base = ioremap(mem->start, mem->end - mem->start + 1); if (mpc83xx_spi->base == NULL) { ret = -ENOMEM; goto put_master; } - mpc83xx_spi->irq = platform_get_irq(dev, 0); - - if (mpc83xx_spi->irq < 0) { - ret = -ENXIO; - goto unmap_io; - } + mpc83xx_spi->irq = irq; /* Register for SPI Interrupt */ ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq, @@ -649,9 +635,9 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev) printk(KERN_INFO "%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)\n", - dev_name(&dev->dev), mpc83xx_spi->base, mpc83xx_spi->irq); + dev_name(dev), mpc83xx_spi->base, mpc83xx_spi->irq); - return ret; + return master; unreg_master: destroy_workqueue(mpc83xx_spi->workqueue); @@ -661,18 +647,16 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev) iounmap(mpc83xx_spi->base); put_master: spi_master_put(master); -free_master: - kfree(master); err: - return ret; + return ERR_PTR(ret); } -static int __exit mpc83xx_spi_remove(struct platform_device *dev) +static int __devexit mpc83xx_spi_remove(struct device *dev) { struct mpc83xx_spi *mpc83xx_spi; struct spi_master *master; - master = platform_get_drvdata(dev); + master = dev_get_drvdata(dev); mpc83xx_spi = spi_master_get_devdata(master); flush_workqueue(mpc83xx_spi->workqueue); @@ -685,23 +669,293 @@ static int __exit mpc83xx_spi_remove(struct platform_device *dev) return 0; } +struct mpc83xx_spi_probe_info { + struct fsl_spi_platform_data pdata; + int *gpios; + bool *alow_flags; +}; + +static struct mpc83xx_spi_probe_info * +to_of_pinfo(struct fsl_spi_platform_data *pdata) +{ + return container_of(pdata, struct mpc83xx_spi_probe_info, pdata); +} + +static void mpc83xx_spi_cs_control(struct spi_device *spi, bool on) +{ + struct device *dev = spi->dev.parent; + struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data); + u16 cs = spi->chip_select; + int gpio = pinfo->gpios[cs]; + bool alow = pinfo->alow_flags[cs]; + + gpio_set_value(gpio, on ^ alow); +} + +static int of_mpc83xx_spi_get_chipselects(struct device *dev) +{ + struct device_node *np = dev_archdata_get_node(&dev->archdata); + struct fsl_spi_platform_data *pdata = dev->platform_data; + struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata); + unsigned int ngpios; + int i = 0; + int ret; + + ngpios = of_gpio_count(np); + if (!ngpios) { + /* + * SPI w/o chip-select line. One SPI device is still permitted + * though. + */ + pdata->max_chipselect = 1; + return 0; + } + + pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL); + if (!pinfo->gpios) + return -ENOMEM; + memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios)); + + pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags), + GFP_KERNEL); + if (!pinfo->alow_flags) { + ret = -ENOMEM; + goto err_alloc_flags; + } + + for (; i < ngpios; i++) { + int gpio; + enum of_gpio_flags flags; + + gpio = of_get_gpio_flags(np, i, &flags); + if (!gpio_is_valid(gpio)) { + dev_err(dev, "invalid gpio #%d: %d\n", i, gpio); + goto err_loop; + } + + ret = gpio_request(gpio, dev_name(dev)); + if (ret) { + dev_err(dev, "can't request gpio #%d: %d\n", i, ret); + goto err_loop; + } + + pinfo->gpios[i] = gpio; + pinfo->alow_flags[i] = flags & OF_GPIO_ACTIVE_LOW; + + ret = gpio_direction_output(pinfo->gpios[i], + pinfo->alow_flags[i]); + if (ret) { + dev_err(dev, "can't set output direction for gpio " + "#%d: %d\n", i, ret); + goto err_loop; + } + } + + pdata->max_chipselect = ngpios; + pdata->cs_control = mpc83xx_spi_cs_control; + + return 0; + +err_loop: + while (i >= 0) { + if (gpio_is_valid(pinfo->gpios[i])) + gpio_free(pinfo->gpios[i]); + i--; + } + + kfree(pinfo->alow_flags); + pinfo->alow_flags = NULL; +err_alloc_flags: + kfree(pinfo->gpios); + pinfo->gpios = NULL; + return ret; +} + +static int of_mpc83xx_spi_free_chipselects(struct device *dev) +{ + struct fsl_spi_platform_data *pdata = dev->platform_data; + struct mpc83xx_spi_probe_info *pinfo = to_of_pinfo(pdata); + int i; + + if (!pinfo->gpios) + return 0; + + for (i = 0; i < pdata->max_chipselect; i++) { + if (gpio_is_valid(pinfo->gpios[i])) + gpio_free(pinfo->gpios[i]); + } + + kfree(pinfo->gpios); + kfree(pinfo->alow_flags); + return 0; +} + +static int __devinit of_mpc83xx_spi_probe(struct of_device *ofdev, + const struct of_device_id *ofid) +{ + struct device *dev = &ofdev->dev; + struct device_node *np = ofdev->node; + struct mpc83xx_spi_probe_info *pinfo; + struct fsl_spi_platform_data *pdata; + struct spi_master *master; + struct resource mem; + struct resource irq; + const void *prop; + int ret = -ENOMEM; + + pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + + pdata = &pinfo->pdata; + dev->platform_data = pdata; + + /* Allocate bus num dynamically. */ + pdata->bus_num = -1; + + /* SPI controller is either clocked from QE or SoC clock. */ + pdata->sysclk = get_brgfreq(); + if (pdata->sysclk == -1) { + pdata->sysclk = fsl_get_sys_freq(); + if (pdata->sysclk == -1) { + ret = -ENODEV; + goto err_clk; + } + } + + prop = of_get_property(np, "mode", NULL); + if (prop && !strcmp(prop, "cpu-qe")) + pdata->qe_mode = 1; + + ret = of_mpc83xx_spi_get_chipselects(dev); + if (ret) + goto err; + + ret = of_address_to_resource(np, 0, &mem); + if (ret) + goto err; + + ret = of_irq_to_resource(np, 0, &irq); + if (!ret) { + ret = -EINVAL; + goto err; + } + + master = mpc83xx_spi_probe(dev, &mem, irq.start); + if (IS_ERR(master)) { + ret = PTR_ERR(master); + goto err; + } + + of_register_spi_devices(master, np); + + return 0; + +err: + of_mpc83xx_spi_free_chipselects(dev); +err_clk: + kfree(pinfo); + return ret; +} + +static int __devexit of_mpc83xx_spi_remove(struct of_device *ofdev) +{ + int ret; + + ret = mpc83xx_spi_remove(&ofdev->dev); + if (ret) + return ret; + of_mpc83xx_spi_free_chipselects(&ofdev->dev); + return 0; +} + +static const struct of_device_id of_mpc83xx_spi_match[] = { + { .compatible = "fsl,spi" }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_mpc83xx_spi_match); + +static struct of_platform_driver of_mpc83xx_spi_driver = { + .name = "mpc83xx_spi", + .match_table = of_mpc83xx_spi_match, + .probe = of_mpc83xx_spi_probe, + .remove = __devexit_p(of_mpc83xx_spi_remove), +}; + +#ifdef CONFIG_MPC832x_RDB +/* + * XXX XXX XXX + * This is "legacy" platform driver, was used by the MPC8323E-RDB boards + * only. The driver should go away soon, since newer MPC8323E-RDB's device + * tree can work with OpenFirmware driver. But for now we support old trees + * as well. + */ +static int __devinit plat_mpc83xx_spi_probe(struct platform_device *pdev) +{ + struct resource *mem; + unsigned int irq; + struct spi_master *master; + + if (!pdev->dev.platform_data) + return -EINVAL; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + + master = mpc83xx_spi_probe(&pdev->dev, mem, irq); + if (IS_ERR(master)) + return PTR_ERR(master); + return 0; +} + +static int __devexit plat_mpc83xx_spi_remove(struct platform_device *pdev) +{ + return mpc83xx_spi_remove(&pdev->dev); +} + MODULE_ALIAS("platform:mpc83xx_spi"); static struct platform_driver mpc83xx_spi_driver = { - .remove = __exit_p(mpc83xx_spi_remove), + .probe = plat_mpc83xx_spi_probe, + .remove = __exit_p(plat_mpc83xx_spi_remove), .driver = { .name = "mpc83xx_spi", .owner = THIS_MODULE, }, }; +static bool legacy_driver_failed; + +static void __init legacy_driver_register(void) +{ + legacy_driver_failed = platform_driver_register(&mpc83xx_spi_driver); +} + +static void __exit legacy_driver_unregister(void) +{ + if (legacy_driver_failed) + return; + platform_driver_unregister(&mpc83xx_spi_driver); +} +#else +static void __init legacy_driver_register(void) {} +static void __exit legacy_driver_unregister(void) {} +#endif /* CONFIG_MPC832x_RDB */ + static int __init mpc83xx_spi_init(void) { - return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe); + legacy_driver_register(); + return of_register_platform_driver(&of_mpc83xx_spi_driver); } static void __exit mpc83xx_spi_exit(void) { - platform_driver_unregister(&mpc83xx_spi_driver); + of_unregister_platform_driver(&of_mpc83xx_spi_driver); + legacy_driver_unregister(); } module_init(mpc83xx_spi_init); diff --git a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index e5752f615e09..80f9cc7137c2 100644 --- a/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/trunk/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -719,7 +719,7 @@ void ieee80211_softmac_scan(struct ieee80211_device *ieee) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void ieee80211_softmac_scan_wq(struct work_struct *work) { - struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq); #else void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) @@ -777,7 +777,7 @@ void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void ieee80211_softmac_scan_wq(struct work_struct *work) { - struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, softmac_scan_wq); #else void ieee80211_softmac_scan_wq(struct ieee80211_device *ieee) @@ -2980,7 +2980,7 @@ void ieee80211_start_monitor_mode(struct ieee80211_device *ieee) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void ieee80211_start_ibss_wq(struct work_struct *work) { - struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq); #else void ieee80211_start_ibss_wq(struct ieee80211_device *ieee) @@ -3162,7 +3162,7 @@ void ieee80211_disassociate(struct ieee80211_device *ieee) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void ieee80211_associate_retry_wq(struct work_struct *work) { - struct delayed_work *dwork = container_of(work, struct delayed_work, work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq); #else void ieee80211_associate_retry_wq(struct ieee80211_device *ieee) diff --git a/trunk/drivers/staging/rtl8187se/r8180_core.c b/trunk/drivers/staging/rtl8187se/r8180_core.c index 66de5cc8ddf1..ff1f23f99f27 100644 --- a/trunk/drivers/staging/rtl8187se/r8180_core.c +++ b/trunk/drivers/staging/rtl8187se/r8180_core.c @@ -5438,7 +5438,7 @@ void rtl8180_hw_wakeup_wq (struct work_struct *work) // struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); // struct ieee80211_device * ieee = (struct ieee80211_device*) // container_of(work, struct ieee80211_device, watch_dog_wq); - struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_wakeup_wq); struct net_device *dev = ieee->dev; #else @@ -5459,7 +5459,7 @@ void rtl8180_hw_sleep_wq (struct work_struct *work) // struct r8180_priv *priv = container_of(work, struct r8180_priv, watch_dog_wq); // struct ieee80211_device * ieee = (struct ieee80211_device*) // container_of(work, struct ieee80211_device, watch_dog_wq); - struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(dwork,struct ieee80211_device,hw_sleep_wq); struct net_device *dev = ieee->dev; #else @@ -6407,7 +6407,7 @@ priv->txnpring)/8); void rtl8180_tx_irq_wq(struct work_struct *work) { //struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); - struct delayed_work *dwork = container_of(work,struct delayed_work,work); + struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device * ieee = (struct ieee80211_device*) container_of(dwork, struct ieee80211_device, watch_dog_wq); struct net_device *dev = ieee->dev; @@ -6691,7 +6691,7 @@ lizhaoming--------------------------- RF power on/power off ----------------- #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) void GPIOChangeRFWorkItemCallBack(struct work_struct *work) { - //struct delayed_work *dwork = container_of(work, struct delayed_work, work); + //struct delayed_work *dwork = to_delayed_work(work); struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work); struct net_device *dev = ieee->dev; struct r8180_priv *priv = ieee80211_priv(dev); diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index 742a5bc44be8..2a70563bbee1 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -421,57 +422,52 @@ static int serial_break(struct tty_struct *tty, int break_state) return 0; } -static int serial_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) +static int serial_proc_show(struct seq_file *m, void *v) { struct usb_serial *serial; - int length = 0; int i; - off_t begin = 0; char tmp[40]; dbg("%s", __func__); - length += sprintf(page, "usbserinfo:1.0 driver:2.0\n"); - for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) { + seq_puts(m, "usbserinfo:1.0 driver:2.0\n"); + for (i = 0; i < SERIAL_TTY_MINORS; ++i) { serial = usb_serial_get_by_index(i); if (serial == NULL) continue; - length += sprintf(page+length, "%d:", i); + seq_printf(m, "%d:", i); if (serial->type->driver.owner) - length += sprintf(page+length, " module:%s", + seq_printf(m, " module:%s", module_name(serial->type->driver.owner)); - length += sprintf(page+length, " name:\"%s\"", + seq_printf(m, " name:\"%s\"", serial->type->description); - length += sprintf(page+length, " vendor:%04x product:%04x", + seq_printf(m, " vendor:%04x product:%04x", le16_to_cpu(serial->dev->descriptor.idVendor), le16_to_cpu(serial->dev->descriptor.idProduct)); - length += sprintf(page+length, " num_ports:%d", - serial->num_ports); - length += sprintf(page+length, " port:%d", - i - serial->minor + 1); + seq_printf(m, " num_ports:%d", serial->num_ports); + seq_printf(m, " port:%d", i - serial->minor + 1); usb_make_path(serial->dev, tmp, sizeof(tmp)); - length += sprintf(page+length, " path:%s", tmp); + seq_printf(m, " path:%s", tmp); - length += sprintf(page+length, "\n"); - if ((length + begin) > (off + count)) { - usb_serial_put(serial); - goto done; - } - if ((length + begin) < off) { - begin += length; - length = 0; - } + seq_putc(m, '\n'); usb_serial_put(serial); } - *eof = 1; -done: - if (off >= (length + begin)) - return 0; - *start = page + (off-begin); - return (count < begin+length-off) ? count : begin+length-off; + return 0; } +static int serial_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, serial_proc_show, NULL); +} + +static const struct file_operations serial_proc_fops = { + .owner = THIS_MODULE, + .open = serial_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static int serial_tiocmget(struct tty_struct *tty, struct file *file) { struct usb_serial_port *port = tty->driver_data; @@ -1113,9 +1109,9 @@ static const struct tty_operations serial_ops = { .unthrottle = serial_unthrottle, .break_ctl = serial_break, .chars_in_buffer = serial_chars_in_buffer, - .read_proc = serial_read_proc, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, + .proc_fops = &serial_proc_fops, }; struct tty_driver *usb_serial_tty_driver; diff --git a/trunk/drivers/usb/storage/isd200.c b/trunk/drivers/usb/storage/isd200.c index 882c57b399f7..fdba2f69d4c9 100644 --- a/trunk/drivers/usb/storage/isd200.c +++ b/trunk/drivers/usb/storage/isd200.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -328,7 +329,7 @@ struct isd200_config { struct isd200_info { struct inquiry_data InquiryData; - struct hd_driveid *id; + u16 *id; struct isd200_config ConfigData; unsigned char *RegsBuf; unsigned char ATARegs[8]; @@ -419,19 +420,19 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; - } else if(error & MCR_ERR) { + } else if (error & ATA_MCR) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; buf->Flags = UNIT_ATTENTION; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; - } else if(error & TRK0_ERR) { + } else if (error & ATA_TRK0NF) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; buf->Flags = NOT_READY; buf->AdditionalSenseCode = 0; buf->AdditionalSenseCodeQualifier = 0; - } else if(error & ECC_ERR) { + } else if (error & ATA_UNC) { buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; buf->AdditionalSenseLength = 0xb; buf->Flags = DATA_PROTECT; @@ -547,16 +548,16 @@ static int isd200_action( struct us_data *us, int action, ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; - ata.write.CommandByte = WIN_SRST; + ata.write.CommandByte = ATA_CMD_DEV_RESET; isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; - ata.write.CommandByte = WIN_IDENTIFY; + ata.write.CommandByte = ATA_CMD_ID_ATA; isd200_set_srb(info, DMA_FROM_DEVICE, info->id, - sizeof(struct hd_driveid)); + ATA_ID_WORDS * 2); break; default: @@ -944,22 +945,22 @@ static int isd200_try_enum(struct us_data *us, unsigned char master_slave, break; if (!detect) { - if (regs[ATA_REG_STATUS_OFFSET] & BUSY_STAT) { + if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) { US_DEBUGP(" %s status is still BSY, try again...\n",mstr); } else { US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr); break; } } - /* check for BUSY_STAT and */ - /* WRERR_STAT (workaround ATA Zip drive) and */ - /* ERR_STAT (workaround for Archos CD-ROM) */ + /* check for ATA_BUSY and */ + /* ATA_DF (workaround ATA Zip drive) and */ + /* ATA_ERR (workaround for Archos CD-ROM) */ else if (regs[ATA_REG_STATUS_OFFSET] & - (BUSY_STAT | WRERR_STAT | ERR_STAT )) { + (ATA_BUSY | ATA_DF | ATA_ERR)) { US_DEBUGP(" Status indicates it is not ready, try again...\n"); } /* check for DRDY, ATA devices set DRDY after SRST */ - else if (regs[ATA_REG_STATUS_OFFSET] & READY_STAT) { + else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) { US_DEBUGP(" Identified ATA device\n"); info->DeviceFlags |= DF_ATA_DEVICE; info->DeviceHead = master_slave; @@ -1053,103 +1054,50 @@ static int isd200_manual_enum(struct us_data *us) return(retStatus); } -static void isd200_fix_driveid (struct hd_driveid *id) +static void isd200_fix_driveid(u16 *id) { #ifndef __LITTLE_ENDIAN # ifdef __BIG_ENDIAN int i; - u16 *stringcast; - - id->config = __le16_to_cpu(id->config); - id->cyls = __le16_to_cpu(id->cyls); - id->reserved2 = __le16_to_cpu(id->reserved2); - id->heads = __le16_to_cpu(id->heads); - id->track_bytes = __le16_to_cpu(id->track_bytes); - id->sector_bytes = __le16_to_cpu(id->sector_bytes); - id->sectors = __le16_to_cpu(id->sectors); - id->vendor0 = __le16_to_cpu(id->vendor0); - id->vendor1 = __le16_to_cpu(id->vendor1); - id->vendor2 = __le16_to_cpu(id->vendor2); - stringcast = (u16 *)&id->serial_no[0]; - for (i = 0; i < (20/2); i++) - stringcast[i] = __le16_to_cpu(stringcast[i]); - id->buf_type = __le16_to_cpu(id->buf_type); - id->buf_size = __le16_to_cpu(id->buf_size); - id->ecc_bytes = __le16_to_cpu(id->ecc_bytes); - stringcast = (u16 *)&id->fw_rev[0]; - for (i = 0; i < (8/2); i++) - stringcast[i] = __le16_to_cpu(stringcast[i]); - stringcast = (u16 *)&id->model[0]; - for (i = 0; i < (40/2); i++) - stringcast[i] = __le16_to_cpu(stringcast[i]); - id->dword_io = __le16_to_cpu(id->dword_io); - id->reserved50 = __le16_to_cpu(id->reserved50); - id->field_valid = __le16_to_cpu(id->field_valid); - id->cur_cyls = __le16_to_cpu(id->cur_cyls); - id->cur_heads = __le16_to_cpu(id->cur_heads); - id->cur_sectors = __le16_to_cpu(id->cur_sectors); - id->cur_capacity0 = __le16_to_cpu(id->cur_capacity0); - id->cur_capacity1 = __le16_to_cpu(id->cur_capacity1); - id->lba_capacity = __le32_to_cpu(id->lba_capacity); - id->dma_1word = __le16_to_cpu(id->dma_1word); - id->dma_mword = __le16_to_cpu(id->dma_mword); - id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes); - id->eide_dma_min = __le16_to_cpu(id->eide_dma_min); - id->eide_dma_time = __le16_to_cpu(id->eide_dma_time); - id->eide_pio = __le16_to_cpu(id->eide_pio); - id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy); - for (i = 0; i < 2; ++i) - id->words69_70[i] = __le16_to_cpu(id->words69_70[i]); - for (i = 0; i < 4; ++i) - id->words71_74[i] = __le16_to_cpu(id->words71_74[i]); - id->queue_depth = __le16_to_cpu(id->queue_depth); - for (i = 0; i < 4; ++i) - id->words76_79[i] = __le16_to_cpu(id->words76_79[i]); - id->major_rev_num = __le16_to_cpu(id->major_rev_num); - id->minor_rev_num = __le16_to_cpu(id->minor_rev_num); - id->command_set_1 = __le16_to_cpu(id->command_set_1); - id->command_set_2 = __le16_to_cpu(id->command_set_2); - id->cfsse = __le16_to_cpu(id->cfsse); - id->cfs_enable_1 = __le16_to_cpu(id->cfs_enable_1); - id->cfs_enable_2 = __le16_to_cpu(id->cfs_enable_2); - id->csf_default = __le16_to_cpu(id->csf_default); - id->dma_ultra = __le16_to_cpu(id->dma_ultra); - id->trseuc = __le16_to_cpu(id->trseuc); - id->trsEuc = __le16_to_cpu(id->trsEuc); - id->CurAPMvalues = __le16_to_cpu(id->CurAPMvalues); - id->mprc = __le16_to_cpu(id->mprc); - id->hw_config = __le16_to_cpu(id->hw_config); - id->acoustic = __le16_to_cpu(id->acoustic); - id->msrqs = __le16_to_cpu(id->msrqs); - id->sxfert = __le16_to_cpu(id->sxfert); - id->sal = __le16_to_cpu(id->sal); - id->spg = __le32_to_cpu(id->spg); - id->lba_capacity_2 = __le64_to_cpu(id->lba_capacity_2); - for (i = 0; i < 22; i++) - id->words104_125[i] = __le16_to_cpu(id->words104_125[i]); - id->last_lun = __le16_to_cpu(id->last_lun); - id->word127 = __le16_to_cpu(id->word127); - id->dlf = __le16_to_cpu(id->dlf); - id->csfo = __le16_to_cpu(id->csfo); - for (i = 0; i < 26; i++) - id->words130_155[i] = __le16_to_cpu(id->words130_155[i]); - id->word156 = __le16_to_cpu(id->word156); - for (i = 0; i < 3; i++) - id->words157_159[i] = __le16_to_cpu(id->words157_159[i]); - id->cfa_power = __le16_to_cpu(id->cfa_power); - for (i = 0; i < 14; i++) - id->words161_175[i] = __le16_to_cpu(id->words161_175[i]); - for (i = 0; i < 31; i++) - id->words176_205[i] = __le16_to_cpu(id->words176_205[i]); - for (i = 0; i < 48; i++) - id->words206_254[i] = __le16_to_cpu(id->words206_254[i]); - id->integrity_word = __le16_to_cpu(id->integrity_word); + + for (i = 0; i < ATA_ID_WORDS; i++) + id[i] = __le16_to_cpu(id[i]); # else # error "Please fix " # endif #endif } +static void isd200_dump_driveid(u16 *id) +{ + US_DEBUGP(" Identify Data Structure:\n"); + US_DEBUGP(" config = 0x%x\n", id[ATA_ID_CONFIG]); + US_DEBUGP(" cyls = 0x%x\n", id[ATA_ID_CYLS]); + US_DEBUGP(" heads = 0x%x\n", id[ATA_ID_HEADS]); + US_DEBUGP(" track_bytes = 0x%x\n", id[4]); + US_DEBUGP(" sector_bytes = 0x%x\n", id[5]); + US_DEBUGP(" sectors = 0x%x\n", id[ATA_ID_SECTORS]); + US_DEBUGP(" serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]); + US_DEBUGP(" buf_type = 0x%x\n", id[20]); + US_DEBUGP(" buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]); + US_DEBUGP(" ecc_bytes = 0x%x\n", id[22]); + US_DEBUGP(" fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]); + US_DEBUGP(" model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]); + US_DEBUGP(" max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff); + US_DEBUGP(" dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]); + US_DEBUGP(" capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8); + US_DEBUGP(" tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8); + US_DEBUGP(" tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8); + US_DEBUGP(" field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]); + US_DEBUGP(" cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]); + US_DEBUGP(" cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]); + US_DEBUGP(" cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]); + US_DEBUGP(" cur_capacity = 0x%x\n", ata_id_u32(id, 57)); + US_DEBUGP(" multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff); + US_DEBUGP(" lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY)); + US_DEBUGP(" command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]); + US_DEBUGP(" command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]); +} /************************************************************************** * isd200_get_inquiry_data @@ -1163,7 +1111,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) { struct isd200_info *info = (struct isd200_info *)us->extra; int retStatus = ISD200_GOOD; - struct hd_driveid *id = info->id; + u16 *id = info->id; US_DEBUGP("Entering isd200_get_inquiry_data\n"); @@ -1180,8 +1128,7 @@ static int isd200_get_inquiry_data( struct us_data *us ) /* this must be an ATA device */ /* perform an ATA Command Identify */ transferStatus = isd200_action( us, ACTION_IDENTIFY, - id, - sizeof(struct hd_driveid) ); + id, ATA_ID_WORDS * 2); if (transferStatus != ISD200_TRANSPORT_GOOD) { /* Error issuing ATA Command Identify */ US_DEBUGP(" Error issuing ATA Command Identify\n"); @@ -1191,35 +1138,9 @@ static int isd200_get_inquiry_data( struct us_data *us ) int i; __be16 *src; __u16 *dest; - isd200_fix_driveid(id); - US_DEBUGP(" Identify Data Structure:\n"); - US_DEBUGP(" config = 0x%x\n", id->config); - US_DEBUGP(" cyls = 0x%x\n", id->cyls); - US_DEBUGP(" heads = 0x%x\n", id->heads); - US_DEBUGP(" track_bytes = 0x%x\n", id->track_bytes); - US_DEBUGP(" sector_bytes = 0x%x\n", id->sector_bytes); - US_DEBUGP(" sectors = 0x%x\n", id->sectors); - US_DEBUGP(" serial_no[0] = 0x%x\n", id->serial_no[0]); - US_DEBUGP(" buf_type = 0x%x\n", id->buf_type); - US_DEBUGP(" buf_size = 0x%x\n", id->buf_size); - US_DEBUGP(" ecc_bytes = 0x%x\n", id->ecc_bytes); - US_DEBUGP(" fw_rev[0] = 0x%x\n", id->fw_rev[0]); - US_DEBUGP(" model[0] = 0x%x\n", id->model[0]); - US_DEBUGP(" max_multsect = 0x%x\n", id->max_multsect); - US_DEBUGP(" dword_io = 0x%x\n", id->dword_io); - US_DEBUGP(" capability = 0x%x\n", id->capability); - US_DEBUGP(" tPIO = 0x%x\n", id->tPIO); - US_DEBUGP(" tDMA = 0x%x\n", id->tDMA); - US_DEBUGP(" field_valid = 0x%x\n", id->field_valid); - US_DEBUGP(" cur_cyls = 0x%x\n", id->cur_cyls); - US_DEBUGP(" cur_heads = 0x%x\n", id->cur_heads); - US_DEBUGP(" cur_sectors = 0x%x\n", id->cur_sectors); - US_DEBUGP(" cur_capacity = 0x%x\n", (id->cur_capacity1 << 16) + id->cur_capacity0 ); - US_DEBUGP(" multsect = 0x%x\n", id->multsect); - US_DEBUGP(" lba_capacity = 0x%x\n", id->lba_capacity); - US_DEBUGP(" command_set_1 = 0x%x\n", id->command_set_1); - US_DEBUGP(" command_set_2 = 0x%x\n", id->command_set_2); + isd200_fix_driveid(id); + isd200_dump_driveid(id); memset(&info->InquiryData, 0, sizeof(info->InquiryData)); @@ -1229,30 +1150,30 @@ static int isd200_get_inquiry_data( struct us_data *us ) /* The length must be at least 36 (5 + 31) */ info->InquiryData.AdditionalLength = 0x1F; - if (id->command_set_1 & COMMANDSET_MEDIA_STATUS) { + if (id[ATA_ID_COMMAND_SET_1] & COMMANDSET_MEDIA_STATUS) { /* set the removable bit */ info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; info->DeviceFlags |= DF_REMOVABLE_MEDIA; } /* Fill in vendor identification fields */ - src = (__be16*)id->model; + src = (__be16 *)&id[ATA_ID_PROD]; dest = (__u16*)info->InquiryData.VendorId; for (i=0;i<4;i++) dest[i] = be16_to_cpu(src[i]); - src = (__be16*)(id->model+8); + src = (__be16 *)&id[ATA_ID_PROD + 8/2]; dest = (__u16*)info->InquiryData.ProductId; for (i=0;i<8;i++) dest[i] = be16_to_cpu(src[i]); - src = (__be16*)id->fw_rev; + src = (__be16 *)&id[ATA_ID_FW_REV]; dest = (__u16*)info->InquiryData.ProductRevisionLevel; for (i=0;i<2;i++) dest[i] = be16_to_cpu(src[i]); /* determine if it supports Media Status Notification */ - if (id->command_set_2 & COMMANDSET_MEDIA_STATUS) { + if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) { US_DEBUGP(" Device supports Media Status Notification\n"); /* Indicate that it is enabled, even though it is not @@ -1301,7 +1222,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, union ata_cdb * ataCdb) { struct isd200_info *info = (struct isd200_info *)us->extra; - struct hd_driveid *id = info->id; + u16 *id = info->id; int sendToTransport = 1; unsigned char sectnum, head; unsigned short cylinder; @@ -1369,13 +1290,12 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n"); - if (id->capability & CAPABILITY_LBA ) { - capacity = id->lba_capacity - 1; - } else { - capacity = (id->heads * - id->cyls * - id->sectors) - 1; - } + if (ata_id_has_lba(id)) + capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1; + else + capacity = (id[ATA_ID_HEADS] * id[ATA_ID_CYLS] * + id[ATA_ID_SECTORS]) - 1; + readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity); readCapacityData.BytesPerBlock = cpu_to_be32(0x200); @@ -1392,16 +1312,16 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; - if (id->capability & CAPABILITY_LBA) { + if (ata_id_has_lba(id)) { sectnum = (unsigned char)(lba); cylinder = (unsigned short)(lba>>8); head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); } else { - sectnum = (unsigned char)((lba % id->sectors) + 1); - cylinder = (unsigned short)(lba / (id->sectors * - id->heads)); - head = (unsigned char)((lba / id->sectors) % - id->heads); + sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1); + cylinder = (u16)(lba / (id[ATA_ID_SECTORS] * + id[ATA_ID_HEADS])); + head = (u8)((lba / id[ATA_ID_SECTORS]) % + id[ATA_ID_HEADS]); } ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; @@ -1415,7 +1335,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); ataCdb->write.CylinderLowByte = (unsigned char)cylinder; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.CommandByte = WIN_READ; + ataCdb->write.CommandByte = ATA_CMD_PIO_READ; break; case WRITE_10: @@ -1424,14 +1344,16 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; - if (id->capability & CAPABILITY_LBA) { + if (ata_id_has_lba(id)) { sectnum = (unsigned char)(lba); cylinder = (unsigned short)(lba>>8); head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); } else { - sectnum = (unsigned char)((lba % id->sectors) + 1); - cylinder = (unsigned short)(lba / (id->sectors * id->heads)); - head = (unsigned char)((lba / id->sectors) % id->heads); + sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1); + cylinder = (u16)(lba / (id[ATA_ID_SECTORS] * + id[ATA_ID_HEADS])); + head = (u8)((lba / id[ATA_ID_SECTORS]) % + id[ATA_ID_HEADS]); } ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; @@ -1445,7 +1367,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); ataCdb->write.CylinderLowByte = (unsigned char)cylinder; ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.CommandByte = WIN_WRITE; + ataCdb->write.CommandByte = ATA_CMD_PIO_WRITE; break; case ALLOW_MEDIUM_REMOVAL: @@ -1459,7 +1381,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? - WIN_DOORLOCK : WIN_DOORUNLOCK; + ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Not removeable media, just report okay\n"); @@ -1539,8 +1461,7 @@ static int isd200_init_info(struct us_data *us) if (!info) retStatus = ISD200_ERROR; else { - info->id = (struct hd_driveid *) - kzalloc(sizeof(struct hd_driveid), GFP_KERNEL); + info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL); info->RegsBuf = (unsigned char *) kmalloc(sizeof(info->ATARegs), GFP_KERNEL); info->srb.sense_buffer = diff --git a/trunk/drivers/usb/wusbcore/devconnect.c b/trunk/drivers/usb/wusbcore/devconnect.c index f0aac0cf315a..386eaa22d215 100644 --- a/trunk/drivers/usb/wusbcore/devconnect.c +++ b/trunk/drivers/usb/wusbcore/devconnect.c @@ -471,7 +471,7 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc) */ static void wusbhc_keep_alive_run(struct work_struct *ws) { - struct delayed_work *dw = container_of(ws, struct delayed_work, work); + struct delayed_work *dw = to_delayed_work(ws); struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer); mutex_lock(&wusbhc->mutex); diff --git a/trunk/drivers/video/68328fb.c b/trunk/drivers/video/68328fb.c index 7f907fb23b8a..0b17824b0eb5 100644 --- a/trunk/drivers/video/68328fb.c +++ b/trunk/drivers/video/68328fb.c @@ -471,9 +471,11 @@ int __init mc68x328fb_init(void) fb_info.pseudo_palette = &mc68x328fb_pseudo_palette; fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; - fb_alloc_cmap(&fb_info.cmap, 256, 0); + if (fb_alloc_cmap(&fb_info.cmap, 256, 0)) + return -ENOMEM; if (register_framebuffer(&fb_info) < 0) { + fb_dealloc_cmap(&fb_info.cmap); return -EINVAL; } @@ -494,6 +496,7 @@ module_init(mc68x328fb_init); static void __exit mc68x328fb_cleanup(void) { unregister_framebuffer(&fb_info); + fb_dealloc_cmap(&fb_info.cmap); } module_exit(mc68x328fb_cleanup); diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index 41c27a44bd82..ffe2f2796e29 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -1597,32 +1597,8 @@ config FB_VT8623 Driver for CastleRock integrated graphics core in the VIA VT8623 [Apollo CLE266] chipset. -config FB_CYBLA - tristate "Cyberblade/i1 support" - depends on FB && PCI && X86_32 && !64BIT - select FB_CFB_IMAGEBLIT - ---help--- - This driver is supposed to support the Trident Cyberblade/i1 - graphics core integrated in the VIA VT8601A North Bridge, - also known as VIA Apollo PLE133. - - Status: - - Developed, tested and working on EPIA 5000 and EPIA 800. - - Does work reliable on all systems with CRT/LCD connected to - normal VGA ports. - - Should work on systems that do use the internal LCD port, but - this is absolutely not tested. - - Character imageblit, copyarea and rectangle fill are hw accelerated, - ypan scrolling is used by default. - - Please do read . - - To compile this driver as a module, choose M here: the - module will be called cyblafb. - config FB_TRIDENT - tristate "Trident support" + tristate "Trident/CyberXXX/CyberBlade support" depends on FB && PCI select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -1633,21 +1609,14 @@ config FB_TRIDENT and Blade XP. There are also integrated versions of these chips called CyberXXXX, CyberImage or CyberBlade. These chips are mostly found in laptops - but also on some motherboards. For more information, read - + but also on some motherboards including early VIA EPIA motherboards. + For more information, read Say Y if you have such a graphics board. To compile this driver as a module, choose M here: the module will be called tridentfb. -config FB_TRIDENT_ACCEL - bool "Trident Acceleration functions (EXPERIMENTAL)" - depends on FB_TRIDENT && EXPERIMENTAL - ---help--- - This will compile the Trident frame buffer device with - acceleration functions. - config FB_ARK tristate "ARK 2000PV support" depends on FB && PCI @@ -1920,6 +1889,30 @@ config FB_TMIO_ACCELL depends on FB_TMIO default y +config FB_S3C + tristate "Samsung S3C framebuffer support" + depends on FB && ARCH_S3C64XX + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Frame buffer driver for the built-in FB controller in the Samsung + SoC line from the S3C2443 onwards, including the S3C2416, S3C2450, + and the S3C64XX series such as the S3C6400 and S3C6410. + + These chips all have the same basic framebuffer design with the + actual capabilities depending on the chip. For instance the S3C6400 + and S3C6410 support 4 hardware windows whereas the S3C24XX series + currently only have two. + + Currently the support is only for the S3C6400 and S3C6410 SoCs. + +config FB_S3C_DEBUG_REGWRITE + bool "Debug register writes" + depends on FB_S3C + ---help--- + Show all register writes via printk(KERN_DEBUG) + config FB_S3C2410 tristate "S3C2410 LCD framebuffer support" depends on FB && ARCH_S3C2410 diff --git a/trunk/drivers/video/Makefile b/trunk/drivers/video/Makefile index bb265eca7d57..0dbd6c68d76b 100644 --- a/trunk/drivers/video/Makefile +++ b/trunk/drivers/video/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o obj-$(CONFIG_FB_MAC) += macfb.o obj-$(CONFIG_FB_HECUBA) += hecubafb.o +obj-$(CONFIG_FB_N411) += n411.o obj-$(CONFIG_FB_HGA) += hgafb.o obj-$(CONFIG_FB_XVR500) += sunxvr500.o obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o @@ -110,6 +111,7 @@ obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_SH7760) += sh7760fb.o obj-$(CONFIG_FB_IMX) += imxfb.o +obj-$(CONFIG_FB_S3C) += s3c-fb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o diff --git a/trunk/drivers/video/amba-clcd.c b/trunk/drivers/video/amba-clcd.c index 4e046fed1380..61050ab14128 100644 --- a/trunk/drivers/video/amba-clcd.c +++ b/trunk/drivers/video/amba-clcd.c @@ -408,7 +408,9 @@ static int clcdfb_register(struct clcd_fb *fb) /* * Allocate colourmap. */ - fb_alloc_cmap(&fb->fb.cmap, 256, 0); + ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0); + if (ret) + goto unmap; /* * Ensure interrupts are disabled. @@ -426,6 +428,8 @@ static int clcdfb_register(struct clcd_fb *fb) printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); + fb_dealloc_cmap(&fb->fb.cmap); + unmap: iounmap(fb->regs); free_clk: clk_put(fb->clk); @@ -485,6 +489,8 @@ static int clcdfb_remove(struct amba_device *dev) clcdfb_disable(fb); unregister_framebuffer(&fb->fb); + if (fb->fb.cmap.len) + fb_dealloc_cmap(&fb->fb.cmap); iounmap(fb->regs); clk_put(fb->clk); diff --git a/trunk/drivers/video/amifb.c b/trunk/drivers/video/amifb.c index 100f23661465..82bedd7f7789 100644 --- a/trunk/drivers/video/amifb.c +++ b/trunk/drivers/video/amifb.c @@ -2437,7 +2437,9 @@ static int __init amifb_init(void) goto amifb_error; } - fb_alloc_cmap(&fb_info.cmap, 1<fix = asiliantfb_fix; p->fix.smem_start = addr; p->var = asiliantfb_var; p->fbops = &asiliantfb_ops; p->flags = FBINFO_DEFAULT; - fb_alloc_cmap(&p->cmap, 256, 0); + err = fb_alloc_cmap(&p->cmap, 256, 0); + if (err) { + printk(KERN_ERR "C&T 69000 fb failed to alloc cmap memory\n"); + return err; + } - if (register_framebuffer(p) < 0) { + err = register_framebuffer(p); + if (err < 0) { printk(KERN_ERR "C&T 69000 framebuffer failed to register\n"); - return; + fb_dealloc_cmap(&p->cmap); + return err; } printk(KERN_INFO "fb%d: Asiliant 69000 frame buffer (%dK RAM detected)\n", @@ -532,6 +540,7 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) { unsigned long addr, size; struct fb_info *p; + int err; if ((dp->resource[0].flags & IORESOURCE_MEM) == 0) return -ENODEV; @@ -560,7 +569,13 @@ asiliantfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) pci_write_config_dword(dp, 4, 0x02800083); writeb(3, p->screen_base + 0x400784); - init_asiliant(p, addr); + err = init_asiliant(p, addr); + if (err) { + iounmap(p->screen_base); + release_mem_region(addr, size); + framebuffer_release(p); + return err; + } pci_set_drvdata(dp, p); return 0; @@ -571,6 +586,7 @@ static void __devexit asiliantfb_remove(struct pci_dev *dp) struct fb_info *p = pci_get_drvdata(dp); unregister_framebuffer(p); + fb_dealloc_cmap(&p->cmap); iounmap(p->screen_base); release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0)); pci_set_drvdata(dp, NULL); diff --git a/trunk/drivers/video/aty/mach64_accel.c b/trunk/drivers/video/aty/mach64_accel.c index a8f60c33863c..0cc9724e61a2 100644 --- a/trunk/drivers/video/aty/mach64_accel.c +++ b/trunk/drivers/video/aty/mach64_accel.c @@ -39,7 +39,8 @@ void aty_reset_engine(const struct atyfb_par *par) { /* reset engine */ aty_st_le32(GEN_TEST_CNTL, - aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par); + aty_ld_le32(GEN_TEST_CNTL, par) & + ~(GUI_ENGINE_ENABLE | HWCURSOR_ENABLE), par); /* enable engine */ aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par); diff --git a/trunk/drivers/video/aty/mach64_cursor.c b/trunk/drivers/video/aty/mach64_cursor.c index faf95da8fcbc..04c710804bb0 100644 --- a/trunk/drivers/video/aty/mach64_cursor.c +++ b/trunk/drivers/video/aty/mach64_cursor.c @@ -77,9 +77,13 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) if (par->asleep) return -EPERM; - /* Hide cursor */ wait_for_fifo(1, par); - aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par); + if (cursor->enable) + aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) + | HWCURSOR_ENABLE, par); + else + aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) + & ~HWCURSOR_ENABLE, par); /* set position */ if (cursor->set & FB_CUR_SETPOS) { @@ -109,7 +113,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) y<<=1; h<<=1; } - wait_for_fifo(4, par); + wait_for_fifo(3, par); aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par); aty_st_le32(CUR_HORZ_VERT_OFF, ((u32) (64 - h + yoff) << 16) | xoff, par); @@ -177,11 +181,6 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor) } } - if (cursor->enable) { - wait_for_fifo(1, par); - aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) - | HWCURSOR_ENABLE, par); - } return 0; } diff --git a/trunk/drivers/video/aty/radeon_pm.c b/trunk/drivers/video/aty/radeon_pm.c index 1de0c0032468..97a1f095f327 100644 --- a/trunk/drivers/video/aty/radeon_pm.c +++ b/trunk/drivers/video/aty/radeon_pm.c @@ -89,6 +89,9 @@ static struct radeon_device_id radeon_workaround_list[] = { BUGFIX("Acer Aspire 2010", PCI_VENDOR_ID_AI, 0x0061, radeon_pm_off, radeon_reinitialize_M10), + BUGFIX("Acer Travelmate 290D/292LMi", + PCI_VENDOR_ID_AI, 0x005a, + radeon_pm_off, radeon_reinitialize_M10), { .ident = NULL } }; diff --git a/trunk/drivers/video/backlight/backlight.c b/trunk/drivers/video/backlight/backlight.c index 157057c79ca3..dd37cbcaf8ce 100644 --- a/trunk/drivers/video/backlight/backlight.c +++ b/trunk/drivers/video/backlight/backlight.c @@ -35,6 +35,8 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; bd = container_of(self, struct backlight_device, fb_notif); + if (!lock_fb_info(evdata->info)) + return -ENODEV; mutex_lock(&bd->ops_lock); if (bd->ops) if (!bd->ops->check_fb || @@ -47,6 +49,7 @@ static int fb_notifier_callback(struct notifier_block *self, backlight_update_status(bd); } mutex_unlock(&bd->ops_lock); + unlock_fb_info(evdata->info); return 0; } diff --git a/trunk/drivers/video/backlight/lcd.c b/trunk/drivers/video/backlight/lcd.c index b6449470106c..0bb13df0fa89 100644 --- a/trunk/drivers/video/backlight/lcd.c +++ b/trunk/drivers/video/backlight/lcd.c @@ -40,6 +40,8 @@ static int fb_notifier_callback(struct notifier_block *self, if (!ld->ops) return 0; + if (!lock_fb_info(evdata->info)) + return -ENODEV; mutex_lock(&ld->ops_lock); if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) { if (event == FB_EVENT_BLANK) { @@ -51,6 +53,7 @@ static int fb_notifier_callback(struct notifier_block *self, } } mutex_unlock(&ld->ops_lock); + unlock_fb_info(evdata->info); return 0; } diff --git a/trunk/drivers/video/cirrusfb.c b/trunk/drivers/video/cirrusfb.c index a2aa6ddffbe2..d42e385f091c 100644 --- a/trunk/drivers/video/cirrusfb.c +++ b/trunk/drivers/video/cirrusfb.c @@ -34,8 +34,6 @@ * */ -#define CIRRUSFB_VERSION "2.0-pre2" - #include #include #include @@ -72,20 +70,9 @@ * */ -/* enable debug output? */ -/* #define CIRRUSFB_DEBUG 1 */ - /* disable runtime assertions? */ /* #define CIRRUSFB_NDEBUG */ -/* debug output */ -#ifdef CIRRUSFB_DEBUG -#define DPRINTK(fmt, args...) \ - printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) -#else -#define DPRINTK(fmt, args...) -#endif - /* debugging assertions */ #ifndef CIRRUSFB_NDEBUG #define assert(expr) \ @@ -108,14 +95,15 @@ /* board types */ enum cirrus_board { BT_NONE = 0, - BT_SD64, - BT_PICCOLO, - BT_PICASSO, - BT_SPECTRUM, + BT_SD64, /* GD5434 */ + BT_PICCOLO, /* GD5426 */ + BT_PICASSO, /* GD5426 or GD5428 */ + BT_SPECTRUM, /* GD5426 or GD5428 */ BT_PICASSO4, /* GD5446 */ BT_ALPINE, /* GD543x/4x */ BT_GD5480, - BT_LAGUNA, /* GD546x */ + BT_LAGUNA, /* GD5462/64 */ + BT_LAGUNAB, /* GD5465 */ }; /* @@ -150,15 +138,17 @@ static const struct cirrusfb_board_info_rec { .maxclock = { /* guess */ /* the SD64/P4 have a higher max. videoclock */ - 140000, 140000, 140000, 140000, 140000, + 135100, 135100, 85500, 85500, 0 }, .init_sr07 = true, .init_sr1f = true, .scrn_start_bit19 = true, .sr07 = 0xF0, .sr07_1bpp = 0xF0, + .sr07_1bpp_mux = 0xF6, .sr07_8bpp = 0xF1, - .sr1f = 0x20 + .sr07_8bpp_mux = 0xF7, + .sr1f = 0x1E }, [BT_PICCOLO] = { .name = "CL Piccolo", @@ -210,9 +200,11 @@ static const struct cirrusfb_board_info_rec { .init_sr07 = true, .init_sr1f = false, .scrn_start_bit19 = true, - .sr07 = 0x20, - .sr07_1bpp = 0x20, - .sr07_8bpp = 0x21, + .sr07 = 0xA0, + .sr07_1bpp = 0xA0, + .sr07_1bpp_mux = 0xA6, + .sr07_8bpp = 0xA1, + .sr07_8bpp_mux = 0xA7, .sr1f = 0 }, [BT_ALPINE] = { @@ -225,8 +217,8 @@ static const struct cirrusfb_board_info_rec { .init_sr1f = true, .scrn_start_bit19 = true, .sr07 = 0xA0, - .sr07_1bpp = 0xA1, - .sr07_1bpp_mux = 0xA7, + .sr07_1bpp = 0xA0, + .sr07_1bpp_mux = 0xA6, .sr07_8bpp = 0xA1, .sr07_8bpp_mux = 0xA7, .sr1f = 0x1C @@ -247,8 +239,18 @@ static const struct cirrusfb_board_info_rec { [BT_LAGUNA] = { .name = "CL Laguna", .maxclock = { - /* guess */ - 135100, 135100, 135100, 135100, 135100, + /* taken from X11 code */ + 170000, 170000, 170000, 170000, 135100, + }, + .init_sr07 = false, + .init_sr1f = false, + .scrn_start_bit19 = true, + }, + [BT_LAGUNAB] = { + .name = "CL Laguna AGP", + .maxclock = { + /* taken from X11 code */ + 170000, 250000, 170000, 170000, 135100, }, .init_sr07 = false, .init_sr1f = false, @@ -262,8 +264,8 @@ static const struct cirrusfb_board_info_rec { static struct pci_device_id cirrusfb_pci_table[] = { CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE), - CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE), - CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE), + CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_SD64), + CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_SD64), CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */ CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE), CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE), @@ -271,7 +273,7 @@ static struct pci_device_id cirrusfb_pci_table[] = { CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */ CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */ CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */ - CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA), /* CL Laguna 3DA*/ + CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNAB), /* CL Laguna 3DA*/ { 0, } }; MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); @@ -326,10 +328,6 @@ static const struct { }; #endif /* CONFIG_ZORRO */ -struct cirrusfb_regs { - int multiplexing; -}; - #ifdef CIRRUSFB_DEBUG enum cirrusfb_dbg_reg_class { CRT, @@ -340,10 +338,12 @@ enum cirrusfb_dbg_reg_class { /* info about board */ struct cirrusfb_info { u8 __iomem *regbase; + u8 __iomem *laguna_mmio; enum cirrus_board btype; unsigned char SFR; /* Shadow of special function register */ - struct cirrusfb_regs currentmode; + int multiplexing; + int doubleVCLK; int blank_mode; u32 pseudo_palette[16]; @@ -357,43 +357,8 @@ static char *mode_option __devinitdata = "640x480@60"; /**** BEGIN PROTOTYPES ******************************************************/ /*--- Interface used by the world ------------------------------------------*/ -static int cirrusfb_init(void); -#ifndef MODULE -static int cirrusfb_setup(char *options); -#endif - -static int cirrusfb_open(struct fb_info *info, int user); -static int cirrusfb_release(struct fb_info *info, int user); -static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info); -static int cirrusfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info); -static int cirrusfb_set_par(struct fb_info *info); static int cirrusfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); -static int cirrusfb_blank(int blank_mode, struct fb_info *info); -static void cirrusfb_fillrect(struct fb_info *info, - const struct fb_fillrect *region); -static void cirrusfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area); -static void cirrusfb_imageblit(struct fb_info *info, - const struct fb_image *image); - -/* function table of the above functions */ -static struct fb_ops cirrusfb_ops = { - .owner = THIS_MODULE, - .fb_open = cirrusfb_open, - .fb_release = cirrusfb_release, - .fb_setcolreg = cirrusfb_setcolreg, - .fb_check_var = cirrusfb_check_var, - .fb_set_par = cirrusfb_set_par, - .fb_pan_display = cirrusfb_pan_display, - .fb_blank = cirrusfb_blank, - .fb_fillrect = cirrusfb_fillrect, - .fb_copyarea = cirrusfb_copyarea, - .fb_imageblit = cirrusfb_imageblit, -}; /*--- Internal routines ----------------------------------------------------*/ static void init_vgachip(struct fb_info *info); @@ -421,22 +386,27 @@ static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, u_short x, u_short y, u_short width, u_short height, - u_char color, u_short line_length); + u32 fg_color, u32 bg_color, + u_short line_length, u_char blitmode); static void bestclock(long freq, int *nom, int *den, int *div); #ifdef CIRRUSFB_DEBUG -static void cirrusfb_dump(void); -static void cirrusfb_dbg_reg_dump(caddr_t regbase); -static void cirrusfb_dbg_print_regs(caddr_t regbase, +static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase); +static void cirrusfb_dbg_print_regs(struct fb_info *info, + caddr_t regbase, enum cirrusfb_dbg_reg_class reg_class, ...); -static void cirrusfb_dbg_print_byte(const char *name, unsigned char val); #endif /* CIRRUSFB_DEBUG */ /*** END PROTOTYPES ********************************************************/ /*****************************************************************************/ /*** BEGIN Interface Used by the World ***************************************/ +static inline int is_laguna(const struct cirrusfb_info *cinfo) +{ + return cinfo->btype == BT_LAGUNA || cinfo->btype == BT_LAGUNAB; +} + static int opencount; /*--- Open /dev/fbx ---------------------------------------------------------*/ @@ -460,85 +430,94 @@ static int cirrusfb_release(struct fb_info *info, int user) /**** BEGIN Hardware specific Routines **************************************/ /* Check if the MCLK is not a better clock source */ -static int cirrusfb_check_mclk(struct cirrusfb_info *cinfo, long freq) +static int cirrusfb_check_mclk(struct fb_info *info, long freq) { + struct cirrusfb_info *cinfo = info->par; long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f; /* Read MCLK value */ mclk = (14318 * mclk) >> 3; - DPRINTK("Read MCLK of %ld kHz\n", mclk); + dev_dbg(info->device, "Read MCLK of %ld kHz\n", mclk); /* Determine if we should use MCLK instead of VCLK, and if so, what we * should divide it by to get VCLK */ if (abs(freq - mclk) < 250) { - DPRINTK("Using VCLK = MCLK\n"); + dev_dbg(info->device, "Using VCLK = MCLK\n"); return 1; } else if (abs(freq - (mclk / 2)) < 250) { - DPRINTK("Using VCLK = MCLK/2\n"); + dev_dbg(info->device, "Using VCLK = MCLK/2\n"); return 2; } return 0; } -static int cirrusfb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) +static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var, + struct fb_info *info) { - int yres; - /* memory size in pixels */ - unsigned pixels = info->screen_size * 8 / var->bits_per_pixel; + long freq; + long maxclock; + struct cirrusfb_info *cinfo = info->par; + unsigned maxclockidx = var->bits_per_pixel >> 3; - switch (var->bits_per_pixel) { - case 1: - pixels /= 4; - break; /* 8 pixel per byte, only 1/4th of mem usable */ - case 8: - case 16: - case 32: - break; /* 1 pixel == 1 byte */ - default: - printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..." - "color depth not supported.\n", - var->xres, var->yres, var->bits_per_pixel); - DPRINTK("EXIT - EINVAL error\n"); - return -EINVAL; - } + /* convert from ps to kHz */ + freq = PICOS2KHZ(var->pixclock); - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; - /* use highest possible virtual resolution */ - if (var->yres_virtual == -1) { - var->yres_virtual = pixels / var->xres_virtual; + dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); - printk(KERN_INFO "cirrusfb: virtual resolution set to " - "maximum of %dx%d\n", var->xres_virtual, - var->yres_virtual); - } - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; + maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; + cinfo->multiplexing = 0; - if (var->xres_virtual * var->yres_virtual > pixels) { - printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... " - "virtual resolution too high to fit into video memory!\n", - var->xres_virtual, var->yres_virtual, - var->bits_per_pixel); - DPRINTK("EXIT - EINVAL error\n"); + /* If the frequency is greater than we can support, we might be able + * to use multiplexing for the video mode */ + if (freq > maxclock) { + dev_err(info->device, + "Frequency greater than maxclock (%ld kHz)\n", + maxclock); return -EINVAL; } + /* + * Additional constraint: 8bpp uses DAC clock doubling to allow maximum + * pixel clock + */ + if (var->bits_per_pixel == 8) { + switch (cinfo->btype) { + case BT_ALPINE: + case BT_SD64: + case BT_PICASSO4: + if (freq > 85500) + cinfo->multiplexing = 1; + break; + case BT_GD5480: + if (freq > 135100) + cinfo->multiplexing = 1; + break; + default: + break; + } + } - if (var->xoffset < 0) - var->xoffset = 0; - if (var->yoffset < 0) - var->yoffset = 0; + /* If we have a 1MB 5434, we need to put ourselves in a mode where + * the VCLK is double the pixel clock. */ + cinfo->doubleVCLK = 0; + if (cinfo->btype == BT_SD64 && info->fix.smem_len <= MB_ && + var->bits_per_pixel == 16) { + cinfo->doubleVCLK = 1; + } - /* truncate xoffset and yoffset to maximum if too high */ - if (var->xoffset > var->xres_virtual - var->xres) - var->xoffset = var->xres_virtual - var->xres - 1; - if (var->yoffset > var->yres_virtual - var->yres) - var->yoffset = var->yres_virtual - var->yres - 1; + return 0; +} + +static int cirrusfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + int yres; + /* memory size in pixels */ + unsigned pixels = info->screen_size * 8 / var->bits_per_pixel; + struct cirrusfb_info *cinfo = info->par; switch (var->bits_per_pixel) { case 1: @@ -550,7 +529,7 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, case 8: var->red.offset = 0; - var->red.length = 6; + var->red.length = 8; var->green = var->red; var->blue = var->red; break; @@ -561,20 +540,20 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, var->green.offset = -3; var->blue.offset = 8; } else { - var->red.offset = 10; + var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; } var->red.length = 5; - var->green.length = 5; + var->green.length = 6; var->blue.length = 5; break; - case 32: + case 24: if (isPReP) { - var->red.offset = 8; - var->green.offset = 16; - var->blue.offset = 24; + var->red.offset = 0; + var->green.offset = 8; + var->blue.offset = 16; } else { var->red.offset = 16; var->green.offset = 8; @@ -586,12 +565,45 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, break; default: - DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); + dev_dbg(info->device, + "Unsupported bpp size: %d\n", var->bits_per_pixel); assert(false); /* should never occur */ break; } + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + /* use highest possible virtual resolution */ + if (var->yres_virtual == -1) { + var->yres_virtual = pixels / var->xres_virtual; + + dev_info(info->device, + "virtual resolution set to maximum of %dx%d\n", + var->xres_virtual, var->yres_virtual); + } + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xres_virtual * var->yres_virtual > pixels) { + dev_err(info->device, "mode %dx%dx%d rejected... " + "virtual resolution too high to fit into video memory!\n", + var->xres_virtual, var->yres_virtual, + var->bits_per_pixel); + return -EINVAL; + } + + if (var->xoffset < 0) + var->xoffset = 0; + if (var->yoffset < 0) + var->yoffset = 0; + + /* truncate xoffset and yoffset to maximum if too high */ + if (var->xoffset > var->xres_virtual - var->xres) + var->xoffset = var->xres_virtual - var->xres - 1; + if (var->yoffset > var->yres_virtual - var->yres) + var->yoffset = var->yres_virtual - var->yres - 1; + var->red.msb_right = var->green.msb_right = var->blue.msb_right = @@ -606,99 +618,31 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, yres = (yres + 1) / 2; if (yres >= 1280) { - printk(KERN_ERR "cirrusfb: ERROR: VerticalTotal >= 1280; " + dev_err(info->device, "ERROR: VerticalTotal >= 1280; " "special treatment required! (TODO)\n"); - DPRINTK("EXIT - EINVAL error\n"); return -EINVAL; } - return 0; -} - -static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, - struct cirrusfb_regs *regs, - struct fb_info *info) -{ - long freq; - long maxclock; - int maxclockidx = var->bits_per_pixel >> 3; - struct cirrusfb_info *cinfo = info->par; - - switch (var->bits_per_pixel) { - case 1: - info->fix.line_length = var->xres_virtual / 8; - info->fix.visual = FB_VISUAL_MONO10; - break; - - case 8: - info->fix.line_length = var->xres_virtual; - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; - - case 16: - case 32: - info->fix.line_length = var->xres_virtual * maxclockidx; - info->fix.visual = FB_VISUAL_TRUECOLOR; - break; - - default: - DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); - assert(false); - /* should never occur */ - break; - } - - info->fix.type = FB_TYPE_PACKED_PIXELS; - - /* convert from ps to kHz */ - freq = PICOS2KHZ(var->pixclock); - - DPRINTK("desired pixclock: %ld kHz\n", freq); - - maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; - regs->multiplexing = 0; + if (cirrusfb_check_pixclock(var, info)) + return -EINVAL; - /* If the frequency is greater than we can support, we might be able - * to use multiplexing for the video mode */ - if (freq > maxclock) { - switch (cinfo->btype) { - case BT_ALPINE: - case BT_GD5480: - regs->multiplexing = 1; - break; + if (!is_laguna(cinfo)) + var->accel_flags = FB_ACCELF_TEXT; - default: - printk(KERN_ERR "cirrusfb: Frequency greater " - "than maxclock (%ld kHz)\n", maxclock); - DPRINTK("EXIT - return -EINVAL\n"); - return -EINVAL; - } - } -#if 0 - /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where - * the VCLK is double the pixel clock. */ - switch (var->bits_per_pixel) { - case 16: - case 32: - if (var->xres <= 800) - /* Xbh has this type of clock for 32-bit */ - freq /= 2; - break; - } -#endif return 0; } -static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo, - int div) +static void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div) { + struct cirrusfb_info *cinfo = info->par; unsigned char old1f, old1e; + assert(cinfo != NULL); old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40; if (div) { - DPRINTK("Set %s as pixclock source.\n", - (div == 2) ? "MCLK/2" : "MCLK"); + dev_dbg(info->device, "Set %s as pixclock source.\n", + (div == 2) ? "MCLK/2" : "MCLK"); old1f |= 0x40; old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1; if (div == 2) @@ -718,101 +662,119 @@ static int cirrusfb_set_par_foo(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; struct fb_var_screeninfo *var = &info->var; - struct cirrusfb_regs regs; u8 __iomem *regbase = cinfo->regbase; unsigned char tmp; - int offset = 0, err; + int pitch; const struct cirrusfb_board_info_rec *bi; int hdispend, hsyncstart, hsyncend, htotal; int yres, vdispend, vsyncstart, vsyncend, vtotal; long freq; int nom, den, div; + unsigned int control = 0, format = 0, threshold = 0; - DPRINTK("ENTER\n"); - DPRINTK("Requested mode: %dx%dx%d\n", + dev_dbg(info->device, "Requested mode: %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel); - DPRINTK("pixclock: %d\n", var->pixclock); - init_vgachip(info); + switch (var->bits_per_pixel) { + case 1: + info->fix.line_length = var->xres_virtual / 8; + info->fix.visual = FB_VISUAL_MONO10; + break; - err = cirrusfb_decode_var(var, ®s, info); - if (err) { - /* should never happen */ - DPRINTK("mode change aborted. invalid var.\n"); - return -EINVAL; + case 8: + info->fix.line_length = var->xres_virtual; + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + + case 16: + case 24: + info->fix.line_length = var->xres_virtual * + var->bits_per_pixel >> 3; + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; } + info->fix.type = FB_TYPE_PACKED_PIXELS; + + init_vgachip(info); bi = &cirrusfb_board_info[cinfo->btype]; hsyncstart = var->xres + var->right_margin; hsyncend = hsyncstart + var->hsync_len; - htotal = (hsyncend + var->left_margin) / 8 - 5; - hdispend = var->xres / 8 - 1; - hsyncstart = hsyncstart / 8 + 1; - hsyncend = hsyncend / 8 + 1; + htotal = (hsyncend + var->left_margin) / 8; + hdispend = var->xres / 8; + hsyncstart = hsyncstart / 8; + hsyncend = hsyncend / 8; - yres = var->yres; - vsyncstart = yres + var->lower_margin; + vdispend = var->yres; + vsyncstart = vdispend + var->lower_margin; vsyncend = vsyncstart + var->vsync_len; vtotal = vsyncend + var->upper_margin; - vdispend = yres - 1; if (var->vmode & FB_VMODE_DOUBLE) { - yres *= 2; + vdispend *= 2; vsyncstart *= 2; vsyncend *= 2; vtotal *= 2; } else if (var->vmode & FB_VMODE_INTERLACED) { - yres = (yres + 1) / 2; + vdispend = (vdispend + 1) / 2; vsyncstart = (vsyncstart + 1) / 2; vsyncend = (vsyncend + 1) / 2; vtotal = (vtotal + 1) / 2; } - - vtotal -= 2; - vsyncstart -= 1; - vsyncend -= 1; - + yres = vdispend; if (yres >= 1024) { vtotal /= 2; vsyncstart /= 2; vsyncend /= 2; vdispend /= 2; } - if (regs.multiplexing) { + + vdispend -= 1; + vsyncstart -= 1; + vsyncend -= 1; + vtotal -= 2; + + if (cinfo->multiplexing) { htotal /= 2; hsyncstart /= 2; hsyncend /= 2; hdispend /= 2; } + + htotal -= 5; + hdispend -= 1; + hsyncstart += 1; + hsyncend += 1; + /* unlock register VGA_CRTC_H_TOTAL..CRT7 */ vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ /* if debugging is enabled, all parameters get output before writing */ - DPRINTK("CRT0: %d\n", htotal); + dev_dbg(info->device, "CRT0: %d\n", htotal); vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal); - DPRINTK("CRT1: %d\n", hdispend); + dev_dbg(info->device, "CRT1: %d\n", hdispend); vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend); - DPRINTK("CRT2: %d\n", var->xres / 8); + dev_dbg(info->device, "CRT2: %d\n", var->xres / 8); vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8); /* + 128: Compatible read */ - DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32); + dev_dbg(info->device, "CRT3: 128+%d\n", (htotal + 5) % 32); vga_wcrt(regbase, VGA_CRTC_H_BLANK_END, 128 + ((htotal + 5) % 32)); - DPRINTK("CRT4: %d\n", hsyncstart); + dev_dbg(info->device, "CRT4: %d\n", hsyncstart); vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart); tmp = hsyncend % 32; if ((htotal + 5) & 32) tmp += 128; - DPRINTK("CRT5: %d\n", tmp); + dev_dbg(info->device, "CRT5: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp); - DPRINTK("CRT6: %d\n", vtotal & 0xff); + dev_dbg(info->device, "CRT6: %d\n", vtotal & 0xff); vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff); tmp = 16; /* LineCompare bit #9 */ @@ -830,7 +792,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) tmp |= 64; if (vsyncstart & 512) tmp |= 128; - DPRINTK("CRT7: %d\n", tmp); + dev_dbg(info->device, "CRT7: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp); tmp = 0x40; /* LineCompare bit #8 */ @@ -838,25 +800,25 @@ static int cirrusfb_set_par_foo(struct fb_info *info) tmp |= 0x20; if (var->vmode & FB_VMODE_DOUBLE) tmp |= 0x80; - DPRINTK("CRT9: %d\n", tmp); + dev_dbg(info->device, "CRT9: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp); - DPRINTK("CRT10: %d\n", vsyncstart & 0xff); + dev_dbg(info->device, "CRT10: %d\n", vsyncstart & 0xff); vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff); - DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16); + dev_dbg(info->device, "CRT11: 64+32+%d\n", vsyncend % 16); vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32); - DPRINTK("CRT12: %d\n", vdispend & 0xff); + dev_dbg(info->device, "CRT12: %d\n", vdispend & 0xff); vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff); - DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff); + dev_dbg(info->device, "CRT15: %d\n", (vdispend + 1) & 0xff); vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff); - DPRINTK("CRT16: %d\n", vtotal & 0xff); + dev_dbg(info->device, "CRT16: %d\n", vtotal & 0xff); vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff); - DPRINTK("CRT18: 0xff\n"); + dev_dbg(info->device, "CRT18: 0xff\n"); vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff); tmp = 0; @@ -871,41 +833,75 @@ static int cirrusfb_set_par_foo(struct fb_info *info) if (vtotal & 512) tmp |= 128; - DPRINTK("CRT1a: %d\n", tmp); + dev_dbg(info->device, "CRT1a: %d\n", tmp); vga_wcrt(regbase, CL_CRT1A, tmp); freq = PICOS2KHZ(var->pixclock); + if (var->bits_per_pixel == 24) + if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) + freq *= 3; + if (cinfo->multiplexing) + freq /= 2; + if (cinfo->doubleVCLK) + freq *= 2; + bestclock(freq, &nom, &den, &div); + dev_dbg(info->device, "VCLK freq: %ld kHz nom: %d den: %d div: %d\n", + freq, nom, den, div); + /* set VCLK0 */ /* hardware RefClock: 14.31818 MHz */ /* formula: VClk = (OSC * N) / (D * (1+P)) */ /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ - if (cinfo->btype == BT_ALPINE) { + if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_PICASSO4 || + cinfo->btype == BT_SD64) { /* if freq is close to mclk or mclk/2 select mclk * as clock source */ - int divMCLK = cirrusfb_check_mclk(cinfo, freq); - if (divMCLK) { + int divMCLK = cirrusfb_check_mclk(info, freq); + if (divMCLK) nom = 0; - cirrusfb_set_mclk_as_source(cinfo, divMCLK); + cirrusfb_set_mclk_as_source(info, divMCLK); + } + if (is_laguna(cinfo)) { + long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc); + unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407); + unsigned short tile_control; + + if (cinfo->btype == BT_LAGUNAB) { + tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4); + tile_control &= ~0x80; + fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4); } + + fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc); + fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407); + control = fb_readw(cinfo->laguna_mmio + 0x402); + threshold = fb_readw(cinfo->laguna_mmio + 0xea); + control &= ~0x6800; + format = 0; + threshold &= 0xffc0 & 0x3fbf; } if (nom) { - vga_wseq(regbase, CL_SEQRB, nom); tmp = den << 1; if (div != 0) tmp |= 1; - /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ if ((cinfo->btype == BT_SD64) || (cinfo->btype == BT_ALPINE) || (cinfo->btype == BT_GD5480)) tmp |= 0x80; - DPRINTK("CL_SEQR1B: %ld\n", (long) tmp); - vga_wseq(regbase, CL_SEQR1B, tmp); + /* Laguna chipset has reversed clock registers */ + if (is_laguna(cinfo)) { + vga_wseq(regbase, CL_SEQRE, tmp); + vga_wseq(regbase, CL_SEQR1E, nom); + } else { + vga_wseq(regbase, CL_SEQRE, nom); + vga_wseq(regbase, CL_SEQR1E, tmp); + } } if (yres >= 1024) @@ -916,9 +912,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) * address wrap, no compat. */ vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3); -/* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); - * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ - /* don't know if it would hurt to also program this if no interlaced */ /* mode is used, but I feel better this way.. :-) */ if (var->vmode & FB_VMODE_INTERLACED) @@ -926,19 +919,15 @@ static int cirrusfb_set_par_foo(struct fb_info *info) else vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ - vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0); - - /* adjust horizontal/vertical sync type (low/high) */ + /* adjust horizontal/vertical sync type (low/high), use VCLK3 */ /* enable display memory & CRTC I/O address for color mode */ - tmp = 0x03; + tmp = 0x03 | 0xc; if (var->sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x40; if (var->sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x80; WGen(cinfo, VGA_MIS_W, tmp); - /* Screen A Preset Row-Scan register */ - vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0); /* text cursor on and start line */ vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor end line */ @@ -952,7 +941,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) /* programming for different color depths */ if (var->bits_per_pixel == 1) { - DPRINTK("cirrusfb: preparing for 1 bit deep display\n"); + dev_dbg(info->device, "preparing for 1 bit deep display\n"); vga_wgfx(regbase, VGA_GFX_MODE, 0); /* mode register */ /* SR07 */ @@ -964,68 +953,53 @@ static int cirrusfb_set_par_foo(struct fb_info *info) case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: - DPRINTK(" (for GD54xx)\n"); vga_wseq(regbase, CL_SEQR7, - regs.multiplexing ? + cinfo->multiplexing ? bi->sr07_1bpp_mux : bi->sr07_1bpp); break; case BT_LAGUNA: - DPRINTK(" (for GD546x)\n"); + case BT_LAGUNAB: vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) & ~0x01); break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } /* Extended Sequencer Mode */ switch (cinfo->btype) { - case BT_SD64: - /* setting the SEQRF on SD64 is not necessary - * (only during init) - */ - DPRINTK("(for SD64)\n"); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x1a); - break; case BT_PICCOLO: case BT_SPECTRUM: - DPRINTK("(for Piccolo/Spectrum)\n"); - /* ### ueberall 0x22? */ - /* ##vorher 1c MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ vga_wseq(regbase, CL_SEQRF, 0xb0); break; case BT_PICASSO: - DPRINTK("(for Picasso)\n"); - /* ##vorher 22 MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); /* ## vorher d0 avoid FIFO underruns..? */ vga_wseq(regbase, CL_SEQRF, 0xd0); break; + case BT_SD64: case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: case BT_LAGUNA: - DPRINTK(" (for GD54xx)\n"); + case BT_LAGUNAB: /* do nothing */ break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } /* pixel mask: pass-through for first plane */ WGen(cinfo, VGA_PEL_MSK, 0x01); - if (regs.multiplexing) + if (cinfo->multiplexing) /* hidden dac reg: 1280x1024 */ WHDR(cinfo, 0x4a); else @@ -1035,7 +1009,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06); /* plane mask: only write to first plane */ vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01); - offset = var->xres_virtual / 16; } /****************************************************** @@ -1045,7 +1018,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ else if (var->bits_per_pixel == 8) { - DPRINTK("cirrusfb: preparing for 8 bit deep display\n"); + dev_dbg(info->device, "preparing for 8 bit deep display\n"); switch (cinfo->btype) { case BT_SD64: case BT_PICCOLO: @@ -1054,34 +1027,27 @@ static int cirrusfb_set_par_foo(struct fb_info *info) case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: - DPRINTK(" (for GD54xx)\n"); vga_wseq(regbase, CL_SEQR7, - regs.multiplexing ? + cinfo->multiplexing ? bi->sr07_8bpp_mux : bi->sr07_8bpp); break; case BT_LAGUNA: - DPRINTK(" (for GD546x)\n"); + case BT_LAGUNAB: vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) | 0x01); + threshold |= 0x10; break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } switch (cinfo->btype) { - case BT_SD64: - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x1d); - break; - case BT_PICCOLO: case BT_PICASSO: case BT_SPECTRUM: - /* ### vorher 1c MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); break; @@ -1091,40 +1057,27 @@ static int cirrusfb_set_par_foo(struct fb_info *info) /* ### INCOMPLETE!! */ vga_wseq(regbase, CL_SEQRF, 0xb8); #endif -/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ - break; - case BT_ALPINE: - DPRINTK(" (for GD543x)\n"); - /* We already set SRF and SR1F */ - break; - + case BT_SD64: case BT_GD5480: case BT_LAGUNA: - DPRINTK(" (for GD54xx)\n"); + case BT_LAGUNAB: /* do nothing */ break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown board\n"); break; } /* mode register: 256 color mode */ vga_wgfx(regbase, VGA_GFX_MODE, 64); - /* pixel mask: pass-through all planes */ - WGen(cinfo, VGA_PEL_MSK, 0xff); - if (regs.multiplexing) + if (cinfo->multiplexing) /* hidden dac reg: 1280x1024 */ WHDR(cinfo, 0x4a); else /* hidden dac: nothing */ WHDR(cinfo, 0); - /* memory mode: chain4, ext. memory */ - vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); - /* plane mask: enable writing to all 4 planes */ - vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); - offset = var->xres_virtual / 8; } /****************************************************** @@ -1134,147 +1087,110 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ else if (var->bits_per_pixel == 16) { - DPRINTK("cirrusfb: preparing for 16 bit deep display\n"); + dev_dbg(info->device, "preparing for 16 bit deep display\n"); switch (cinfo->btype) { - case BT_SD64: - /* Extended Sequencer Mode: 256c col. mode */ - vga_wseq(regbase, CL_SEQR7, 0xf7); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x1e); - break; - case BT_PICCOLO: case BT_SPECTRUM: vga_wseq(regbase, CL_SEQR7, 0x87); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); break; case BT_PICASSO: vga_wseq(regbase, CL_SEQR7, 0x27); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); break; + case BT_SD64: case BT_PICASSO4: - vga_wseq(regbase, CL_SEQR7, 0x27); -/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ - break; - case BT_ALPINE: - DPRINTK(" (for GD543x)\n"); - vga_wseq(regbase, CL_SEQR7, 0xa7); + /* Extended Sequencer Mode: 256c col. mode */ + vga_wseq(regbase, CL_SEQR7, + cinfo->doubleVCLK ? 0xa3 : 0xa7); break; case BT_GD5480: - DPRINTK(" (for GD5480)\n"); vga_wseq(regbase, CL_SEQR7, 0x17); /* We already set SRF and SR1F */ break; case BT_LAGUNA: - DPRINTK(" (for GD546x)\n"); + case BT_LAGUNAB: vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) & ~0x01); + control |= 0x2000; + format |= 0x1400; + threshold |= 0x10; break; default: - printk(KERN_WARNING "CIRRUSFB: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } /* mode register: 256 color mode */ vga_wgfx(regbase, VGA_GFX_MODE, 64); - /* pixel mask: pass-through all planes */ - WGen(cinfo, VGA_PEL_MSK, 0xff); #ifdef CONFIG_PCI - WHDR(cinfo, 0xc0); /* Copy Xbh */ + WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1); #elif defined(CONFIG_ZORRO) /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */ WHDR(cinfo, 0xa0); /* hidden dac reg: nothing special */ #endif - /* memory mode: chain4, ext. memory */ - vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); - /* plane mask: enable writing to all 4 planes */ - vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); - offset = var->xres_virtual / 4; } /****************************************************** * - * 32 bpp + * 24 bpp * */ - else if (var->bits_per_pixel == 32) { - DPRINTK("cirrusfb: preparing for 32 bit deep display\n"); + else if (var->bits_per_pixel == 24) { + dev_dbg(info->device, "preparing for 24 bit deep display\n"); switch (cinfo->btype) { - case BT_SD64: - /* Extended Sequencer Mode: 256c col. mode */ - vga_wseq(regbase, CL_SEQR7, 0xf9); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x1e); - break; - case BT_PICCOLO: case BT_SPECTRUM: vga_wseq(regbase, CL_SEQR7, 0x85); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); break; case BT_PICASSO: vga_wseq(regbase, CL_SEQR7, 0x25); /* Fast Page-Mode writes */ vga_wseq(regbase, CL_SEQRF, 0xb0); - /* MCLK select */ - vga_wseq(regbase, CL_SEQR1F, 0x22); break; + case BT_SD64: case BT_PICASSO4: - vga_wseq(regbase, CL_SEQR7, 0x25); -/* vga_wseq(regbase, CL_SEQR1F, 0x1c); */ - break; - case BT_ALPINE: - DPRINTK(" (for GD543x)\n"); - vga_wseq(regbase, CL_SEQR7, 0xa9); + /* Extended Sequencer Mode: 256c col. mode */ + vga_wseq(regbase, CL_SEQR7, 0xa5); break; case BT_GD5480: - DPRINTK(" (for GD5480)\n"); - vga_wseq(regbase, CL_SEQR7, 0x19); + vga_wseq(regbase, CL_SEQR7, 0x15); /* We already set SRF and SR1F */ break; case BT_LAGUNA: - DPRINTK(" (for GD546x)\n"); + case BT_LAGUNAB: vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) & ~0x01); + control |= 0x4000; + format |= 0x2400; + threshold |= 0x20; break; default: - printk(KERN_WARNING "cirrusfb: unknown Board\n"); + dev_warn(info->device, "unknown Board\n"); break; } /* mode register: 256 color mode */ vga_wgfx(regbase, VGA_GFX_MODE, 64); - /* pixel mask: pass-through all planes */ - WGen(cinfo, VGA_PEL_MSK, 0xff); /* hidden dac reg: 8-8-8 mode (24 or 32) */ WHDR(cinfo, 0xc5); - /* memory mode: chain4, ext. memory */ - vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x0a); - /* plane mask: enable writing to all 4 planes */ - vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0xff); - offset = var->xres_virtual / 4; } /****************************************************** @@ -1284,67 +1200,55 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ else - printk(KERN_ERR "cirrusfb: What's this?? " - " requested color depth == %d.\n", + dev_err(info->device, + "What's this? requested color depth == %d.\n", var->bits_per_pixel); - vga_wcrt(regbase, VGA_CRTC_OFFSET, offset & 0xff); + pitch = info->fix.line_length >> 3; + vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff); tmp = 0x22; - if (offset & 0x100) + if (pitch & 0x100) tmp |= 0x10; /* offset overflow bit */ /* screen start addr #16-18, fastpagemode cycles */ vga_wcrt(regbase, CL_CRT1B, tmp); - if (cinfo->btype == BT_SD64 || - cinfo->btype == BT_PICASSO4 || - cinfo->btype == BT_ALPINE || - cinfo->btype == BT_GD5480) - /* screen start address bit 19 */ - vga_wcrt(regbase, CL_CRT1D, 0x00); - - /* text cursor location high */ - vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0); - /* text cursor location low */ - vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0); - /* underline row scanline = at very bottom */ - vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0); - - /* controller mode */ - vga_wattr(regbase, VGA_ATC_MODE, 1); - /* overscan (border) color */ - vga_wattr(regbase, VGA_ATC_OVERSCAN, 0); - /* color plane enable */ - vga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 15); + /* screen start address bit 19 */ + if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) + vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1); + + if (is_laguna(cinfo)) { + tmp = 0; + if ((htotal + 5) & 256) + tmp |= 128; + if (hdispend & 256) + tmp |= 64; + if (hsyncstart & 256) + tmp |= 48; + if (vtotal & 1024) + tmp |= 8; + if (vdispend & 1024) + tmp |= 4; + if (vsyncstart & 1024) + tmp |= 3; + + vga_wcrt(regbase, CL_CRT1E, tmp); + dev_dbg(info->device, "CRT1e: %d\n", tmp); + } + /* pixel panning */ vga_wattr(regbase, CL_AR33, 0); - /* color select */ - vga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0); /* [ EGS: SetOffset(); ] */ /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */ AttrOn(cinfo); - /* set/reset register */ - vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0); - /* set/reset enable */ - vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0); - /* color compare */ - vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0); - /* data rotate */ - vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0); - /* read map select */ - vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0); - /* miscellaneous register */ - vga_wgfx(regbase, VGA_GFX_MISC, 1); - /* color don't care */ - vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 15); - /* bit mask */ - vga_wgfx(regbase, VGA_GFX_BIT_MASK, 255); - - /* graphics cursor attributes: nothing special */ - vga_wseq(regbase, CL_SEQR12, 0x0); - + if (is_laguna(cinfo)) { + /* no tiles */ + fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402); + fb_writew(format, cinfo->laguna_mmio + 0xc0); + fb_writew(threshold, cinfo->laguna_mmio + 0xea); + } /* finally, turn on everything - turn off "FullBandwidth" bit */ /* also, set "DotClock%2" bit where requested */ tmp = 0x01; @@ -1355,18 +1259,12 @@ static int cirrusfb_set_par_foo(struct fb_info *info) */ vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp); - DPRINTK("CL_SEQR1: %d\n", tmp); - - cinfo->currentmode = regs; - - /* pan to requested offset */ - cirrusfb_pan_display(var, info); + dev_dbg(info->device, "CL_SEQR1: %d\n", tmp); #ifdef CIRRUSFB_DEBUG - cirrusfb_dump(); + cirrusfb_dbg_reg_dump(info, NULL); #endif - DPRINTK("EXIT\n"); return 0; } @@ -1418,27 +1316,19 @@ static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, static int cirrusfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - int xoffset = 0; - int yoffset = 0; + int xoffset; unsigned long base; - unsigned char tmp = 0, tmp2 = 0, xpix; + unsigned char tmp, xpix; struct cirrusfb_info *cinfo = info->par; - DPRINTK("ENTER\n"); - DPRINTK("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset); - /* no range checks for xoffset and yoffset, */ /* as fb_pan_display has already done this */ if (var->vmode & FB_VMODE_YWRAP) return -EINVAL; - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - xoffset = var->xoffset * info->var.bits_per_pixel / 8; - yoffset = var->yoffset; - base = yoffset * info->fix.line_length + xoffset; + base = var->yoffset * info->fix.line_length + xoffset; if (info->var.bits_per_pixel == 1) { /* base is already correct */ @@ -1448,14 +1338,15 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var, xpix = (unsigned char) ((xoffset % 4) * 2); } - cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */ + if (!is_laguna(cinfo)) + cirrusfb_WaitBLT(cinfo->regbase); /* lower 8 + 8 bits of screen start address */ - vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, - (unsigned char) (base & 0xff)); - vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, - (unsigned char) (base >> 8)); + vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff); + vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff); + /* 0xf2 is %11110010, exclude tmp bits */ + tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2; /* construct bits 16, 17 and 18 of screen start address */ if (base & 0x10000) tmp |= 0x01; @@ -1464,13 +1355,17 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var, if (base & 0x40000) tmp |= 0x08; - /* 0xf2 is %11110010, exclude tmp bits */ - tmp2 = (vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; - vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2); + vga_wcrt(cinfo->regbase, CL_CRT1B, tmp); /* construct bit 19 of screen start address */ - if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) - vga_wcrt(cinfo->regbase, CL_CRT1D, (base >> 12) & 0x80); + if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) { + tmp = vga_rcrt(cinfo->regbase, CL_CRT1D); + if (is_laguna(cinfo)) + tmp = (tmp & ~0x18) | ((base >> 16) & 0x18); + else + tmp = (tmp & ~0x80) | ((base >> 12) & 0x80); + vga_wcrt(cinfo->regbase, CL_CRT1D, tmp); + } /* write pixel panning value to AR33; this does not quite work in 8bpp * @@ -1479,9 +1374,6 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var, if (info->var.bits_per_pixel == 1) vga_wattr(cinfo->regbase, CL_AR33, xpix); - cirrusfb_WaitBLT(cinfo->regbase); - - DPRINTK("EXIT\n"); return 0; } @@ -1502,57 +1394,54 @@ static int cirrusfb_blank(int blank_mode, struct fb_info *info) struct cirrusfb_info *cinfo = info->par; int current_mode = cinfo->blank_mode; - DPRINTK("ENTER, blank mode = %d\n", blank_mode); + dev_dbg(info->device, "ENTER, blank mode = %d\n", blank_mode); if (info->state != FBINFO_STATE_RUNNING || current_mode == blank_mode) { - DPRINTK("EXIT, returning 0\n"); + dev_dbg(info->device, "EXIT, returning 0\n"); return 0; } /* Undo current */ if (current_mode == FB_BLANK_NORMAL || - current_mode == FB_BLANK_UNBLANK) { - /* unblank the screen */ - val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE); + current_mode == FB_BLANK_UNBLANK) /* clear "FullBandwidth" bit */ - vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); - /* and undo VESA suspend trickery */ - vga_wgfx(cinfo->regbase, CL_GRE, 0x00); - } - - /* set new */ - if (blank_mode > FB_BLANK_NORMAL) { - /* blank the screen */ - val = vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE); + val = 0; + else /* set "FullBandwidth" bit */ - vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); - } + val = 0x20; + + val |= vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE) & 0xdf; + vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val); switch (blank_mode) { case FB_BLANK_UNBLANK: case FB_BLANK_NORMAL: + val = 0x00; break; case FB_BLANK_VSYNC_SUSPEND: - vga_wgfx(cinfo->regbase, CL_GRE, 0x04); + val = 0x04; break; case FB_BLANK_HSYNC_SUSPEND: - vga_wgfx(cinfo->regbase, CL_GRE, 0x02); + val = 0x02; break; case FB_BLANK_POWERDOWN: - vga_wgfx(cinfo->regbase, CL_GRE, 0x06); + val = 0x06; break; default: - DPRINTK("EXIT, returning 1\n"); + dev_dbg(info->device, "EXIT, returning 1\n"); return 1; } + vga_wgfx(cinfo->regbase, CL_GRE, val); + cinfo->blank_mode = blank_mode; - DPRINTK("EXIT, returning 0\n"); + dev_dbg(info->device, "EXIT, returning 0\n"); /* Let fbcon do a soft blank for us */ return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0; } + /**** END Hardware specific Routines **************************************/ /****************************************************************************/ /**** BEGIN Internal Routines ***********************************************/ @@ -1562,8 +1451,6 @@ static void init_vgachip(struct fb_info *info) struct cirrusfb_info *cinfo = info->par; const struct cirrusfb_board_info_rec *bi; - DPRINTK("ENTER\n"); - assert(cinfo != NULL); bi = &cirrusfb_board_info[cinfo->btype]; @@ -1591,25 +1478,23 @@ static void init_vgachip(struct fb_info *info) /* disable flickerfixer */ vga_wcrt(cinfo->regbase, CL_CRT51, 0x00); mdelay(100); - /* from Klaus' NetBSD driver: */ - vga_wgfx(cinfo->regbase, CL_GR2F, 0x00); - /* put blitter into 542x compat */ - vga_wgfx(cinfo->regbase, CL_GR33, 0x00); /* mode */ vga_wgfx(cinfo->regbase, CL_GR31, 0x00); - break; - - case BT_GD5480: + case BT_GD5480: /* fall through */ /* from Klaus' NetBSD driver: */ vga_wgfx(cinfo->regbase, CL_GR2F, 0x00); + case BT_ALPINE: /* fall through */ + /* put blitter into 542x compat */ + vga_wgfx(cinfo->regbase, CL_GR33, 0x00); break; - case BT_ALPINE: + case BT_LAGUNA: + case BT_LAGUNAB: /* Nothing to do to reset the board. */ break; default: - printk(KERN_ERR "cirrusfb: Warning: Unknown board type\n"); + dev_err(info->device, "Warning: Unknown board type\n"); break; } @@ -1629,31 +1514,28 @@ static void init_vgachip(struct fb_info *info) WGen(cinfo, CL_VSSM2, 0x01); /* reset sequencer logic */ - vga_wseq(cinfo->regbase, CL_SEQR0, 0x03); + vga_wseq(cinfo->regbase, VGA_SEQ_RESET, 0x03); /* FullBandwidth (video off) and 8/9 dot clock */ vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); - /* polarity (-/-), disable access to display memory, - * VGA_CRTC_START_HI base address: color - */ - WGen(cinfo, VGA_MIS_W, 0xc1); /* "magic cookie" - doesn't make any sense to me.. */ /* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */ /* unlock all extension registers */ vga_wseq(cinfo->regbase, CL_SEQR6, 0x12); - /* reset blitter */ - vga_wgfx(cinfo->regbase, CL_GR31, 0x04); - switch (cinfo->btype) { case BT_GD5480: vga_wseq(cinfo->regbase, CL_SEQRF, 0x98); break; case BT_ALPINE: + case BT_LAGUNA: + case BT_LAGUNAB: break; case BT_SD64: +#ifdef CONFIG_ZORRO vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8); +#endif break; default: vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f); @@ -1665,8 +1547,8 @@ static void init_vgachip(struct fb_info *info) vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* character map select: doesn't even matter in gx mode */ vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); - /* memory mode: chain-4, no odd/even, ext. memory */ - vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); + /* memory mode: chain4, ext. memory */ + vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* controller-internal base address of video memory */ if (bi->init_sr07) @@ -1692,20 +1574,12 @@ static void init_vgachip(struct fb_info *info) vga_wseq(cinfo->regbase, CL_SEQR18, 0x02); } - /* MCLK select etc. */ - if (bi->init_sr1f) - vga_wseq(cinfo->regbase, CL_SEQR1F, bi->sr1f); - /* Screen A preset row scan: none */ vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); /* Text cursor start: disable text cursor */ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor end: - */ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); - /* Screen start address high: 0 */ - vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00); - /* Screen start address low: 0 */ - vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00); /* text cursor location high: 0 */ vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location low: 0 */ @@ -1713,10 +1587,6 @@ static void init_vgachip(struct fb_info *info) /* Underline Row scanline: - */ vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); - /* mode control: timing enable, byte mode, no compat modes */ - vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3); - /* Line Compare: not needed */ - vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* ### add 0x40 for text modes with > 30 MHz pixclock */ /* ext. display controls: ext.adr. wrap */ vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02); @@ -1739,7 +1609,9 @@ static void init_vgachip(struct fb_info *info) vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); /* Bit Mask: no mask at all */ vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); - if (cinfo->btype == BT_ALPINE) + + if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64 || + is_laguna(cinfo)) /* (5434 can't have bit 3 set for bitblt) */ vga_wgfx(cinfo->regbase, CL_GRB, 0x20); else @@ -1779,18 +1651,11 @@ static void init_vgachip(struct fb_info *info) vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); /* Color Plane enable: Enable all 4 planes */ vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); -/* ### vga_wattr(cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */ /* Color Select: - */ vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ - if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480) - /* polarity (-/-), enable display mem, - * VGA_CRTC_START_HI i/o base = color - */ - WGen(cinfo, VGA_MIS_W, 0xc3); - /* BLT Start/status: Blitter reset */ vga_wgfx(cinfo->regbase, CL_GR31, 0x04); /* - " - : "end-of-reset" */ @@ -1798,8 +1663,6 @@ static void init_vgachip(struct fb_info *info) /* misc... */ WHDR(cinfo, 0); /* Hidden DAC register: - */ - - DPRINTK("EXIT\n"); return; } @@ -1808,8 +1671,6 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on) #ifdef CONFIG_ZORRO /* only works on Zorro boards */ static int IsOn = 0; /* XXX not ok for multiple boards */ - DPRINTK("ENTER\n"); - if (cinfo->btype == BT_PICASSO4) return; /* nothing to switch */ if (cinfo->btype == BT_ALPINE) @@ -1819,8 +1680,6 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on) if (cinfo->btype == BT_PICASSO) { if ((on && !IsOn) || (!on && IsOn)) WSFR(cinfo, 0xff); - - DPRINTK("EXIT\n"); return; } if (on) { @@ -1847,11 +1706,10 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on) case BT_SPECTRUM: WSFR(cinfo, 0x4f); break; - default: /* do nothing */ break; + default: /* do nothing */ + break; } } - - DPRINTK("EXIT\n"); #endif /* CONFIG_ZORRO */ } @@ -1859,6 +1717,17 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on) /* Linux 2.6-style accelerated functions */ /******************************************/ +static int cirrusfb_sync(struct fb_info *info) +{ + struct cirrusfb_info *cinfo = info->par; + + if (!is_laguna(cinfo)) { + while (vga_rgfx(cinfo->regbase, CL_GR31) & 0x03) + cpu_relax(); + } + return 0; +} + static void cirrusfb_fillrect(struct fb_info *info, const struct fb_fillrect *region) { @@ -1894,8 +1763,8 @@ static void cirrusfb_fillrect(struct fb_info *info, info->var.bits_per_pixel, (region->dx * m) / 8, region->dy, (region->width * m) / 8, region->height, - color, - info->fix.line_length); + color, color, + info->fix.line_length, 0x40); } static void cirrusfb_copyarea(struct fb_info *info, @@ -1943,9 +1812,46 @@ static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image) { struct cirrusfb_info *cinfo = info->par; + unsigned char op = (info->var.bits_per_pixel == 24) ? 0xc : 0x4; - cirrusfb_WaitBLT(cinfo->regbase); - cfb_imageblit(info, image); + if (info->state != FBINFO_STATE_RUNNING) + return; + /* Alpine/SD64 does not work at 24bpp ??? */ + if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) + cfb_imageblit(info, image); + else if ((cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) && + op == 0xc) + cfb_imageblit(info, image); + else { + unsigned size = ((image->width + 7) >> 3) * image->height; + int m = info->var.bits_per_pixel; + u32 fg, bg; + + if (info->var.bits_per_pixel == 8) { + fg = image->fg_color; + bg = image->bg_color; + } else { + fg = ((u32 *)(info->pseudo_palette))[image->fg_color]; + bg = ((u32 *)(info->pseudo_palette))[image->bg_color]; + } + if (info->var.bits_per_pixel == 24) { + /* clear background first */ + cirrusfb_RectFill(cinfo->regbase, + info->var.bits_per_pixel, + (image->dx * m) / 8, image->dy, + (image->width * m) / 8, + image->height, + bg, bg, + info->fix.line_length, 0x40); + } + cirrusfb_RectFill(cinfo->regbase, + info->var.bits_per_pixel, + (image->dx * m) / 8, image->dy, + (image->width * m) / 8, image->height, + fg, bg, + info->fix.line_length, op); + memcpy(info->screen_base, image->data, size); + } } #ifdef CONFIG_PPC_PREP @@ -1953,12 +1859,8 @@ static void cirrusfb_imageblit(struct fb_info *info, #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) static void get_prep_addrs(unsigned long *display, unsigned long *registers) { - DPRINTK("ENTER\n"); - *display = PREP_VIDEO_BASE; *registers = (unsigned long) PREP_IO_BASE; - - DPRINTK("EXIT\n"); } #endif /* CONFIG_PPC_PREP */ @@ -1970,40 +1872,43 @@ static int release_io_ports; * based on the DRAM bandwidth bit and DRAM bank switching bit. This * works with 1MB, 2MB and 4MB configurations (which the Motorola boards * seem to have. */ -static unsigned int __devinit cirrusfb_get_memsize(u8 __iomem *regbase) +static unsigned int __devinit cirrusfb_get_memsize(struct fb_info *info, + u8 __iomem *regbase) { unsigned long mem; - unsigned char SRF; + struct cirrusfb_info *cinfo = info->par; - DPRINTK("ENTER\n"); + if (is_laguna(cinfo)) { + unsigned char SR14 = vga_rseq(regbase, CL_SEQR14); - SRF = vga_rseq(regbase, CL_SEQRF); - switch ((SRF & 0x18)) { - case 0x08: - mem = 512 * 1024; - break; - case 0x10: - mem = 1024 * 1024; - break; - /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory - * on the 5430. - */ - case 0x18: - mem = 2048 * 1024; - break; - default: - printk(KERN_WARNING "CLgenfb: Unknown memory size!\n"); - mem = 1024 * 1024; + mem = ((SR14 & 7) + 1) << 20; + } else { + unsigned char SRF = vga_rseq(regbase, CL_SEQRF); + switch ((SRF & 0x18)) { + case 0x08: + mem = 512 * 1024; + break; + case 0x10: + mem = 1024 * 1024; + break; + /* 64-bit DRAM data bus width; assume 2MB. + * Also indicates 2MB memory on the 5430. + */ + case 0x18: + mem = 2048 * 1024; + break; + default: + dev_warn(info->device, "Unknown memory size!\n"); + mem = 1024 * 1024; + } + /* If DRAM bank switching is enabled, there must be + * twice as much memory installed. (4MB on the 5434) + */ + if (cinfo->btype != BT_ALPINE && (SRF & 0x80) != 0) + mem *= 2; } - if (SRF & 0x80) - /* If DRAM bank switching is enabled, there must be twice as much - * memory installed. (4MB on the 5434) - */ - mem *= 2; /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */ - - DPRINTK("EXIT\n"); return mem; } @@ -2014,8 +1919,6 @@ static void get_pci_addrs(const struct pci_dev *pdev, assert(display != NULL); assert(registers != NULL); - DPRINTK("ENTER\n"); - *display = 0; *registers = 0; @@ -2030,14 +1933,15 @@ static void get_pci_addrs(const struct pci_dev *pdev, } assert(*display != 0); - - DPRINTK("EXIT\n"); } static void cirrusfb_pci_unmap(struct fb_info *info) { struct pci_dev *pdev = to_pci_dev(info->device); + struct cirrusfb_info *cinfo = info->par; + if (cinfo->laguna_mmio == NULL) + iounmap(cinfo->laguna_mmio); iounmap(info->screen_base); #if 0 /* if system didn't claim this region, we would... */ release_mem_region(0xA0000, 65535); @@ -2067,6 +1971,22 @@ static void cirrusfb_zorro_unmap(struct fb_info *info) } #endif /* CONFIG_ZORRO */ +/* function table of the above functions */ +static struct fb_ops cirrusfb_ops = { + .owner = THIS_MODULE, + .fb_open = cirrusfb_open, + .fb_release = cirrusfb_release, + .fb_setcolreg = cirrusfb_setcolreg, + .fb_check_var = cirrusfb_check_var, + .fb_set_par = cirrusfb_set_par, + .fb_pan_display = cirrusfb_pan_display, + .fb_blank = cirrusfb_blank, + .fb_fillrect = cirrusfb_fillrect, + .fb_copyarea = cirrusfb_copyarea, + .fb_sync = cirrusfb_sync, + .fb_imageblit = cirrusfb_imageblit, +}; + static int __devinit cirrusfb_set_fbinfo(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; @@ -2077,10 +1997,16 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info) | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN | FBINFO_HWACCEL_FILLRECT + | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA; - if (noaccel) + if (noaccel || is_laguna(cinfo)) { info->flags |= FBINFO_HWACCEL_DISABLED; + info->fix.accel = FB_ACCEL_NONE; + } else + info->fix.accel = FB_ACCEL_CIRRUS_ALPINE; + info->fbops = &cirrusfb_ops; + if (cinfo->btype == BT_GD5480) { if (var->bits_per_pixel == 16) info->screen_base += 1 * MB_; @@ -2104,7 +2030,6 @@ static int __devinit cirrusfb_set_fbinfo(struct fb_info *info) /* FIXME: map region at 0xB8000 if available, fill in here */ info->fix.mmio_len = 0; - info->fix.accel = FB_ACCEL_NONE; fb_alloc_cmap(&info->cmap, 256, 0); @@ -2115,70 +2040,56 @@ static int __devinit cirrusfb_register(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; int err; - enum cirrus_board btype; - - DPRINTK("ENTER\n"); - - printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based " - "graphic boards, v" CIRRUSFB_VERSION "\n"); - - btype = cinfo->btype; /* sanity checks */ - assert(btype != BT_NONE); + assert(cinfo->btype != BT_NONE); /* set all the vital stuff */ cirrusfb_set_fbinfo(info); - DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base); + dev_dbg(info->device, "(RAM start set to: 0x%p)\n", info->screen_base); err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); if (!err) { - DPRINTK("wrong initial video mode\n"); + dev_dbg(info->device, "wrong initial video mode\n"); err = -EINVAL; goto err_dealloc_cmap; } info->var.activate = FB_ACTIVATE_NOW; - err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info); + err = cirrusfb_check_var(&info->var, info); if (err < 0) { /* should never happen */ - DPRINTK("choking on default var... umm, no good.\n"); + dev_dbg(info->device, + "choking on default var... umm, no good.\n"); goto err_dealloc_cmap; } err = register_framebuffer(info); if (err < 0) { - printk(KERN_ERR "cirrusfb: could not register " - "fb device; err = %d!\n", err); + dev_err(info->device, + "could not register fb device; err = %d!\n", err); goto err_dealloc_cmap; } - DPRINTK("EXIT, returning 0\n"); return 0; err_dealloc_cmap: fb_dealloc_cmap(&info->cmap); - cinfo->unmap(info); - framebuffer_release(info); return err; } static void __devexit cirrusfb_cleanup(struct fb_info *info) { struct cirrusfb_info *cinfo = info->par; - DPRINTK("ENTER\n"); switch_monitor(cinfo, 0); - unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); - printk("Framebuffer unregistered\n"); + dev_dbg(info->device, "Framebuffer unregistered\n"); cinfo->unmap(info); framebuffer_release(info); - - DPRINTK("EXIT\n"); } #ifdef CONFIG_PCI @@ -2187,7 +2098,6 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, { struct cirrusfb_info *cinfo; struct fb_info *info; - enum cirrus_board btype; unsigned long board_addr, board_size; int ret; @@ -2201,15 +2111,17 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, if (!info) { printk(KERN_ERR "cirrusfb: could not allocate memory\n"); ret = -ENOMEM; - goto err_disable; + goto err_out; } cinfo = info->par; - cinfo->btype = btype = (enum cirrus_board) ent->driver_data; + cinfo->btype = (enum cirrus_board) ent->driver_data; - DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n", - pdev->resource[0].start, btype); - DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start); + dev_dbg(info->device, + " Found PCI device, base address 0 is 0x%Lx, btype set to %d\n", + (unsigned long long)pdev->resource[0].start, cinfo->btype); + dev_dbg(info->device, " base address 1 is 0x%Lx\n", + (unsigned long long)pdev->resource[1].start); if (isPReP) { pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000); @@ -2219,30 +2131,30 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, /* PReP dies if we ioremap the IO registers, but it works w/out... */ cinfo->regbase = (char __iomem *) info->fix.mmio_start; } else { - DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n"); + dev_dbg(info->device, + "Attempt to get PCI info for Cirrus Graphics Card\n"); get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start); /* FIXME: this forces VGA. alternatives? */ cinfo->regbase = NULL; + cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000); } - DPRINTK("Board address: 0x%lx, register address: 0x%lx\n", + dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx\n", board_addr, info->fix.mmio_start); - board_size = (btype == BT_GD5480) ? - 32 * MB_ : cirrusfb_get_memsize(cinfo->regbase); + board_size = (cinfo->btype == BT_GD5480) ? + 32 * MB_ : cirrusfb_get_memsize(info, cinfo->regbase); ret = pci_request_regions(pdev, "cirrusfb"); if (ret < 0) { - printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, " - "abort\n", - board_addr); + dev_err(info->device, "cannot reserve region 0x%lx, abort\n", + board_addr); goto err_release_fb; } #if 0 /* if the system didn't claim this region, we would... */ if (!request_mem_region(0xA0000, 65535, "cirrusfb")) { - printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n" -, - 0xA0000L); + dev_err(info->device, "cannot reserve region 0x%lx, abort\n", + 0xA0000L); ret = -EBUSY; goto err_release_regions; } @@ -2260,16 +2172,17 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, info->screen_size = board_size; cinfo->unmap = cirrusfb_pci_unmap; - printk(KERN_INFO "RAM (%lu kB) at 0x%lx, Cirrus " - "Logic chipset on PCI bus\n", - info->screen_size >> 10, board_addr); + dev_info(info->device, + "Cirrus Logic chipset on PCI bus, RAM (%lu kB) at 0x%lx\n", + info->screen_size >> 10, board_addr); pci_set_drvdata(pdev, info); ret = cirrusfb_register(info); - if (ret) - iounmap(info->screen_base); - return ret; + if (!ret) + return 0; + pci_set_drvdata(pdev, NULL); + iounmap(info->screen_base); err_release_legacy: if (release_io_ports) release_region(0x3C0, 32); @@ -2279,8 +2192,9 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, #endif pci_release_regions(pdev); err_release_fb: + if (cinfo->laguna_mmio != NULL) + iounmap(cinfo->laguna_mmio); framebuffer_release(info); -err_disable: err_out: return ret; } @@ -2288,11 +2202,8 @@ static int __devinit cirrusfb_pci_register(struct pci_dev *pdev, static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); - DPRINTK("ENTER\n"); cirrusfb_cleanup(info); - - DPRINTK("EXIT\n"); } static struct pci_driver cirrusfb_pci_driver = { @@ -2324,8 +2235,6 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, if (cirrusfb_zorro_table2[btype].id2) z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL); size = cirrusfb_zorro_table2[btype].size; - printk(KERN_INFO "cirrusfb: %s board detected; ", - cirrusfb_board_info[btype].name); info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); if (!info) { @@ -2334,6 +2243,9 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, goto err_out; } + dev_info(info->device, "%s board detected\n", + cirrusfb_board_info[btype].name); + cinfo = info->par; cinfo->btype = btype; @@ -2345,19 +2257,16 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, info->screen_size = size; if (!zorro_request_device(z, "cirrusfb")) { - printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, " - "abort\n", - board_addr); + dev_err(info->device, "cannot reserve region 0x%lx, abort\n", + board_addr); ret = -EBUSY; goto err_release_fb; } - printk(" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); - ret = -EIO; if (btype == BT_PICASSO4) { - printk(KERN_INFO " REG at $%lx\n", board_addr + 0x600000); + dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000); /* To be precise, for the P4 this is not the */ /* begin of the board, but the begin of RAM. */ @@ -2367,7 +2276,7 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, if (!cinfo->regbase) goto err_release_region; - DPRINTK("cirrusfb: Virtual address for board set to: $%p\n", + dev_dbg(info->device, "Virtual address for board set to: $%p\n", cinfo->regbase); cinfo->regbase += 0x600000; info->fix.mmio_start = board_addr + 0x600000; @@ -2377,8 +2286,8 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, if (!info->screen_base) goto err_unmap_regbase; } else { - printk(KERN_INFO " REG at $%lx\n", - (unsigned long) z2->resource.start); + dev_info(info->device, " REG at $%lx\n", + (unsigned long) z2->resource.start); info->fix.smem_start = board_addr; if (board_addr > 0x01000000) @@ -2392,27 +2301,32 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); info->fix.mmio_start = z2->resource.start; - DPRINTK("cirrusfb: Virtual address for board set to: $%p\n", + dev_dbg(info->device, "Virtual address for board set to: $%p\n", cinfo->regbase); } cinfo->unmap = cirrusfb_zorro_unmap; - printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n"); + dev_info(info->device, + "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n", + board_size / MB_, board_addr); + zorro_set_drvdata(z, info); + /* MCLK select etc. */ + if (cirrusfb_board_info[btype].init_sr1f) + vga_wseq(cinfo->regbase, CL_SEQR1F, + cirrusfb_board_info[btype].sr1f); + ret = cirrusfb_register(info); - if (ret) { - if (btype == BT_PICASSO4) { - iounmap(info->screen_base); - iounmap(cinfo->regbase - 0x600000); - } else if (board_addr > 0x01000000) - iounmap(info->screen_base); - } - return ret; + if (!ret) + return 0; + + if (btype == BT_PICASSO4 || board_addr > 0x01000000) + iounmap(info->screen_base); err_unmap_regbase: - /* Parental advisory: explicit hack */ - iounmap(cinfo->regbase - 0x600000); + if (btype == BT_PICASSO4) + iounmap(cinfo->regbase - 0x600000); err_release_region: release_region(board_addr, board_size); err_release_fb: @@ -2424,11 +2338,8 @@ static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) { struct fb_info *info = zorro_get_drvdata(z); - DPRINTK("ENTER\n"); cirrusfb_cleanup(info); - - DPRINTK("EXIT\n"); } static struct zorro_driver cirrusfb_zorro_driver = { @@ -2439,33 +2350,11 @@ static struct zorro_driver cirrusfb_zorro_driver = { }; #endif /* CONFIG_ZORRO */ -static int __init cirrusfb_init(void) -{ - int error = 0; - -#ifndef MODULE - char *option = NULL; - - if (fb_get_options("cirrusfb", &option)) - return -ENODEV; - cirrusfb_setup(option); -#endif - -#ifdef CONFIG_ZORRO - error |= zorro_register_driver(&cirrusfb_zorro_driver); -#endif -#ifdef CONFIG_PCI - error |= pci_register_driver(&cirrusfb_pci_driver); -#endif - return error; -} - #ifndef MODULE -static int __init cirrusfb_setup(char *options) { +static int __init cirrusfb_setup(char *options) +{ char *this_opt; - DPRINTK("ENTER\n"); - if (!options || !*options) return 0; @@ -2473,8 +2362,6 @@ static int __init cirrusfb_setup(char *options) { if (!*this_opt) continue; - DPRINTK("cirrusfb_setup: option '%s'\n", this_opt); - if (!strcmp(this_opt, "noaccel")) noaccel = 1; else if (!strncmp(this_opt, "mode:", 5)) @@ -2494,6 +2381,27 @@ MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik "); MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips"); MODULE_LICENSE("GPL"); +static int __init cirrusfb_init(void) +{ + int error = 0; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("cirrusfb", &option)) + return -ENODEV; + cirrusfb_setup(option); +#endif + +#ifdef CONFIG_ZORRO + error |= zorro_register_driver(&cirrusfb_zorro_driver); +#endif +#ifdef CONFIG_PCI + error |= pci_register_driver(&cirrusfb_pci_driver); +#endif + return error; +} + static void __exit cirrusfb_exit(void) { #ifdef CONFIG_PCI @@ -2560,8 +2468,6 @@ static void AttrOn(const struct cirrusfb_info *cinfo) { assert(cinfo != NULL); - DPRINTK("ENTER\n"); - if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) { /* if we're just in "write value" mode, write back the */ /* same value as before to not modify anything */ @@ -2574,8 +2480,6 @@ static void AttrOn(const struct cirrusfb_info *cinfo) /* dummy write on Reg0 to be on "write index" mode next time */ vga_w(cinfo->regbase, VGA_ATT_IW, 0x00); - - DPRINTK("EXIT\n"); } /*** WHDR() - write into the Hidden DAC register ***/ @@ -2588,6 +2492,8 @@ static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val) { unsigned char dummy; + if (is_laguna(cinfo)) + return; if (cinfo->btype == BT_PICASSO) { /* Klaus' hint for correct access to HDR on some boards */ /* first write 0 to pixel mask (3c6) */ @@ -2655,7 +2561,8 @@ static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned ch vga_w(cinfo->regbase, VGA_PEL_IW, regnum); if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 || - cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) { + cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480 || + cinfo->btype == BT_SD64 || is_laguna(cinfo)) { /* but DAC data register IS, at least for Picasso II */ if (cinfo->btype == BT_PICASSO) data += 0xfff; @@ -2702,9 +2609,8 @@ static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned ch /* FIXME: use interrupts instead */ static void cirrusfb_WaitBLT(u8 __iomem *regbase) { - /* now busy-wait until we're done */ while (vga_rgfx(regbase, CL_GR31) & 0x08) - /* do nothing */ ; + cpu_relax(); } /******************************************************************* @@ -2713,60 +2619,12 @@ static void cirrusfb_WaitBLT(u8 __iomem *regbase) perform accelerated "scrolling" ********************************************************************/ -static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, - u_short curx, u_short cury, - u_short destx, u_short desty, - u_short width, u_short height, - u_short line_length) -{ - u_short nwidth, nheight; - u_long nsrc, ndest; - u_char bltmode; - - DPRINTK("ENTER\n"); - - nwidth = width - 1; - nheight = height - 1; - - bltmode = 0x00; - /* if source adr < dest addr, do the Blt backwards */ - if (cury <= desty) { - if (cury == desty) { - /* if src and dest are on the same line, check x */ - if (curx < destx) - bltmode |= 0x01; - } else - bltmode |= 0x01; - } - if (!bltmode) { - /* standard case: forward blitting */ - nsrc = (cury * line_length) + curx; - ndest = (desty * line_length) + destx; - } else { - /* this means start addresses are at the end, - * counting backwards - */ - nsrc = cury * line_length + curx + - nheight * line_length + nwidth; - ndest = desty * line_length + destx + - nheight * line_length + nwidth; - } - - /* - run-down of registers to be programmed: - destination pitch - source pitch - BLT width/height - source start - destination start - BLT mode - BLT ROP - VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color" - start/stop - */ - - cirrusfb_WaitBLT(regbase); +static void cirrusfb_set_blitter(u8 __iomem *regbase, + u_short nwidth, u_short nheight, + u_long nsrc, u_long ndest, + u_short bltmode, u_short line_length) +{ /* pitch: set to line_length */ /* dest pitch low */ vga_wgfx(regbase, CL_GR24, line_length & 0xff); @@ -2813,91 +2671,91 @@ static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, /* and finally: GO! */ vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */ - - DPRINTK("EXIT\n"); } /******************************************************************* - cirrusfb_RectFill() + cirrusfb_BitBLT() - perform accelerated rectangle fill + perform accelerated "scrolling" ********************************************************************/ -static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, - u_short x, u_short y, u_short width, u_short height, - u_char color, u_short line_length) +static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel, + u_short curx, u_short cury, + u_short destx, u_short desty, + u_short width, u_short height, + u_short line_length) { - u_short nwidth, nheight; - u_long ndest; - u_char op; - - DPRINTK("ENTER\n"); - - nwidth = width - 1; - nheight = height - 1; + u_short nwidth = width - 1; + u_short nheight = height - 1; + u_long nsrc, ndest; + u_char bltmode; - ndest = (y * line_length) + x; + bltmode = 0x00; + /* if source adr < dest addr, do the Blt backwards */ + if (cury <= desty) { + if (cury == desty) { + /* if src and dest are on the same line, check x */ + if (curx < destx) + bltmode |= 0x01; + } else + bltmode |= 0x01; + } + /* standard case: forward blitting */ + nsrc = (cury * line_length) + curx; + ndest = (desty * line_length) + destx; + if (bltmode) { + /* this means start addresses are at the end, + * counting backwards + */ + nsrc += nheight * line_length + nwidth; + ndest += nheight * line_length + nwidth; + } cirrusfb_WaitBLT(regbase); - /* pitch: set to line_length */ - vga_wgfx(regbase, CL_GR24, line_length & 0xff); /* dest pitch low */ - vga_wgfx(regbase, CL_GR25, line_length >> 8); /* dest pitch hi */ - vga_wgfx(regbase, CL_GR26, line_length & 0xff); /* source pitch low */ - vga_wgfx(regbase, CL_GR27, line_length >> 8); /* source pitch hi */ + cirrusfb_set_blitter(regbase, nwidth, nheight, + nsrc, ndest, bltmode, line_length); +} - /* BLT width: actual number of pixels - 1 */ - vga_wgfx(regbase, CL_GR20, nwidth & 0xff); /* BLT width low */ - vga_wgfx(regbase, CL_GR21, nwidth >> 8); /* BLT width hi */ +/******************************************************************* + cirrusfb_RectFill() - /* BLT height: actual number of lines -1 */ - vga_wgfx(regbase, CL_GR22, nheight & 0xff); /* BLT height low */ - vga_wgfx(regbase, CL_GR23, nheight >> 8); /* BLT width hi */ + perform accelerated rectangle fill +********************************************************************/ - /* BLT destination */ - /* BLT dest low */ - vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff)); - /* BLT dest mid */ - vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8)); - /* BLT dest hi */ - vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16)); +static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel, + u_short x, u_short y, u_short width, u_short height, + u32 fg_color, u32 bg_color, u_short line_length, + u_char blitmode) +{ + u_long ndest = (y * line_length) + x; + u_char op; - /* BLT source: set to 0 (is a dummy here anyway) */ - vga_wgfx(regbase, CL_GR2C, 0x00); /* BLT src low */ - vga_wgfx(regbase, CL_GR2D, 0x00); /* BLT src mid */ - vga_wgfx(regbase, CL_GR2E, 0x00); /* BLT src hi */ + cirrusfb_WaitBLT(regbase); /* This is a ColorExpand Blt, using the */ /* same color for foreground and background */ - vga_wgfx(regbase, VGA_GFX_SR_VALUE, color); /* foreground color */ - vga_wgfx(regbase, VGA_GFX_SR_ENABLE, color); /* background color */ - - op = 0xc0; - if (bits_per_pixel == 16) { - vga_wgfx(regbase, CL_GR10, color); /* foreground color */ - vga_wgfx(regbase, CL_GR11, color); /* background color */ - op = 0x50; - op = 0xd0; - } else if (bits_per_pixel == 32) { - vga_wgfx(regbase, CL_GR10, color); /* foreground color */ - vga_wgfx(regbase, CL_GR11, color); /* background color */ - vga_wgfx(regbase, CL_GR12, color); /* foreground color */ - vga_wgfx(regbase, CL_GR13, color); /* background color */ - vga_wgfx(regbase, CL_GR14, 0); /* foreground color */ - vga_wgfx(regbase, CL_GR15, 0); /* background color */ - op = 0x50; - op = 0xf0; - } - /* BLT mode: color expand, Enable 8x8 copy (faster?) */ - vga_wgfx(regbase, CL_GR30, op); /* BLT mode */ - - /* BLT ROP: SrcCopy */ - vga_wgfx(regbase, CL_GR32, 0x0d); /* BLT ROP */ - - /* and finally: GO! */ - vga_wgfx(regbase, CL_GR31, 0x02); /* BLT Start/status */ - - DPRINTK("EXIT\n"); + vga_wgfx(regbase, VGA_GFX_SR_VALUE, bg_color); + vga_wgfx(regbase, VGA_GFX_SR_ENABLE, fg_color); + + op = 0x80; + if (bits_per_pixel >= 16) { + vga_wgfx(regbase, CL_GR10, bg_color >> 8); + vga_wgfx(regbase, CL_GR11, fg_color >> 8); + op = 0x90; + } + if (bits_per_pixel >= 24) { + vga_wgfx(regbase, CL_GR12, bg_color >> 16); + vga_wgfx(regbase, CL_GR13, fg_color >> 16); + op = 0xa0; + } + if (bits_per_pixel == 32) { + vga_wgfx(regbase, CL_GR14, bg_color >> 24); + vga_wgfx(regbase, CL_GR15, fg_color >> 24); + op = 0xb0; + } + cirrusfb_set_blitter(regbase, width - 1, height - 1, + 0, ndest, op | blitmode, line_length); } /************************************************************************** @@ -2917,8 +2775,6 @@ static void bestclock(long freq, int *nom, int *den, int *div) *den = 0; *div = 0; - DPRINTK("ENTER\n"); - if (freq < 8000) freq = 8000; @@ -2960,12 +2816,6 @@ static void bestclock(long freq, int *nom, int *den, int *div) } } } - - DPRINTK("Best possible values for given frequency:\n"); - DPRINTK(" freq: %ld kHz nom: %d den: %d div: %d\n", - freq, *nom, *den, *div); - - DPRINTK("EXIT\n"); } /* ------------------------------------------------------------------------- @@ -2977,32 +2827,6 @@ static void bestclock(long freq, int *nom, int *den, int *div) #ifdef CIRRUSFB_DEBUG -/** - * cirrusfb_dbg_print_byte - * @name: name associated with byte value to be displayed - * @val: byte value to be displayed - * - * DESCRIPTION: - * Display an indented string, along with a hexidecimal byte value, and - * its decoded bits. Bits 7 through 0 are listed in left-to-right - * order. - */ - -static -void cirrusfb_dbg_print_byte(const char *name, unsigned char val) -{ - DPRINTK("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n", - name, val, - val & 0x80 ? '1' : '0', - val & 0x40 ? '1' : '0', - val & 0x20 ? '1' : '0', - val & 0x10 ? '1' : '0', - val & 0x08 ? '1' : '0', - val & 0x04 ? '1' : '0', - val & 0x02 ? '1' : '0', - val & 0x01 ? '1' : '0'); -} - /** * cirrusfb_dbg_print_regs * @base: If using newmmio, the newmmio base address, otherwise %NULL @@ -3014,9 +2838,9 @@ void cirrusfb_dbg_print_byte(const char *name, unsigned char val) * used at the given @base address to query the information. */ -static -void cirrusfb_dbg_print_regs(caddr_t regbase, - enum cirrusfb_dbg_reg_class reg_class, ...) +static void cirrusfb_dbg_print_regs(struct fb_info *info, + caddr_t regbase, + enum cirrusfb_dbg_reg_class reg_class, ...) { va_list list; unsigned char val = 0; @@ -3042,7 +2866,7 @@ void cirrusfb_dbg_print_regs(caddr_t regbase, break; } - cirrusfb_dbg_print_byte(name, val); + dev_dbg(info->device, "%8s = 0x%02X\n", name, val); name = va_arg(list, char *); } @@ -3050,18 +2874,6 @@ void cirrusfb_dbg_print_regs(caddr_t regbase, va_end(list); } -/** - * cirrusfb_dump - * @cirrusfbinfo: - * - * DESCRIPTION: - */ - -static void cirrusfb_dump(void) -{ - cirrusfb_dbg_reg_dump(NULL); -} - /** * cirrusfb_dbg_reg_dump * @base: If using newmmio, the newmmio base address, otherwise %NULL @@ -3072,12 +2884,11 @@ static void cirrusfb_dump(void) * used at the given @base address to query the information. */ -static -void cirrusfb_dbg_reg_dump(caddr_t regbase) +static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase) { - DPRINTK("CIRRUSFB VGA CRTC register dump:\n"); + dev_dbg(info->device, "VGA CRTC register dump:\n"); - cirrusfb_dbg_print_regs(regbase, CRT, + cirrusfb_dbg_print_regs(info, regbase, CRT, "CR00", 0x00, "CR01", 0x01, "CR02", 0x02, @@ -3127,11 +2938,11 @@ void cirrusfb_dbg_reg_dump(caddr_t regbase) "CR3F", 0x3F, NULL); - DPRINTK("\n"); + dev_dbg(info->device, "\n"); - DPRINTK("CIRRUSFB VGA SEQ register dump:\n"); + dev_dbg(info->device, "VGA SEQ register dump:\n"); - cirrusfb_dbg_print_regs(regbase, SEQ, + cirrusfb_dbg_print_regs(info, regbase, SEQ, "SR00", 0x00, "SR01", 0x01, "SR02", 0x02, @@ -3160,7 +2971,7 @@ void cirrusfb_dbg_reg_dump(caddr_t regbase) "SR1F", 0x1F, NULL); - DPRINTK("\n"); + dev_dbg(info->device, "\n"); } #endif /* CIRRUSFB_DEBUG */ diff --git a/trunk/drivers/video/console/fbcon.c b/trunk/drivers/video/console/fbcon.c index 1657b9608b04..2cd500a304f2 100644 --- a/trunk/drivers/video/console/fbcon.c +++ b/trunk/drivers/video/console/fbcon.c @@ -2954,8 +2954,11 @@ static int fbcon_fb_unbind(int idx) static int fbcon_fb_unregistered(struct fb_info *info) { - int i, idx = info->node; + int i, idx; + if (!lock_fb_info(info)) + return -ENODEV; + idx = info->node; for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map[i] == idx) con2fb_map[i] = -1; @@ -2979,13 +2982,14 @@ static int fbcon_fb_unregistered(struct fb_info *info) } } - if (!num_registered_fb) - unregister_con_driver(&fb_con); - - if (primary_device == idx) primary_device = -1; + unlock_fb_info(info); + + if (!num_registered_fb) + unregister_con_driver(&fb_con); + return 0; } @@ -3021,9 +3025,13 @@ static inline void fbcon_select_primary(struct fb_info *info) static int fbcon_fb_registered(struct fb_info *info) { - int ret = 0, i, idx = info->node; + int ret = 0, i, idx; + if (!lock_fb_info(info)) + return -ENODEV; + idx = info->node; fbcon_select_primary(info); + unlock_fb_info(info); if (info_idx == -1) { for (i = first_fb_vc; i <= last_fb_vc; i++) { @@ -3124,7 +3132,7 @@ static void fbcon_get_requirement(struct fb_info *info, } } -static int fbcon_event_notify(struct notifier_block *self, +static int fbcon_event_notify(struct notifier_block *self, unsigned long action, void *data) { struct fb_event *event = data; @@ -3132,7 +3140,7 @@ static int fbcon_event_notify(struct notifier_block *self, struct fb_videomode *mode; struct fb_con2fbmap *con2fb; struct fb_blit_caps *caps; - int ret = 0; + int idx, ret = 0; /* * ignore all events except driver registration and deregistration @@ -3144,23 +3152,54 @@ static int fbcon_event_notify(struct notifier_block *self, switch(action) { case FB_EVENT_SUSPEND: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_suspended(info); + unlock_fb_info(info); break; case FB_EVENT_RESUME: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_resumed(info); + unlock_fb_info(info); break; case FB_EVENT_MODE_CHANGE: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_modechanged(info); + unlock_fb_info(info); break; case FB_EVENT_MODE_CHANGE_ALL: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_set_all_vcs(info); + unlock_fb_info(info); break; case FB_EVENT_MODE_DELETE: mode = event->data; + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } ret = fbcon_mode_deleted(info, mode); + unlock_fb_info(info); break; case FB_EVENT_FB_UNBIND: - ret = fbcon_fb_unbind(info->node); + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } + idx = info->node; + unlock_fb_info(info); + ret = fbcon_fb_unbind(idx); break; case FB_EVENT_FB_REGISTERED: ret = fbcon_fb_registered(info); @@ -3178,17 +3217,31 @@ static int fbcon_event_notify(struct notifier_block *self, con2fb->framebuffer = con2fb_map[con2fb->console - 1]; break; case FB_EVENT_BLANK: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_fb_blanked(info, *(int *)event->data); + unlock_fb_info(info); break; case FB_EVENT_NEW_MODELIST: + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_new_modelist(info); + unlock_fb_info(info); break; case FB_EVENT_GET_REQ: caps = event->data; + if (!lock_fb_info(info)) { + ret = -ENODEV; + goto done; + } fbcon_get_requirement(info, caps); + unlock_fb_info(info); break; } - done: return ret; } diff --git a/trunk/drivers/video/cyblafb.c b/trunk/drivers/video/cyblafb.c deleted file mode 100644 index 9704b73135f5..000000000000 --- a/trunk/drivers/video/cyblafb.c +++ /dev/null @@ -1,1683 +0,0 @@ -/* - * Frame buffer driver for Trident Cyberblade/i1 graphics core - * - * Copyright 2005 Knut Petersen - * - * CREDITS: - * tridentfb.c by Jani Monoses - * see files above for further credits - * - */ - -#define CYBLAFB_DEBUG 0 -#define CYBLAFB_KD_GRAPHICS_QUIRK 1 - -#define CYBLAFB_PIXMAPSIZE 8192 - -#include -#include -#include -#include -#include -#include -#include