diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index 375ae760dc1e..d260d92089ad 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -415,6 +415,362 @@ and other resources, etc.
+
+ Error handling
+
+
+ This chapter describes how errors are handled under libata.
+ Readers are advised to read SCSI EH
+ (Documentation/scsi/scsi_eh.txt) and ATA exceptions doc first.
+
+
+ Origins of commands
+
+ In libata, a command is represented with struct ata_queued_cmd
+ or qc. qc's are preallocated during port initialization and
+ repetitively used for command executions. Currently only one
+ qc is allocated per port but yet-to-be-merged NCQ branch
+ allocates one for each tag and maps each qc to NCQ tag 1-to-1.
+
+
+ libata commands can originate from two sources - libata itself
+ and SCSI midlayer. libata internal commands are used for
+ initialization and error handling. All normal blk requests
+ and commands for SCSI emulation are passed as SCSI commands
+ through queuecommand callback of SCSI host template.
+
+
+
+ How commands are issued
+
+
+
+ Internal commands
+
+
+ First, qc is allocated and initialized using
+ ata_qc_new_init(). Although ata_qc_new_init() doesn't
+ implement any wait or retry mechanism when qc is not
+ available, internal commands are currently issued only during
+ initialization and error recovery, so no other command is
+ active and allocation is guaranteed to succeed.
+
+
+ Once allocated qc's taskfile is initialized for the command to
+ be executed. qc currently has two mechanisms to notify
+ completion. One is via qc->complete_fn() callback and the
+ other is completion qc->waiting. qc->complete_fn() callback
+ is the asynchronous path used by normal SCSI translated
+ commands and qc->waiting is the synchronous (issuer sleeps in
+ process context) path used by internal commands.
+
+
+ Once initialization is complete, host_set lock is acquired
+ and the qc is issued.
+
+
+
+
+ SCSI commands
+
+
+ All libata drivers use ata_scsi_queuecmd() as
+ hostt->queuecommand callback. scmds can either be simulated
+ or translated. No qc is involved in processing a simulated
+ scmd. The result is computed right away and the scmd is
+ completed.
+
+
+ For a translated scmd, ata_qc_new_init() is invoked to
+ allocate a qc and the scmd is translated into the qc. SCSI
+ midlayer's completion notification function pointer is stored
+ into qc->scsidone.
+
+
+ qc->complete_fn() callback is used for completion
+ notification. ATA commands use ata_scsi_qc_complete() while
+ ATAPI commands use atapi_qc_complete(). Both functions end up
+ calling qc->scsidone to notify upper layer when the qc is
+ finished. After translation is completed, the qc is issued
+ with ata_qc_issue().
+
+
+ Note that SCSI midlayer invokes hostt->queuecommand while
+ holding host_set lock, so all above occur while holding
+ host_set lock.
+
+
+
+
+
+
+
+ How commands are processed
+
+ Depending on which protocol and which controller are used,
+ commands are processed differently. For the purpose of
+ discussion, a controller which uses taskfile interface and all
+ standard callbacks is assumed.
+
+
+ Currently 6 ATA command protocols are used. They can be
+ sorted into the following four categories according to how
+ they are processed.
+
+
+
+ ATA NO DATA or DMA
+
+
+ ATA_PROT_NODATA and ATA_PROT_DMA fall into this category.
+ These types of commands don't require any software
+ intervention once issued. Device will raise interrupt on
+ completion.
+
+
+
+
+ ATA PIO
+
+
+ ATA_PROT_PIO is in this category. libata currently
+ implements PIO with polling. ATA_NIEN bit is set to turn
+ off interrupt and pio_task on ata_wq performs polling and
+ IO.
+
+
+
+
+ ATAPI NODATA or DMA
+
+
+ ATA_PROT_ATAPI_NODATA and ATA_PROT_ATAPI_DMA are in this
+ category. packet_task is used to poll BSY bit after
+ issuing PACKET command. Once BSY is turned off by the
+ device, packet_task transfers CDB and hands off processing
+ to interrupt handler.
+
+
+
+
+ ATAPI PIO
+
+
+ ATA_PROT_ATAPI is in this category. ATA_NIEN bit is set
+ and, as in ATAPI NODATA or DMA, packet_task submits cdb.
+ However, after submitting cdb, further processing (data
+ transfer) is handed off to pio_task.
+
+
+
+
+
+
+ How commands are completed
+
+ Once issued, all qc's are either completed with
+ ata_qc_complete() or time out. For commands which are handled
+ by interrupts, ata_host_intr() invokes ata_qc_complete(), and,
+ for PIO tasks, pio_task invokes ata_qc_complete(). In error
+ cases, packet_task may also complete commands.
+
+
+ ata_qc_complete() does the following.
+
+
+
+
+
+
+ DMA memory is unmapped.
+
+
+
+
+
+ ATA_QCFLAG_ACTIVE is clared from qc->flags.
+
+
+
+
+
+ qc->complete_fn() callback is invoked. If the return value of
+ the callback is not zero. Completion is short circuited and
+ ata_qc_complete() returns.
+
+
+
+
+
+ __ata_qc_complete() is called, which does
+
+
+
+
+ qc->flags is cleared to zero.
+
+
+
+
+
+ ap->active_tag and qc->tag are poisoned.
+
+
+
+
+
+ qc->waiting is claread & completed (in that order).
+
+
+
+
+
+ qc is deallocated by clearing appropriate bit in ap->qactive.
+
+
+
+
+
+
+
+
+
+
+ So, it basically notifies upper layer and deallocates qc. One
+ exception is short-circuit path in #3 which is used by
+ atapi_qc_complete().
+
+
+ For all non-ATAPI commands, whether it fails or not, almost
+ the same code path is taken and very little error handling
+ takes place. A qc is completed with success status if it
+ succeeded, with failed status otherwise.
+
+
+ However, failed ATAPI commands require more handling as
+ REQUEST SENSE is needed to acquire sense data. If an ATAPI
+ command fails, ata_qc_complete() is invoked with error status,
+ which in turn invokes atapi_qc_complete() via
+ qc->complete_fn() callback.
+
+
+ This makes atapi_qc_complete() set scmd->result to
+ SAM_STAT_CHECK_CONDITION, complete the scmd and return 1. As
+ the sense data is empty but scmd->result is CHECK CONDITION,
+ SCSI midlayer will invoke EH for the scmd, and returning 1
+ makes ata_qc_complete() to return without deallocating the qc.
+ This leads us to ata_scsi_error() with partially completed qc.
+
+
+
+
+ ata_scsi_error()
+
+ ata_scsi_error() is the current hostt->eh_strategy_handler()
+ for libata. As discussed above, this will be entered in two
+ cases - timeout and ATAPI error completion. This function
+ calls low level libata driver's eng_timeout() callback, the
+ standard callback for which is ata_eng_timeout(). It checks
+ if a qc is active and calls ata_qc_timeout() on the qc if so.
+ Actual error handling occurs in ata_qc_timeout().
+
+
+ If EH is invoked for timeout, ata_qc_timeout() stops BMDMA and
+ completes the qc. Note that as we're currently in EH, we
+ cannot call scsi_done. As described in SCSI EH doc, a
+ recovered scmd should be either retried with
+ scsi_queue_insert() or finished with scsi_finish_command().
+ Here, we override qc->scsidone with scsi_finish_command() and
+ calls ata_qc_complete().
+
+
+ If EH is invoked due to a failed ATAPI qc, the qc here is
+ completed but not deallocated. The purpose of this
+ half-completion is to use the qc as place holder to make EH
+ code reach this place. This is a bit hackish, but it works.
+
+
+ Once control reaches here, the qc is deallocated by invoking
+ __ata_qc_complete() explicitly. Then, internal qc for REQUEST
+ SENSE is issued. Once sense data is acquired, scmd is
+ finished by directly invoking scsi_finish_command() on the
+ scmd. Note that as we already have completed and deallocated
+ the qc which was associated with the scmd, we don't need
+ to/cannot call ata_qc_complete() again.
+
+
+
+
+ Problems with the current EH
+
+
+
+
+
+ Error representation is too crude. Currently any and all
+ error conditions are represented with ATA STATUS and ERROR
+ registers. Errors which aren't ATA device errors are treated
+ as ATA device errors by setting ATA_ERR bit. Better error
+ descriptor which can properly represent ATA and other
+ errors/exceptions is needed.
+
+
+
+
+
+ When handling timeouts, no action is taken to make device
+ forget about the timed out command and ready for new commands.
+
+
+
+
+
+ EH handling via ata_scsi_error() is not properly protected
+ from usual command processing. On EH entrance, the device is
+ not in quiescent state. Timed out commands may succeed or
+ fail any time. pio_task and atapi_task may still be running.
+
+
+
+
+
+ Too weak error recovery. Devices / controllers causing HSM
+ mismatch errors and other errors quite often require reset to
+ return to known state. Also, advanced error handling is
+ necessary to support features like NCQ and hotplug.
+
+
+
+
+
+ ATA errors are directly handled in the interrupt handler and
+ PIO errors in pio_task. This is problematic for advanced
+ error handling for the following reasons.
+
+
+ First, advanced error handling often requires context and
+ internal qc execution.
+
+
+ Second, even a simple failure (say, CRC error) needs
+ information gathering and could trigger complex error handling
+ (say, resetting & reconfiguring). Having multiple code
+ paths to gather information, enter EH and trigger actions
+ makes life painful.
+
+
+ Third, scattered EH code makes implementing low level drivers
+ difficult. Low level drivers override libata callbacks. If
+ EH is scattered over several places, each affected callbacks
+ should perform its part of error handling. This can be error
+ prone and painful.
+
+
+
+
+
+
+
libata Library
!Edrivers/scsi/libata-core.c
@@ -431,6 +787,722 @@ and other resources, etc.
!Idrivers/scsi/libata-scsi.c
+
+ ATA errors & exceptions
+
+
+ This chapter tries to identify what error/exception conditions exist
+ for ATA/ATAPI devices and describe how they should be handled in
+ implementation-neutral way.
+
+
+
+ The term 'error' is used to describe conditions where either an
+ explicit error condition is reported from device or a command has
+ timed out.
+
+
+
+ The term 'exception' is either used to describe exceptional
+ conditions which are not errors (say, power or hotplug events), or
+ to describe both errors and non-error exceptional conditions. Where
+ explicit distinction between error and exception is necessary, the
+ term 'non-error exception' is used.
+
+
+
+ Exception categories
+
+ Exceptions are described primarily with respect to legacy
+ taskfile + bus master IDE interface. If a controller provides
+ other better mechanism for error reporting, mapping those into
+ categories described below shouldn't be difficult.
+
+
+
+ In the following sections, two recovery actions - reset and
+ reconfiguring transport - are mentioned. These are described
+ further in .
+
+
+
+ HSM violation
+
+ This error is indicated when STATUS value doesn't match HSM
+ requirement during issuing or excution any ATA/ATAPI command.
+
+
+
+ Examples
+
+
+
+ ATA_STATUS doesn't contain !BSY && DRDY && !DRQ while trying
+ to issue a command.
+
+
+
+
+
+ !BSY && !DRQ during PIO data transfer.
+
+
+
+
+
+ DRQ on command completion.
+
+
+
+
+
+ !BSY && ERR after CDB tranfer starts but before the
+ last byte of CDB is transferred. ATA/ATAPI standard states
+ that "The device shall not terminate the PACKET command
+ with an error before the last byte of the command packet has
+ been written" in the error outputs description of PACKET
+ command and the state diagram doesn't include such
+ transitions.
+
+
+
+
+
+
+ In these cases, HSM is violated and not much information
+ regarding the error can be acquired from STATUS or ERROR
+ register. IOW, this error can be anything - driver bug,
+ faulty device, controller and/or cable.
+
+
+
+ As HSM is violated, reset is necessary to restore known state.
+ Reconfiguring transport for lower speed might be helpful too
+ as transmission errors sometimes cause this kind of errors.
+
+
+
+
+ ATA/ATAPI device error (non-NCQ / non-CHECK CONDITION)
+
+
+ These are errors detected and reported by ATA/ATAPI devices
+ indicating device problems. For this type of errors, STATUS
+ and ERROR register values are valid and describe error
+ condition. Note that some of ATA bus errors are detected by
+ ATA/ATAPI devices and reported using the same mechanism as
+ device errors. Those cases are described later in this
+ section.
+
+
+
+ For ATA commands, this type of errors are indicated by !BSY
+ && ERR during command execution and on completion.
+
+
+ For ATAPI commands,
+
+
+
+
+
+ !BSY && ERR && ABRT right after issuing PACKET
+ indicates that PACKET command is not supported and falls in
+ this category.
+
+
+
+
+
+ !BSY && ERR(==CHK) && !ABRT after the last
+ byte of CDB is transferred indicates CHECK CONDITION and
+ doesn't fall in this category.
+
+
+
+
+
+ !BSY && ERR(==CHK) && ABRT after the last byte
+ of CDB is transferred *probably* indicates CHECK CONDITION and
+ doesn't fall in this category.
+
+
+
+
+
+
+ Of errors detected as above, the followings are not ATA/ATAPI
+ device errors but ATA bus errors and should be handled
+ according to .
+
+
+
+
+
+ CRC error during data transfer
+
+
+ This is indicated by ICRC bit in the ERROR register and
+ means that corruption occurred during data transfer. Upto
+ ATA/ATAPI-7, the standard specifies that this bit is only
+ applicable to UDMA transfers but ATA/ATAPI-8 draft revision
+ 1f says that the bit may be applicable to multiword DMA and
+ PIO.
+
+
+
+
+
+ ABRT error during data transfer or on completion
+
+
+ Upto ATA/ATAPI-7, the standard specifies that ABRT could be
+ set on ICRC errors and on cases where a device is not able
+ to complete a command. Combined with the fact that MWDMA
+ and PIO transfer errors aren't allowed to use ICRC bit upto
+ ATA/ATAPI-7, it seems to imply that ABRT bit alone could
+ indicate tranfer errors.
+
+
+ However, ATA/ATAPI-8 draft revision 1f removes the part
+ that ICRC errors can turn on ABRT. So, this is kind of
+ gray area. Some heuristics are needed here.
+
+
+
+
+
+
+
+ ATA/ATAPI device errors can be further categorized as follows.
+
+
+
+
+
+ Media errors
+
+
+ This is indicated by UNC bit in the ERROR register. ATA
+ devices reports UNC error only after certain number of
+ retries cannot recover the data, so there's nothing much
+ else to do other than notifying upper layer.
+
+
+ READ and WRITE commands report CHS or LBA of the first
+ failed sector but ATA/ATAPI standard specifies that the
+ amount of transferred data on error completion is
+ indeterminate, so we cannot assume that sectors preceding
+ the failed sector have been transferred and thus cannot
+ complete those sectors successfully as SCSI does.
+
+
+
+
+
+ Media changed / media change requested error
+
+
+ <<TODO: fill here>>
+
+
+
+
+ Address error
+
+
+ This is indicated by IDNF bit in the ERROR register.
+ Report to upper layer.
+
+
+
+
+ Other errors
+
+
+ This can be invalid command or parameter indicated by ABRT
+ ERROR bit or some other error condition. Note that ABRT
+ bit can indicate a lot of things including ICRC and Address
+ errors. Heuristics needed.
+
+
+
+
+
+
+
+ Depending on commands, not all STATUS/ERROR bits are
+ applicable. These non-applicable bits are marked with
+ "na" in the output descriptions but upto ATA/ATAPI-7
+ no definition of "na" can be found. However,
+ ATA/ATAPI-8 draft revision 1f describes "N/A" as
+ follows.
+
+
+
+
+ 3.2.3.3a N/A
+
+
+ A keyword the indicates a field has no defined value in
+ this standard and should not be checked by the host or
+ device. N/A fields should be cleared to zero.
+
+
+
+
+
+
+
+ So, it seems reasonable to assume that "na" bits are
+ cleared to zero by devices and thus need no explicit masking.
+
+
+
+
+
+ ATAPI device CHECK CONDITION
+
+
+ ATAPI device CHECK CONDITION error is indicated by set CHK bit
+ (ERR bit) in the STATUS register after the last byte of CDB is
+ transferred for a PACKET command. For this kind of errors,
+ sense data should be acquired to gather information regarding
+ the errors. REQUEST SENSE packet command should be used to
+ acquire sense data.
+
+
+
+ Once sense data is acquired, this type of errors can be
+ handled similary to other SCSI errors. Note that sense data
+ may indicate ATA bus error (e.g. Sense Key 04h HARDWARE ERROR
+ && ASC/ASCQ 47h/00h SCSI PARITY ERROR). In such
+ cases, the error should be considered as an ATA bus error and
+ handled according to .
+
+
+
+
+
+ ATA device error (NCQ)
+
+
+ NCQ command error is indicated by cleared BSY and set ERR bit
+ during NCQ command phase (one or more NCQ commands
+ outstanding). Although STATUS and ERROR registers will
+ contain valid values describing the error, READ LOG EXT is
+ required to clear the error condition, determine which command
+ has failed and acquire more information.
+
+
+
+ READ LOG EXT Log Page 10h reports which tag has failed and
+ taskfile register values describing the error. With this
+ information the failed command can be handled as a normal ATA
+ command error as in and all
+ other in-flight commands must be retried. Note that this
+ retry should not be counted - it's likely that commands
+ retried this way would have completed normally if it were not
+ for the failed command.
+
+
+
+ Note that ATA bus errors can be reported as ATA device NCQ
+ errors. This should be handled as described in .
+
+
+
+ If READ LOG EXT Log Page 10h fails or reports NQ, we're
+ thoroughly screwed. This condition should be treated
+ according to .
+
+
+
+
+
+ ATA bus error
+
+
+ ATA bus error means that data corruption occurred during
+ transmission over ATA bus (SATA or PATA). This type of errors
+ can be indicated by
+
+
+
+
+
+
+ ICRC or ABRT error as described in .
+
+
+
+
+
+ Controller-specific error completion with error information
+ indicating transmission error.
+
+
+
+
+
+ On some controllers, command timeout. In this case, there may
+ be a mechanism to determine that the timeout is due to
+ transmission error.
+
+
+
+
+
+ Unknown/random errors, timeouts and all sorts of weirdities.
+
+
+
+
+
+
+ As described above, transmission errors can cause wide variety
+ of symptoms ranging from device ICRC error to random device
+ lockup, and, for many cases, there is no way to tell if an
+ error condition is due to transmission error or not;
+ therefore, it's necessary to employ some kind of heuristic
+ when dealing with errors and timeouts. For example,
+ encountering repetitive ABRT errors for known supported
+ command is likely to indicate ATA bus error.
+
+
+
+ Once it's determined that ATA bus errors have possibly
+ occurred, lowering ATA bus transmission speed is one of
+ actions which may alleviate the problem. See for more information.
+
+
+
+
+
+ PCI bus error
+
+
+ Data corruption or other failures during transmission over PCI
+ (or other system bus). For standard BMDMA, this is indicated
+ by Error bit in the BMDMA Status register. This type of
+ errors must be logged as it indicates something is very wrong
+ with the system. Resetting host controller is recommended.
+
+
+
+
+
+ Late completion
+
+
+ This occurs when timeout occurs and the timeout handler finds
+ out that the timed out command has completed successfully or
+ with error. This is usually caused by lost interrupts. This
+ type of errors must be logged. Resetting host controller is
+ recommended.
+
+
+
+
+
+ Unknown error (timeout)
+
+
+ This is when timeout occurs and the command is still
+ processing or the host and device are in unknown state. When
+ this occurs, HSM could be in any valid or invalid state. To
+ bring the device to known state and make it forget about the
+ timed out command, resetting is necessary. The timed out
+ command may be retried.
+
+
+
+ Timeouts can also be caused by transmission errors. Refer to
+ for more details.
+
+
+
+
+
+ Hotplug and power management exceptions
+
+
+ <<TODO: fill here>>
+
+
+
+
+
+
+
+ EH recovery actions
+
+
+ This section discusses several important recovery actions.
+
+
+
+ Clearing error condition
+
+
+ Many controllers require its error registers to be cleared by
+ error handler. Different controllers may have different
+ requirements.
+
+
+
+ For SATA, it's strongly recommended to clear at least SError
+ register during error handling.
+
+
+
+
+ Reset
+
+
+ During EH, resetting is necessary in the following cases.
+
+
+
+
+
+
+ HSM is in unknown or invalid state
+
+
+
+
+
+ HBA is in unknown or invalid state
+
+
+
+
+
+ EH needs to make HBA/device forget about in-flight commands
+
+
+
+
+
+ HBA/device behaves weirdly
+
+
+
+
+
+
+ Resetting during EH might be a good idea regardless of error
+ condition to improve EH robustness. Whether to reset both or
+ either one of HBA and device depends on situation but the
+ following scheme is recommended.
+
+
+
+
+
+
+ When it's known that HBA is in ready state but ATA/ATAPI
+ device in in unknown state, reset only device.
+
+
+
+
+
+ If HBA is in unknown state, reset both HBA and device.
+
+
+
+
+
+
+ HBA resetting is implementation specific. For a controller
+ complying to taskfile/BMDMA PCI IDE, stopping active DMA
+ transaction may be sufficient iff BMDMA state is the only HBA
+ context. But even mostly taskfile/BMDMA PCI IDE complying
+ controllers may have implementation specific requirements and
+ mechanism to reset themselves. This must be addressed by
+ specific drivers.
+
+
+
+ OTOH, ATA/ATAPI standard describes in detail ways to reset
+ ATA/ATAPI devices.
+
+
+
+
+ PATA hardware reset
+
+
+ This is hardware initiated device reset signalled with
+ asserted PATA RESET- signal. There is no standard way to
+ initiate hardware reset from software although some
+ hardware provides registers that allow driver to directly
+ tweak the RESET- signal.
+
+
+
+
+ Software reset
+
+
+ This is achieved by turning CONTROL SRST bit on for at
+ least 5us. Both PATA and SATA support it but, in case of
+ SATA, this may require controller-specific support as the
+ second Register FIS to clear SRST should be transmitted
+ while BSY bit is still set. Note that on PATA, this resets
+ both master and slave devices on a channel.
+
+
+
+
+ EXECUTE DEVICE DIAGNOSTIC command
+
+
+ Although ATA/ATAPI standard doesn't describe exactly, EDD
+ implies some level of resetting, possibly similar level
+ with software reset. Host-side EDD protocol can be handled
+ with normal command processing and most SATA controllers
+ should be able to handle EDD's just like other commands.
+ As in software reset, EDD affects both devices on a PATA
+ bus.
+
+
+ Although EDD does reset devices, this doesn't suit error
+ handling as EDD cannot be issued while BSY is set and it's
+ unclear how it will act when device is in unknown/weird
+ state.
+
+
+
+
+ ATAPI DEVICE RESET command
+
+
+ This is very similar to software reset except that reset
+ can be restricted to the selected device without affecting
+ the other device sharing the cable.
+
+
+
+
+ SATA phy reset
+
+
+ This is the preferred way of resetting a SATA device. In
+ effect, it's identical to PATA hardware reset. Note that
+ this can be done with the standard SCR Control register.
+ As such, it's usually easier to implement than software
+ reset.
+
+
+
+
+
+
+
+ One more thing to consider when resetting devices is that
+ resetting clears certain configuration parameters and they
+ need to be set to their previous or newly adjusted values
+ after reset.
+
+
+
+ Parameters affected are.
+
+
+
+
+
+
+ CHS set up with INITIALIZE DEVICE PARAMETERS (seldomly used)
+
+
+
+
+
+ Parameters set with SET FEATURES including transfer mode setting
+
+
+
+
+
+ Block count set with SET MULTIPLE MODE
+
+
+
+
+
+ Other parameters (SET MAX, MEDIA LOCK...)
+
+
+
+
+
+
+ ATA/ATAPI standard specifies that some parameters must be
+ maintained across hardware or software reset, but doesn't
+ strictly specify all of them. Always reconfiguring needed
+ parameters after reset is required for robustness. Note that
+ this also applies when resuming from deep sleep (power-off).
+
+
+
+ Also, ATA/ATAPI standard requires that IDENTIFY DEVICE /
+ IDENTIFY PACKET DEVICE is issued after any configuration
+ parameter is updated or a hardware reset and the result used
+ for further operation. OS driver is required to implement
+ revalidation mechanism to support this.
+
+
+
+
+
+ Reconfigure transport
+
+
+ For both PATA and SATA, a lot of corners are cut for cheap
+ connectors, cables or controllers and it's quite common to see
+ high transmission error rate. This can be mitigated by
+ lowering transmission speed.
+
+
+
+ The following is a possible scheme Jeff Garzik suggested.
+
+
+
+
+ If more than $N (3?) transmission errors happen in 15 minutes,
+
+
+
+
+ if SATA, decrease SATA PHY speed. if speed cannot be decreased,
+
+
+
+
+ decrease UDMA xfer speed. if at UDMA0, switch to PIO4,
+
+
+
+
+ decrease PIO xfer speed. if at PIO3, complain, but continue
+
+
+
+
+
+
+
+
+
+
+
ata_piix Internals
!Idrivers/scsi/ata_piix.c
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index 6dd274d7e1cf..2d65c2182161 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -906,9 +906,20 @@ Aside:
4. The I/O scheduler
-I/O schedulers are now per queue. They should be runtime switchable and modular
-but aren't yet. Jens has most bits to do this, but the sysfs implementation is
-missing.
+I/O scheduler, a.k.a. elevator, is implemented in two layers. Generic dispatch
+queue and specific I/O schedulers. Unless stated otherwise, elevator is used
+to refer to both parts and I/O scheduler to specific I/O schedulers.
+
+Block layer implements generic dispatch queue in ll_rw_blk.c and elevator.c.
+The generic dispatch queue is responsible for properly ordering barrier
+requests, requeueing, handling non-fs requests and all other subtleties.
+
+Specific I/O schedulers are responsible for ordering normal filesystem
+requests. They can also choose to delay certain requests to improve
+throughput or whatever purpose. As the plural form indicates, there are
+multiple I/O schedulers. They can be built as modules but at least one should
+be built inside the kernel. Each queue can choose different one and can also
+change to another one dynamically.
A block layer call to the i/o scheduler follows the convention elv_xxx(). This
calls elevator_xxx_fn in the elevator switch (drivers/block/elevator.c). Oh,
@@ -921,44 +932,36 @@ keeping work.
The functions an elevator may implement are: (* are mandatory)
elevator_merge_fn called to query requests for merge with a bio
-elevator_merge_req_fn " " " with another request
+elevator_merge_req_fn called when two requests get merged. the one
+ which gets merged into the other one will be
+ never seen by I/O scheduler again. IOW, after
+ being merged, the request is gone.
elevator_merged_fn called when a request in the scheduler has been
involved in a merge. It is used in the deadline
scheduler for example, to reposition the request
if its sorting order has changed.
-*elevator_next_req_fn returns the next scheduled request, or NULL
- if there are none (or none are ready).
+elevator_dispatch_fn fills the dispatch queue with ready requests.
+ I/O schedulers are free to postpone requests by
+ not filling the dispatch queue unless @force
+ is non-zero. Once dispatched, I/O schedulers
+ are not allowed to manipulate the requests -
+ they belong to generic dispatch queue.
-*elevator_add_req_fn called to add a new request into the scheduler
+elevator_add_req_fn called to add a new request into the scheduler
elevator_queue_empty_fn returns true if the merge queue is empty.
Drivers shouldn't use this, but rather check
if elv_next_request is NULL (without losing the
request if one exists!)
-elevator_remove_req_fn This is called when a driver claims ownership of
- the target request - it now belongs to the
- driver. It must not be modified or merged.
- Drivers must not lose the request! A subsequent
- call of elevator_next_req_fn must return the
- _next_ request.
-
-elevator_requeue_req_fn called to add a request to the scheduler. This
- is used when the request has alrnadebeen
- returned by elv_next_request, but hasn't
- completed. If this is not implemented then
- elevator_add_req_fn is called instead.
-
elevator_former_req_fn
elevator_latter_req_fn These return the request before or after the
one specified in disk sort order. Used by the
block layer to find merge possibilities.
-elevator_completed_req_fn called when a request is completed. This might
- come about due to being merged with another or
- when the device completes the request.
+elevator_completed_req_fn called when a request is completed.
elevator_may_queue_fn returns true if the scheduler wants to allow the
current context to queue a new request even if
@@ -967,13 +970,33 @@ elevator_may_queue_fn returns true if the scheduler wants to allow the
elevator_set_req_fn
elevator_put_req_fn Must be used to allocate and free any elevator
- specific storate for a request.
+ specific storage for a request.
+
+elevator_activate_req_fn Called when device driver first sees a request.
+ I/O schedulers can use this callback to
+ determine when actual execution of a request
+ starts.
+elevator_deactivate_req_fn Called when device driver decides to delay
+ a request by requeueing it.
elevator_init_fn
elevator_exit_fn Allocate and free any elevator specific storage
for a queue.
-4.2 I/O scheduler implementation
+4.2 Request flows seen by I/O schedulers
+All requests seens by I/O schedulers strictly follow one of the following three
+flows.
+
+ set_req_fn ->
+
+ i. add_req_fn -> (merged_fn ->)* -> dispatch_fn -> activate_req_fn ->
+ (deactivate_req_fn -> activate_req_fn ->)* -> completed_req_fn
+ ii. add_req_fn -> (merged_fn ->)* -> merge_req_fn
+ iii. [none]
+
+ -> put_req_fn
+
+4.3 I/O scheduler implementation
The generic i/o scheduler algorithm attempts to sort/merge/batch requests for
optimal disk scan and request servicing performance (based on generic
principles and device capabilities), optimized for:
@@ -993,18 +1016,7 @@ request in sort order to prevent binary tree lookups.
This arrangement is not a generic block layer characteristic however, so
elevators may implement queues as they please.
-ii. Last merge hint
-The last merge hint is part of the generic queue layer. I/O schedulers must do
-some management on it. For the most part, the most important thing is to make
-sure q->last_merge is cleared (set to NULL) when the request on it is no longer
-a candidate for merging (for example if it has been sent to the driver).
-
-The last merge performed is cached as a hint for the subsequent request. If
-sequential data is being submitted, the hint is used to perform merges without
-any scanning. This is not sufficient when there are multiple processes doing
-I/O though, so a "merge hash" is used by some schedulers.
-
-iii. Merge hash
+ii. Merge hash
AS and deadline use a hash table indexed by the last sector of a request. This
enables merging code to quickly look up "back merge" candidates, even when
multiple I/O streams are being performed at once on one disk.
@@ -1013,29 +1025,8 @@ multiple I/O streams are being performed at once on one disk.
are far less common than "back merges" due to the nature of most I/O patterns.
Front merges are handled by the binary trees in AS and deadline schedulers.
-iv. Handling barrier cases
-A request with flags REQ_HARDBARRIER or REQ_SOFTBARRIER must not be ordered
-around. That is, they must be processed after all older requests, and before
-any newer ones. This includes merges!
-
-In AS and deadline schedulers, barriers have the effect of flushing the reorder
-queue. The performance cost of this will vary from nothing to a lot depending
-on i/o patterns and device characteristics. Obviously they won't improve
-performance, so their use should be kept to a minimum.
-
-v. Handling insertion position directives
-A request may be inserted with a position directive. The directives are one of
-ELEVATOR_INSERT_BACK, ELEVATOR_INSERT_FRONT, ELEVATOR_INSERT_SORT.
-
-ELEVATOR_INSERT_SORT is a general directive for non-barrier requests.
-ELEVATOR_INSERT_BACK is used to insert a barrier to the back of the queue.
-ELEVATOR_INSERT_FRONT is used to insert a barrier to the front of the queue, and
-overrides the ordering requested by any previous barriers. In practice this is
-harmless and required, because it is used for SCSI requeueing. This does not
-require flushing the reorder queue, so does not impose a performance penalty.
-
-vi. Plugging the queue to batch requests in anticipation of opportunities for
- merge/sort optimizations
+iii. Plugging the queue to batch requests in anticipation of opportunities for
+ merge/sort optimizations
This is just the same as in 2.4 so far, though per-device unplugging
support is anticipated for 2.5. Also with a priority-based i/o scheduler,
@@ -1069,7 +1060,7 @@ Aside:
blk_kick_queue() to unplug a specific queue (right away ?)
or optionally, all queues, is in the plan.
-4.3 I/O contexts
+4.4 I/O contexts
I/O contexts provide a dynamically allocated per process data area. They may
be used in I/O schedulers, and in the block layer (could be used for IO statis,
priorities for example). See *io_context in drivers/block/ll_rw_blk.c, and
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index a55f0f95b171..b0fe41da007b 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -777,7 +777,7 @@ doing so is the same as described in the "Configuring Multiple Bonds
Manually" section, below.
NOTE: It has been observed that some Red Hat supplied kernels
-are apparently unable to rename modules at load time (the "-obonding1"
+are apparently unable to rename modules at load time (the "-o bond1"
part). Attempts to pass that option to modprobe will produce an
"Operation not permitted" error. This has been reported on some
Fedora Core kernels, and has been seen on RHEL 4 as well. On kernels
@@ -883,7 +883,8 @@ the above does not work, and the second bonding instance never sees
its options. In that case, the second options line can be substituted
as follows:
-install bonding1 /sbin/modprobe bonding -obond1 mode=balance-alb miimon=50
+install bond1 /sbin/modprobe --ignore-install bonding -o bond1 \
+ mode=balance-alb miimon=50
This may be repeated any number of times, specifying a new and
unique name in place of bond1 for each subsequent instance.
diff --git a/Makefile b/Makefile
index 1fa7e5343464..f1d121f23025 100644
--- a/Makefile
+++ b/Makefile
@@ -334,7 +334,7 @@ KALLSYMS = scripts/kallsyms
PERL = perl
CHECK = sparse
-CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ $(CF)
+CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF)
MODFLAGS = -DMODULE
CFLAGS_MODULE = $(MODFLAGS)
AFLAGS_MODULE = $(MODFLAGS)
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
index 582a3519fb28..9903e3a79102 100644
--- a/arch/alpha/kernel/pci-noop.c
+++ b/arch/alpha/kernel/pci-noop.c
@@ -154,7 +154,7 @@ pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
void *
dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, int gfp)
+ dma_addr_t *dma_handle, gfp_t gfp)
{
void *ret;
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 7cb23f12ecbd..c468e312e5f8 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -397,7 +397,7 @@ pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
{
void *cpu_addr;
long order = get_order(size);
- int gfp = GFP_ATOMIC;
+ gfp_t gfp = GFP_ATOMIC;
try_again:
cpu_addr = (void *)__get_free_pages(gfp, order);
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 11fff042aa81..682367bd0f65 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -204,6 +204,7 @@ config ARCH_H720X
config ARCH_AAEC2000
bool "Agilent AAEC-2000 based"
+ select ARM_AMBA
help
This enables support for systems based on the Agilent AAEC-2000
@@ -687,7 +688,8 @@ source "drivers/acorn/block/Kconfig"
if PCMCIA || ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX \
|| ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC \
- || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE
+ || ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE \
+ || MACH_MP1000
source "drivers/ide/Kconfig"
endif
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 7c7f475e213e..a54d2eb64892 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -39,7 +39,8 @@
defined(CONFIG_ARCH_IXP4XX) || \
defined(CONFIG_ARCH_IXP2000) || \
defined(CONFIG_ARCH_LH7A40X) || \
- defined(CONFIG_ARCH_OMAP)
+ defined(CONFIG_ARCH_OMAP) || \
+ defined(CONFIG_MACH_MP1000)
.macro loadsp, rb
addruart \rb
.endm
diff --git a/arch/arm/configs/mp1000_defconfig b/arch/arm/configs/mp1000_defconfig
new file mode 100644
index 000000000000..d2cbc6fada1d
--- /dev/null
+++ b/arch/arm/configs/mp1000_defconfig
@@ -0,0 +1,897 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-rc1
+# Fri Sep 16 15:48:13 2005
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+CONFIG_ARCH_CLPS711X=y
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CEIVA is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+CONFIG_MACH_MP1000=y
+CONFIG_MP1000_90MHZ=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM720T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_LV4T=y
+CONFIG_CPU_CACHE_V4=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WT=y
+CONFIG_CPU_TLB_V4WT=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_SMP is not set
+CONFIG_PREEMPT=y
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttyCL,38400 root=/dev/discs/disc0/part1 ip=any cs89x0_media=rj45"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=m
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-2
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=m
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+# CONFIG_MTD_CFI_I1 is not set
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=m
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=m
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_XIP is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=m
+CONFIG_MTD_PHYSMAP_START=0x0000000
+CONFIG_MTD_PHYSMAP_LEN=0x4000000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_EDB7312=m
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_MP1000=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+CONFIG_IDE_ARM=y
+CONFIG_BLK_DEV_IDE_MP1000=y
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+CONFIG_CS89x0=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+CONFIG_INPUT_EVBUG=y
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CLPS711X=y
+CONFIG_SERIAL_CLPS711X_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_WAITQ=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 1a85cfdad5ac..6055e1427ba3 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -11,6 +11,7 @@
*/
#include
#include
+#include
#include
#include
#include
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index f6de76e0a45d..baa09601a64e 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -345,7 +345,9 @@ static int bad_syscall(int n, struct pt_regs *regs)
struct thread_info *thread = current_thread_info();
siginfo_t info;
- if (current->personality != PER_LINUX && thread->exec_domain->handler) {
+ if (current->personality != PER_LINUX &&
+ current->personality != PER_LINUX_32BIT &&
+ thread->exec_domain->handler) {
thread->exec_domain->handler(n, regs);
return regs->ARM_r0;
}
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 8725d63e4219..71e5b99e519e 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -11,7 +11,7 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
strnlen_user.o strchr.o strrchr.o testchangebit.o \
testclearbit.o testsetbit.o uaccess.o getuser.o \
putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
- ucmpdi2.o lib1funcs.o div64.o \
+ ucmpdi2.o lib1funcs.o div64.o sha1.o \
io-readsb.o io-writesb.o io-readsl.o io-writesl.o
ifeq ($(CONFIG_CPU_32v3),y)
diff --git a/arch/arm/lib/sha1.S b/arch/arm/lib/sha1.S
new file mode 100644
index 000000000000..ff6ece487ffc
--- /dev/null
+++ b/arch/arm/lib/sha1.S
@@ -0,0 +1,206 @@
+/*
+ * linux/arch/arm/lib/sha1.S
+ *
+ * SHA transform optimized for ARM
+ *
+ * Copyright: (C) 2005 by Nicolas Pitre
+ * Created: September 17, 2005
+ *
+ * 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.
+ *
+ * The reference implementation for this code is linux/lib/sha1.c
+ */
+
+#include
+
+ .text
+
+
+/*
+ * void sha_transform(__u32 *digest, const char *in, __u32 *W)
+ *
+ * Note: the "in" ptr may be unaligned.
+ */
+
+ENTRY(sha_transform)
+
+ stmfd sp!, {r4 - r8, lr}
+
+ @ for (i = 0; i < 16; i++)
+ @ W[i] = be32_to_cpu(in[i]); */
+
+#ifdef __ARMEB__
+ mov r4, r0
+ mov r0, r2
+ mov r2, #64
+ bl memcpy
+ mov r2, r0
+ mov r0, r4
+#else
+ mov r3, r2
+ mov lr, #16
+1: ldrb r4, [r1], #1
+ ldrb r5, [r1], #1
+ ldrb r6, [r1], #1
+ ldrb r7, [r1], #1
+ subs lr, lr, #1
+ orr r5, r5, r4, lsl #8
+ orr r6, r6, r5, lsl #8
+ orr r7, r7, r6, lsl #8
+ str r7, [r3], #4
+ bne 1b
+#endif
+
+ @ for (i = 0; i < 64; i++)
+ @ W[i+16] = ror(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 31);
+
+ sub r3, r2, #4
+ mov lr, #64
+2: ldr r4, [r3, #4]!
+ subs lr, lr, #1
+ ldr r5, [r3, #8]
+ ldr r6, [r3, #32]
+ ldr r7, [r3, #52]
+ eor r4, r4, r5
+ eor r4, r4, r6
+ eor r4, r4, r7
+ mov r4, r4, ror #31
+ str r4, [r3, #64]
+ bne 2b
+
+ /*
+ * The SHA functions are:
+ *
+ * f1(B,C,D) = (D ^ (B & (C ^ D)))
+ * f2(B,C,D) = (B ^ C ^ D)
+ * f3(B,C,D) = ((B & C) | (D & (B | C)))
+ *
+ * Then the sub-blocks are processed as follows:
+ *
+ * A' = ror(A, 27) + f(B,C,D) + E + K + *W++
+ * B' = A
+ * C' = ror(B, 2)
+ * D' = C
+ * E' = D
+ *
+ * We therefore unroll each loop 5 times to avoid register shuffling.
+ * Also the ror for C (and also D and E which are successivelyderived
+ * from it) is applied in place to cut on an additional mov insn for
+ * each round.
+ */
+
+ .macro sha_f1, A, B, C, D, E
+ ldr r3, [r2], #4
+ eor ip, \C, \D
+ add \E, r1, \E, ror #2
+ and ip, \B, ip, ror #2
+ add \E, \E, \A, ror #27
+ eor ip, ip, \D, ror #2
+ add \E, \E, r3
+ add \E, \E, ip
+ .endm
+
+ .macro sha_f2, A, B, C, D, E
+ ldr r3, [r2], #4
+ add \E, r1, \E, ror #2
+ eor ip, \B, \C, ror #2
+ add \E, \E, \A, ror #27
+ eor ip, ip, \D, ror #2
+ add \E, \E, r3
+ add \E, \E, ip
+ .endm
+
+ .macro sha_f3, A, B, C, D, E
+ ldr r3, [r2], #4
+ add \E, r1, \E, ror #2
+ orr ip, \B, \C, ror #2
+ add \E, \E, \A, ror #27
+ and ip, ip, \D, ror #2
+ add \E, \E, r3
+ and r3, \B, \C, ror #2
+ orr ip, ip, r3
+ add \E, \E, ip
+ .endm
+
+ ldmia r0, {r4 - r8}
+
+ mov lr, #4
+ ldr r1, .L_sha_K + 0
+
+ /* adjust initial values */
+ mov r6, r6, ror #30
+ mov r7, r7, ror #30
+ mov r8, r8, ror #30
+
+3: subs lr, lr, #1
+ sha_f1 r4, r5, r6, r7, r8
+ sha_f1 r8, r4, r5, r6, r7
+ sha_f1 r7, r8, r4, r5, r6
+ sha_f1 r6, r7, r8, r4, r5
+ sha_f1 r5, r6, r7, r8, r4
+ bne 3b
+
+ ldr r1, .L_sha_K + 4
+ mov lr, #4
+
+4: subs lr, lr, #1
+ sha_f2 r4, r5, r6, r7, r8
+ sha_f2 r8, r4, r5, r6, r7
+ sha_f2 r7, r8, r4, r5, r6
+ sha_f2 r6, r7, r8, r4, r5
+ sha_f2 r5, r6, r7, r8, r4
+ bne 4b
+
+ ldr r1, .L_sha_K + 8
+ mov lr, #4
+
+5: subs lr, lr, #1
+ sha_f3 r4, r5, r6, r7, r8
+ sha_f3 r8, r4, r5, r6, r7
+ sha_f3 r7, r8, r4, r5, r6
+ sha_f3 r6, r7, r8, r4, r5
+ sha_f3 r5, r6, r7, r8, r4
+ bne 5b
+
+ ldr r1, .L_sha_K + 12
+ mov lr, #4
+
+6: subs lr, lr, #1
+ sha_f2 r4, r5, r6, r7, r8
+ sha_f2 r8, r4, r5, r6, r7
+ sha_f2 r7, r8, r4, r5, r6
+ sha_f2 r6, r7, r8, r4, r5
+ sha_f2 r5, r6, r7, r8, r4
+ bne 6b
+
+ ldmia r0, {r1, r2, r3, ip, lr}
+ add r4, r1, r4
+ add r5, r2, r5
+ add r6, r3, r6, ror #2
+ add r7, ip, r7, ror #2
+ add r8, lr, r8, ror #2
+ stmia r0, {r4 - r8}
+
+ ldmfd sp!, {r4 - r8, pc}
+
+.L_sha_K:
+ .word 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
+
+
+/*
+ * void sha_init(__u32 *buf)
+ */
+
+.L_sha_initial_digest:
+ .word 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
+
+ENTRY(sha_init)
+
+ str lr, [sp, #-4]!
+ adr r1, .L_sha_initial_digest
+ ldmia r1, {r1, r2, r3, ip, lr}
+ stmia r0, {r1, r2, r3, ip, lr}
+ ldr pc, [sp], #4
+
diff --git a/arch/arm/mach-aaec2000/Makefile b/arch/arm/mach-aaec2000/Makefile
index 20ec83896c37..a8e462f58bc9 100644
--- a/arch/arm/mach-aaec2000/Makefile
+++ b/arch/arm/mach-aaec2000/Makefile
@@ -3,7 +3,7 @@
#
# Common support (must be linked before board specific support)
-obj-y += core.o
+obj-y += core.o clock.o
# Specific board support
obj-$(CONFIG_MACH_AAED2000) += aaed2000.o
diff --git a/arch/arm/mach-aaec2000/aaed2000.c b/arch/arm/mach-aaec2000/aaed2000.c
index c9d899886648..f5ef69702296 100644
--- a/arch/arm/mach-aaec2000/aaed2000.c
+++ b/arch/arm/mach-aaec2000/aaed2000.c
@@ -27,16 +27,65 @@
#include
#include
+#include
+
#include "core.h"
+static void aaed2000_clcd_disable(struct clcd_fb *fb)
+{
+ AAED_EXT_GPIO &= ~AAED_EGPIO_LCD_PWR_EN;
+}
+
+static void aaed2000_clcd_enable(struct clcd_fb *fb)
+{
+ AAED_EXT_GPIO |= AAED_EGPIO_LCD_PWR_EN;
+}
+
+struct aaec2000_clcd_info clcd_info = {
+ .enable = aaed2000_clcd_enable,
+ .disable = aaed2000_clcd_disable,
+ .panel = {
+ .mode = {
+ .name = "Sharp",
+ .refresh = 60,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = 39721,
+ .left_margin = 20,
+ .right_margin = 44,
+ .upper_margin = 21,
+ .lower_margin = 34,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ },
+ .width = -1,
+ .height = -1,
+ .tim2 = TIM2_IVS | TIM2_IHS,
+ .cntl = CNTL_LCDTFT,
+ .bpp = 16,
+ },
+};
+
static void __init aaed2000_init_irq(void)
{
aaec2000_init_irq();
}
+static void __init aaed2000_init(void)
+{
+ aaec2000_set_clcd_plat_data(&clcd_info);
+}
+
+static struct map_desc aaed2000_io_desc[] __initdata = {
+ { EXT_GPIO_VBASE, EXT_GPIO_PBASE, EXT_GPIO_LENGTH, MT_DEVICE }, /* Ext GPIO */
+};
+
static void __init aaed2000_map_io(void)
{
aaec2000_map_io();
+ iotable_init(aaed2000_io_desc, ARRAY_SIZE(aaed2000_io_desc));
}
MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform")
@@ -47,4 +96,5 @@ MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform")
.map_io = aaed2000_map_io,
.init_irq = aaed2000_init_irq,
.timer = &aaec2000_timer,
+ .init_machine = aaed2000_init,
MACHINE_END
diff --git a/arch/arm/mach-aaec2000/clock.c b/arch/arm/mach-aaec2000/clock.c
new file mode 100644
index 000000000000..99e019169dda
--- /dev/null
+++ b/arch/arm/mach-aaec2000/clock.c
@@ -0,0 +1,110 @@
+/*
+ * linux/arch/arm/mach-aaec2000/clock.c
+ *
+ * Copyright (C) 2005 Nicolas Bellido Y Ortega
+ *
+ * Based on linux/arch/arm/mach-integrator/clock.c
+ *
+ * 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
+
+#include
+#include
+
+#include "clock.h"
+
+static LIST_HEAD(clocks);
+static DECLARE_MUTEX(clocks_sem);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ struct clk *p, *clk = ERR_PTR(-ENOENT);
+
+ down(&clocks_sem);
+ list_for_each_entry(p, &clocks, node) {
+ if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+ up(&clocks_sem);
+
+ return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+ module_put(clk->owner);
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+int clk_use(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_use);
+
+void clk_unuse(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_unuse);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_register(struct clk *clk)
+{
+ down(&clocks_sem);
+ list_add(&clk->node, &clocks);
+ up(&clocks_sem);
+ return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+ down(&clocks_sem);
+ list_del(&clk->node);
+ up(&clocks_sem);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+static int __init clk_init(void)
+{
+ return 0;
+}
+arch_initcall(clk_init);
diff --git a/arch/arm/mach-aaec2000/clock.h b/arch/arm/mach-aaec2000/clock.h
new file mode 100644
index 000000000000..d4bb74ff613f
--- /dev/null
+++ b/arch/arm/mach-aaec2000/clock.h
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/mach-aaec2000/clock.h
+ *
+ * Copyright (C) 2005 Nicolas Bellido Y Ortega
+ *
+ * Based on linux/arch/arm/mach-integrator/clock.h
+ *
+ * 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.
+ */
+struct module;
+
+struct clk {
+ struct list_head node;
+ unsigned long rate;
+ struct module *owner;
+ const char *name;
+ void *data;
+};
+
+int clk_register(struct clk *clk);
+void clk_unregister(struct clk *clk);
diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
index aece0cd4f0a3..0c53dab80905 100644
--- a/arch/arm/mach-aaec2000/core.c
+++ b/arch/arm/mach-aaec2000/core.c
@@ -13,19 +13,27 @@
#include
#include
#include
+#include
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
+#include
+#include
#include
#include
#include
+#include "core.h"
+#include "clock.h"
+
/*
* Common I/O mapping:
*
@@ -40,9 +48,17 @@
* default mapping provided here.
*/
static struct map_desc standard_io_desc[] __initdata = {
- /* virtual physical length type */
- { VIO_APB_BASE, PIO_APB_BASE, IO_APB_LENGTH, MT_DEVICE },
- { VIO_AHB_BASE, PIO_AHB_BASE, IO_AHB_LENGTH, MT_DEVICE }
+ {
+ .virtual = VIO_APB_BASE,
+ .physical = __phys_to_pfn(PIO_APB_BASE),
+ .length = IO_APB_LENGTH,
+ .type = MT_DEVICE
+ }, {
+ .virtual = VIO_AHB_BASE,
+ .physical = __phys_to_pfn(PIO_AHB_BASE),
+ .length = IO_AHB_LENGTH,
+ .type = MT_DEVICE
+ }
};
void __init aaec2000_map_io(void)
@@ -155,3 +171,116 @@ struct sys_timer aaec2000_timer = {
.offset = aaec2000_gettimeoffset,
};
+static struct clcd_panel mach_clcd_panel;
+
+static int aaec2000_clcd_setup(struct clcd_fb *fb)
+{
+ dma_addr_t dma;
+
+ fb->panel = &mach_clcd_panel;
+
+ fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, SZ_1M,
+ &dma, GFP_KERNEL);
+
+ if (!fb->fb.screen_base) {
+ printk(KERN_ERR "CLCD: unable to map framebuffer\n");
+ return -ENOMEM;
+ }
+
+ fb->fb.fix.smem_start = dma;
+ fb->fb.fix.smem_len = SZ_1M;
+
+ return 0;
+}
+
+static int aaec2000_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+ return dma_mmap_writecombine(&fb->dev->dev, vma,
+ fb->fb.screen_base,
+ fb->fb.fix.smem_start,
+ fb->fb.fix.smem_len);
+}
+
+static void aaec2000_clcd_remove(struct clcd_fb *fb)
+{
+ dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+ fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+static struct clcd_board clcd_plat_data = {
+ .name = "AAEC-2000",
+ .check = clcdfb_check,
+ .decode = clcdfb_decode,
+ .setup = aaec2000_clcd_setup,
+ .mmap = aaec2000_clcd_mmap,
+ .remove = aaec2000_clcd_remove,
+};
+
+static struct amba_device clcd_device = {
+ .dev = {
+ .bus_id = "mb:16",
+ .coherent_dma_mask = ~0,
+ .platform_data = &clcd_plat_data,
+ },
+ .res = {
+ .start = AAEC_CLCD_PHYS,
+ .end = AAEC_CLCD_PHYS + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ .irq = { INT_LCD, NO_IRQ },
+ .periphid = 0x41110,
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+ &clcd_device,
+};
+
+static struct clk aaec2000_clcd_clk = {
+ .name = "CLCDCLK",
+};
+
+void __init aaec2000_set_clcd_plat_data(struct aaec2000_clcd_info *clcd)
+{
+ clcd_plat_data.enable = clcd->enable;
+ clcd_plat_data.disable = clcd->disable;
+ memcpy(&mach_clcd_panel, &clcd->panel, sizeof(struct clcd_panel));
+}
+
+static struct flash_platform_data aaec2000_flash_data = {
+ .map_name = "cfi_probe",
+ .width = 4,
+};
+
+static struct resource aaec2000_flash_resource = {
+ .start = AAEC_FLASH_BASE,
+ .end = AAEC_FLASH_BASE + AAEC_FLASH_SIZE,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device aaec2000_flash_device = {
+ .name = "armflash",
+ .id = 0,
+ .dev = {
+ .platform_data = &aaec2000_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &aaec2000_flash_resource,
+};
+
+static int __init aaec2000_init(void)
+{
+ int i;
+
+ clk_register(&aaec2000_clcd_clk);
+
+ for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+ struct amba_device *d = amba_devs[i];
+ amba_device_register(d, &iomem_resource);
+ }
+
+ platform_device_register(&aaec2000_flash_device);
+
+ return 0;
+};
+arch_initcall(aaec2000_init);
+
diff --git a/arch/arm/mach-aaec2000/core.h b/arch/arm/mach-aaec2000/core.h
index 91893d848c16..daefc0ea14a1 100644
--- a/arch/arm/mach-aaec2000/core.h
+++ b/arch/arm/mach-aaec2000/core.h
@@ -9,8 +9,19 @@
*
*/
+#include
+
struct sys_timer;
extern struct sys_timer aaec2000_timer;
extern void __init aaec2000_map_io(void);
extern void __init aaec2000_init_irq(void);
+
+struct aaec2000_clcd_info {
+ struct clcd_panel panel;
+ void (*disable)(struct clcd_fb *);
+ void (*enable)(struct clcd_fb *);
+};
+
+extern void __init aaec2000_set_clcd_plat_data(struct aaec2000_clcd_info *);
+
diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig
index 0793dcf54f2e..d5c155045762 100644
--- a/arch/arm/mach-clps711x/Kconfig
+++ b/arch/arm/mach-clps711x/Kconfig
@@ -69,6 +69,17 @@ config EP72XX_ROM_BOOT
You almost surely want to say N here.
+config MACH_MP1000
+ bool "MACH_MP1000"
+ help
+ Say Y if you intend to run the kernel on the Comdial MP1000 platform.
+
+config MP1000_90MHZ
+ bool "MP1000_90MHZ"
+ depends on MACH_MP1000
+ help
+ Say Y if you have the MP1000 configured to be set at 90MHZ rather than 74MHZ
+
endmenu
endif
diff --git a/arch/arm/mach-clps711x/Makefile b/arch/arm/mach-clps711x/Makefile
index 4a197315f0cf..8a6dc1ccf8fe 100644
--- a/arch/arm/mach-clps711x/Makefile
+++ b/arch/arm/mach-clps711x/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_ARCH_CDB89712) += cdb89712.o
obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o
obj-$(CONFIG_ARCH_EDB7211) += edb7211-arch.o edb7211-mm.o
obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o
+obj-$(CONFIG_MACH_MP1000) += mp1000-mach.o mp1000-mm.o mp1000-seprom.o
obj-$(CONFIG_ARCH_P720T) += p720t.o
leds-$(CONFIG_ARCH_P720T) += p720t-leds.o
obj-$(CONFIG_LEDS) += $(leds-y)
diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c
index dc73feb1ffb0..43b9423d1440 100644
--- a/arch/arm/mach-clps711x/autcpu12.c
+++ b/arch/arm/mach-clps711x/autcpu12.c
@@ -46,10 +46,14 @@
*/
static struct map_desc autcpu12_io_desc[] __initdata = {
- /* virtual, physical, length, type */
- /* memory-mapped extra io and CS8900A Ethernet chip */
- /* ethernet chip */
- { AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, MT_DEVICE }
+ /* memory-mapped extra io and CS8900A Ethernet chip */
+ /* ethernet chip */
+ {
+ .virtual = AUTCPU12_VIRT_CS8900A,
+ .pfn = __phys_to_pfn(AUTCPU12_PHYS_CS8900A),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ }
};
void __init autcpu12_map_io(void)
diff --git a/arch/arm/mach-clps711x/cdb89712.c b/arch/arm/mach-clps711x/cdb89712.c
index a46c82cd2711..cba7be5a06c3 100644
--- a/arch/arm/mach-clps711x/cdb89712.c
+++ b/arch/arm/mach-clps711x/cdb89712.c
@@ -39,7 +39,12 @@
* ethernet driver, perhaps.
*/
static struct map_desc cdb89712_io_desc[] __initdata = {
- { ETHER_BASE, ETHER_START, ETHER_SIZE, MT_DEVICE }
+ {
+ .virtual = ETHER_BASE,
+ .pfn =__phys_to_pfn(ETHER_START),
+ .length = ETHER_SIZE,
+ .type = MT_DEVICE
+ }
};
static void __init cdb89712_map_io(void)
diff --git a/arch/arm/mach-clps711x/ceiva.c b/arch/arm/mach-clps711x/ceiva.c
index 780d91805984..35d51a759b59 100644
--- a/arch/arm/mach-clps711x/ceiva.c
+++ b/arch/arm/mach-clps711x/ceiva.c
@@ -37,11 +37,13 @@
#include "common.h"
static struct map_desc ceiva_io_desc[] __initdata = {
- /* virtual, physical, length, type */
-
- /* SED1355 controlled video RAM & registers */
- { CEIVA_VIRT_SED1355, CEIVA_PHYS_SED1355, SZ_2M, MT_DEVICE }
-
+ /* SED1355 controlled video RAM & registers */
+ {
+ .virtual = CEIVA_VIRT_SED1355,
+ .pfn = __phys_to_pfn(CEIVA_PHYS_SED1355),
+ .length = SZ_2M,
+ .type = MT_DEVICE
+ }
};
diff --git a/arch/arm/mach-clps711x/edb7211-mm.c b/arch/arm/mach-clps711x/edb7211-mm.c
index 7fd7b01822d0..72f8bb05d55e 100644
--- a/arch/arm/mach-clps711x/edb7211-mm.c
+++ b/arch/arm/mach-clps711x/edb7211-mm.c
@@ -51,15 +51,27 @@ extern void clps711x_map_io(void);
* happens).
*/
static struct map_desc edb7211_io_desc[] __initdata = {
- /* virtual, physical, length, type */
-
- /* memory-mapped extra keyboard row and CS8900A Ethernet chip */
- { EP7211_VIRT_EXTKBD, EP7211_PHYS_EXTKBD, SZ_1M, MT_DEVICE },
- { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, SZ_1M, MT_DEVICE },
-
- /* flash banks */
- { EP7211_VIRT_FLASH1, EP7211_PHYS_FLASH1, SZ_8M, MT_DEVICE },
- { EP7211_VIRT_FLASH2, EP7211_PHYS_FLASH2, SZ_8M, MT_DEVICE }
+ { /* memory-mapped extra keyboard row */
+ .virtual = EP7211_VIRT_EXTKBD,
+ .pfn = __phys_to_pfn(EP7211_PHYS_EXTKBD),
+ .length = SZ_1M,
+ .type - MT_DEVICE
+ }, { /* and CS8900A Ethernet chip */
+ .virtual = EP7211_VIRT_CS8900A,
+ .pfn = __phys_to_pfn(EP7211_PHYS_CS8900A),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ }, { /* flash banks */
+ .virtual = EP7211_VIRT_FLASH1,
+ .pfn = __phys_to_pfn(EP7211_PHYS_FLASH1),
+ .length = SZ_8M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = EP7211_VIRT_FLASH2,
+ .pfn = __phys_to_pfn(EP7211_PHYS_FLASH2),
+ .length = SZ_8M,
+ .type = MT_DEVICE
+ }
};
void __init edb7211_map_io(void)
diff --git a/arch/arm/mach-clps711x/mm.c b/arch/arm/mach-clps711x/mm.c
index 120b7cac84b5..a00f77ef8df8 100644
--- a/arch/arm/mach-clps711x/mm.c
+++ b/arch/arm/mach-clps711x/mm.c
@@ -24,6 +24,7 @@
#include
#include
+#include
#include
#include
#include
@@ -34,7 +35,12 @@
* This maps the generic CLPS711x registers
*/
static struct map_desc clps711x_io_desc[] __initdata = {
- { CLPS7111_VIRT_BASE, CLPS7111_PHYS_BASE, 1048576, MT_DEVICE }
+ {
+ .virtual = CLPS7111_VIRT_BASE,
+ .pfn = __phys_to_pfn(CLPS7111_PHYS_BASE),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ }
};
void __init clps711x_map_io(void)
diff --git a/arch/arm/mach-clps711x/mp1000-mach.c b/arch/arm/mach-clps711x/mp1000-mach.c
new file mode 100644
index 000000000000..c2816bcde5e7
--- /dev/null
+++ b/arch/arm/mach-clps711x/mp1000-mach.c
@@ -0,0 +1,49 @@
+/*
+ * linux/arch/arm/mach-mp1000/mp1000.c
+ *
+ * Copyright (C) 2005 Comdial Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "common.h"
+
+extern void mp1000_map_io(void);
+
+static void __init mp1000_init(void)
+{
+ seprom_init();
+}
+
+MACHINE_START(MP1000, "Comdial MP1000")
+ /* Maintainer: Jon Ringle */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xff000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0015100,
+ .map_io = mp1000_map_io,
+ .init_irq = clps711x_init_irq,
+ .init_machine = mp1000_init,
+ .timer = &clps711x_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-clps711x/mp1000-mm.c b/arch/arm/mach-clps711x/mp1000-mm.c
new file mode 100644
index 000000000000..20e810b0ec0c
--- /dev/null
+++ b/arch/arm/mach-clps711x/mp1000-mm.c
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/mach-mp1000/mm.c
+ *
+ * Extra MM routines for the MP1000
+ *
+ * Copyright (C) 2005 Comdial Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+extern void clps711x_map_io(void);
+
+static struct map_desc mp1000_io_desc[] __initdata = {
+ { MP1000_EIO_BASE, MP1000_EIO_START, MP1000_EIO_SIZE, MT_DEVICE },
+ { MP1000_FIO_BASE, MP1000_FIO_START, MP1000_FIO_SIZE, MT_DEVICE },
+ { MP1000_LIO_BASE, MP1000_LIO_START, MP1000_LIO_SIZE, MT_DEVICE },
+ { MP1000_NIO_BASE, MP1000_NIO_START, MP1000_NIO_SIZE, MT_DEVICE },
+ { MP1000_IDE_BASE, MP1000_IDE_START, MP1000_IDE_SIZE, MT_DEVICE },
+ { MP1000_DSP_BASE, MP1000_DSP_START, MP1000_DSP_SIZE, MT_DEVICE }
+};
+
+void __init mp1000_map_io(void)
+{
+ clps711x_map_io();
+ iotable_init(mp1000_io_desc, ARRAY_SIZE(mp1000_io_desc));
+}
diff --git a/arch/arm/mach-clps711x/mp1000-seprom.c b/arch/arm/mach-clps711x/mp1000-seprom.c
new file mode 100644
index 000000000000..b22d0bebb851
--- /dev/null
+++ b/arch/arm/mach-clps711x/mp1000-seprom.c
@@ -0,0 +1,195 @@
+/*`
+ * mp1000-seprom.c
+ *
+ * This file contains the Serial EEPROM code for the MP1000 board
+ *
+ * Copyright (C) 2005 Comdial Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+/* If SepromInit() can initialize and checksum the seprom successfully, */
+/* then it will point seprom_data_ptr at the shadow copy. */
+
+static eeprom_struct seprom_data; /* shadow copy of seprom content */
+
+eeprom_struct *seprom_data_ptr = 0; /* 0 => not initialized */
+
+/*
+ * Port D Bit 5 is Chip Select for EEPROM
+ * Port E Bit 0 is Input, Data out from EEPROM
+ * Port E Bit 1 is Output, Data in to EEPROM
+ * Port E Bit 2 is Output, CLK to EEPROM
+ */
+
+static char *port_d_ptr = (char *)(CLPS7111_VIRT_BASE + PDDR);
+static char *port_e_ptr = (char *)(CLPS7111_VIRT_BASE + PEDR);
+
+#define NO_OF_SHORTS 64 // Device is 64 x 16 bits
+#define ENABLE_RW 0
+#define DISABLE_RW 1
+
+static inline void toggle_seprom_clock(void)
+{
+ *port_e_ptr |= HwPortESepromCLK;
+ *port_e_ptr &= ~(HwPortESepromCLK);
+}
+
+static inline void select_eeprom(void)
+{
+ *port_d_ptr |= HwPortDEECS;
+ *port_e_ptr &= ~(HwPortESepromCLK);
+}
+
+static inline void deselect_eeprom(void)
+{
+ *port_d_ptr &= ~(HwPortDEECS);
+ *port_e_ptr &= ~(HwPortESepromDIn);
+}
+
+/*
+ * GetSepromDataPtr - returns pointer to shadow (RAM) copy of seprom
+ * and returns 0 if seprom is not initialized or
+ * has a checksum error.
+ */
+
+eeprom_struct* get_seprom_ptr(void)
+{
+ return seprom_data_ptr;
+}
+
+unsigned char* get_eeprom_mac_address(void)
+{
+ return seprom_data_ptr->variant.eprom_struct.mac_Address;
+}
+
+/*
+ * ReadSProm, Physically reads data from the Serial PROM
+ */
+static void read_sprom(short address, int length, eeprom_struct *buffer)
+{
+ short data = COMMAND_READ | (address & 0x3F);
+ short bit;
+ int i;
+
+ select_eeprom();
+
+ // Clock in 9 bits of the command
+ for (i = 0, bit = 0x100; i < 9; i++, bit >>= 1) {
+ if (data & bit)
+ *port_e_ptr |= HwPortESepromDIn;
+ else
+ *port_e_ptr &= ~(HwPortESepromDIn);
+
+ toggle_seprom_clock();
+ }
+
+ //
+ // Now read one or more shorts of data from the Seprom
+ //
+ while (length-- > 0) {
+ data = 0;
+
+ // Read 16 bits at a time
+ for (i = 0; i < 16; i++) {
+ data <<= 1;
+ toggle_seprom_clock();
+ data |= *port_e_ptr & HwPortESepromDOut;
+
+ }
+
+ buffer->variant.eprom_short_data[address++] = data;
+ }
+
+ deselect_eeprom();
+
+ return;
+}
+
+
+
+/*
+ * ReadSerialPROM
+ *
+ * Input: Pointer to array of 64 x 16 Bits
+ *
+ * Output: if no problem reading data is filled in
+ */
+static void read_serial_prom(eeprom_struct *data)
+{
+ read_sprom(0, 64, data);
+}
+
+
+//
+// Compute Serial EEPROM checksum
+//
+// Input: Pointer to struct with Eprom data
+//
+// Output: The computed Eprom checksum
+//
+static short compute_seprom_checksum(eeprom_struct *data)
+{
+ short checksum = 0;
+ int i;
+
+ for (i = 0; i < 126; i++) {
+ checksum += (short)data->variant.eprom_byte_data[i];
+ }
+
+ return((short)(0x5555 - (checksum & 0xFFFF)));
+}
+
+//
+// Make sure the data port bits for the SEPROM are correctly initialised
+//
+
+void __init seprom_init(void)
+{
+ short checksum;
+
+ // Init Port D
+ *(char *)(CLPS7111_VIRT_BASE + PDDDR) = 0x0;
+ *(char *)(CLPS7111_VIRT_BASE + PDDR) = 0x15;
+
+ // Init Port E
+ *(int *)(CLPS7111_VIRT_BASE + PEDDR) = 0x06;
+ *(int *)(CLPS7111_VIRT_BASE + PEDR) = 0x04;
+
+ //
+ // Make sure that EEPROM struct size never exceeds 128 bytes
+ //
+ if (sizeof(eeprom_struct) > 128) {
+ panic("Serial PROM struct size > 128, aborting read\n");
+ }
+
+ read_serial_prom(&seprom_data);
+
+ checksum = compute_seprom_checksum(&seprom_data);
+
+ if (checksum != seprom_data.variant.eprom_short_data[63]) {
+ panic("Serial EEPROM checksum failed\n");
+ }
+
+ seprom_data_ptr = &seprom_data;
+}
+
diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
index 5bdb90edf992..a1acb945fb51 100644
--- a/arch/arm/mach-clps711x/p720t.c
+++ b/arch/arm/mach-clps711x/p720t.c
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -42,8 +43,17 @@
* We map both here.
*/
static struct map_desc p720t_io_desc[] __initdata = {
- { SYSPLD_VIRT_BASE, SYSPLD_PHYS_BASE, 1048576, MT_DEVICE },
- { 0xfe400000, 0x10400000, 1048576, MT_DEVICE }
+ {
+ .virtual = SYSPLD_VIRT_BASE,
+ .pfn = __phys_to_pfn(SYSPLD_PHYS_BASE),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = 0xfe400000,
+ .pfn = __phys_to_pfn(0x10400000),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ }
};
static void __init
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index e216ab8b9e8f..0364ba4b539e 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -259,10 +259,27 @@ static void __init clps7500_init_irq(void)
}
static struct map_desc cl7500_io_desc[] __initdata = {
- { IO_BASE, IO_START, IO_SIZE, MT_DEVICE }, /* IO space */
- { ISA_BASE, ISA_START, ISA_SIZE, MT_DEVICE }, /* ISA space */
- { FLASH_BASE, FLASH_START, FLASH_SIZE, MT_DEVICE }, /* Flash */
- { LED_BASE, LED_START, LED_SIZE, MT_DEVICE } /* LED */
+ { /* IO space */
+ .virtual = IO_BASE,
+ .pfn = __phys_to_pfn(IO_START),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ }, { /* ISA space */
+ .virtual = ISA_BASE,
+ .pfn = __phys_to_pfn(ISA_START),
+ .length = ISA_SIZE,
+ .type = MT_DEVICE
+ }, { /* Flash */
+ .virtual = FLASH_BASE,
+ .pfn = __phys_to_pfn(FLASH_START),
+ .length = FLASH_SIZE,
+ .type = MT_DEVICE
+ }, { /* LED */
+ .virtual = LED_BASE,
+ .pfn = __phys_to_pfn(LED_START),
+ .length = LED_SIZE,
+ .type = MT_DEVICE
+ }
};
static void __init clps7500_map_io(void)
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 5aeadfd72143..15261646dcdd 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -76,16 +76,42 @@ static struct map_desc ebsa110_io_desc[] __initdata = {
/*
* sparse external-decode ISAIO space
*/
- { IRQ_STAT, TRICK4_PHYS, PGDIR_SIZE, MT_DEVICE }, /* IRQ_STAT/IRQ_MCLR */
- { IRQ_MASK, TRICK3_PHYS, PGDIR_SIZE, MT_DEVICE }, /* IRQ_MASK/IRQ_MSET */
- { SOFT_BASE, TRICK1_PHYS, PGDIR_SIZE, MT_DEVICE }, /* SOFT_BASE */
- { PIT_BASE, TRICK0_PHYS, PGDIR_SIZE, MT_DEVICE }, /* PIT_BASE */
+ { /* IRQ_STAT/IRQ_MCLR */
+ .virtual = IRQ_STAT,
+ .pfn = __phys_to_pfn(TRICK4_PHYS),
+ .length = PGDIR_SIZE,
+ .type = MT_DEVICE
+ }, { /* IRQ_MASK/IRQ_MSET */
+ .virtual = IRQ_MASK,
+ .pfn = __phys_to_pfn(TRICK3_PHYS),
+ .length = PGDIR_SIZE,
+ .type = MT_DEVICE
+ }, { /* SOFT_BASE */
+ .virtual = SOFT_BASE,
+ .pfn = __phys_to_pfn(TRICK1_PHYS),
+ .length = PGDIR_SIZE,
+ .type = MT_DEVICE
+ }, { /* PIT_BASE */
+ .virtual = PIT_BASE,
+ .pfn = __phys_to_pfn(TRICK0_PHYS),
+ .length = PGDIR_SIZE,
+ .type = MT_DEVICE
+ },
/*
* self-decode ISAIO space
*/
- { ISAIO_BASE, ISAIO_PHYS, ISAIO_SIZE, MT_DEVICE },
- { ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, MT_DEVICE }
+ {
+ .virtual = ISAIO_BASE,
+ .pfn = __phys_to_pfn(ISAIO_PHYS),
+ .length = ISAIO_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = ISAMEM_BASE,
+ .pfn = __phys_to_pfn(ISAMEM_PHYS),
+ .length = ISAMEM_SIZE,
+ .type = MT_DEVICE
+ }
};
static void __init ebsa110_map_io(void)
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
index ef7eb5dc91bd..c648bfb676a1 100644
--- a/arch/arm/mach-ebsa110/io.c
+++ b/arch/arm/mach-ebsa110/io.c
@@ -24,6 +24,7 @@
#include
#include
+#include
#include
#include
diff --git a/arch/arm/mach-epxa10db/mm.c b/arch/arm/mach-epxa10db/mm.c
index 2aa57fa46da3..e8832d0910ee 100644
--- a/arch/arm/mach-epxa10db/mm.c
+++ b/arch/arm/mach-epxa10db/mm.c
@@ -31,12 +31,37 @@
/* Page table mapping for I/O region */
static struct map_desc epxa10db_io_desc[] __initdata = {
- { IO_ADDRESS(EXC_REGISTERS_BASE), EXC_REGISTERS_BASE, SZ_16K, MT_DEVICE },
- { IO_ADDRESS(EXC_PLD_BLOCK0_BASE), EXC_PLD_BLOCK0_BASE, SZ_16K, MT_DEVICE },
- { IO_ADDRESS(EXC_PLD_BLOCK1_BASE), EXC_PLD_BLOCK1_BASE, SZ_16K, MT_DEVICE },
- { IO_ADDRESS(EXC_PLD_BLOCK2_BASE), EXC_PLD_BLOCK2_BASE, SZ_16K, MT_DEVICE },
- { IO_ADDRESS(EXC_PLD_BLOCK3_BASE), EXC_PLD_BLOCK3_BASE, SZ_16K, MT_DEVICE },
- { FLASH_VADDR(EXC_EBI_BLOCK0_BASE), EXC_EBI_BLOCK0_BASE, SZ_16M, MT_DEVICE }
+ {
+ .virtual = IO_ADDRESS(EXC_REGISTERS_BASE),
+ .pfn = __phys_to_pfn(EXC_REGISTERS_BASE),
+ .length = SZ_16K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(EXC_PLD_BLOCK0_BASE),
+ .pfn = __phys_to_pfn(EXC_PLD_BLOCK0_BASE),
+ .length = SZ_16K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(EXC_PLD_BLOCK1_BASE),
+ .pfn =__phys_to_pfn(EXC_PLD_BLOCK1_BASE),
+ .length = SZ_16K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(EXC_PLD_BLOCK2_BASE),
+ .physical = __phys_to_pfn(EXC_PLD_BLOCK2_BASE),
+ .length = SZ_16K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(EXC_PLD_BLOCK3_BASE),
+ .pfn = __phys_to_pfn(EXC_PLD_BLOCK3_BASE),
+ .length = SZ_16K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = FLASH_VADDR(EXC_EBI_BLOCK0_BASE),
+ .pfn = __phys_to_pfn(EXC_EBI_BLOCK0_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }
};
void __init epxa10db_map_io(void)
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index eb8238c1ef06..dc09fd200c16 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -130,8 +130,17 @@ void __init footbridge_init_irq(void)
* it means that we have extra bullet protection on our feet.
*/
static struct map_desc fb_common_io_desc[] __initdata = {
- { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, MT_DEVICE },
- { XBUS_BASE, 0x40000000, XBUS_SIZE, MT_DEVICE }
+ {
+ .virtual = ARMCSR_BASE,
+ .pfn = DC21285_ARMCSR_BASE,
+ .length = ARMCSR_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = XBUS_BASE,
+ .pfn = __phys_to_pfn(0x40000000),
+ .length = XBUS_SIZE,
+ .type = MT_DEVICE
+ }
};
/*
@@ -140,11 +149,32 @@ static struct map_desc fb_common_io_desc[] __initdata = {
*/
static struct map_desc ebsa285_host_io_desc[] __initdata = {
#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST)
- { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, MT_DEVICE },
- { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, MT_DEVICE },
- { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, MT_DEVICE },
- { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, MT_DEVICE },
- { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, MT_DEVICE }
+ {
+ .virtual = PCIMEM_BASE,
+ .pfn = __phys_to_pfn(DC21285_PCI_MEM),
+ .length = PCIMEM_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCICFG0_BASE,
+ .pfn = __phys_to_pfn(DC21285_PCI_TYPE_0_CONFIG),
+ .length = PCICFG0_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCICFG1_BASE,
+ .pfn = __phys_to_pfn(DC21285_PCI_TYPE_1_CONFIG),
+ .length = PCICFG1_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCIIACK_BASE,
+ .pfn = __phys_to_pfn(DC21285_PCI_IACK),
+ .length = PCIIACK_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCIO_BASE,
+ .pfn = __phys_to_pfn(DC21285_PCI_IO),
+ .length = PCIO_SIZE,
+ .type = MT_DEVICE
+ }
#endif
};
@@ -153,8 +183,17 @@ static struct map_desc ebsa285_host_io_desc[] __initdata = {
*/
static struct map_desc co285_io_desc[] __initdata = {
#ifdef CONFIG_ARCH_CO285
- { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, MT_DEVICE },
- { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, MT_DEVICE }
+ {
+ .virtual = PCIO_BASE,
+ .pfn = __phys_to_pfn(DC21285_PCI_IO),
+ .length = PCIO_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCIMEM_BASE,
+ .pfn = __phys_to_pfn(DC21285_PCI_MEM),
+ .length = PCIMEM_SIZE,
+ .type = MT_DEVICE
+ }
#endif
};
diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
index 5110e2e65ddd..c096b4569308 100644
--- a/arch/arm/mach-h720x/common.c
+++ b/arch/arm/mach-h720x/common.c
@@ -237,7 +237,12 @@ void __init h720x_init_irq (void)
}
static struct map_desc h720x_io_desc[] __initdata = {
- { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE },
+ {
+ .virtual = IO_VIRT,
+ .pfn = __phys_to_pfn(IO_PHYS),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ },
};
/* Initialize io tables */
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
index f8a742bb2d5b..cb14b0682cef 100644
--- a/arch/arm/mach-imx/generic.c
+++ b/arch/arm/mach-imx/generic.c
@@ -273,8 +273,12 @@ static struct platform_device *devices[] __initdata = {
};
static struct map_desc imx_io_desc[] __initdata = {
- /* virtual physical length type */
- {IMX_IO_BASE, IMX_IO_PHYS, IMX_IO_SIZE, MT_DEVICE},
+ {
+ .virtual = IMX_IO_BASE,
+ .pfn = __phys_to_pfn(IMX_IO_PHYS),
+ .length = IMX_IO_SIZE,
+ .type = MT_DEVICE
+ }
};
void __init
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
index a7511ddfe364..4cbdc1fe04b1 100644
--- a/arch/arm/mach-imx/mx1ads.c
+++ b/arch/arm/mach-imx/mx1ads.c
@@ -61,13 +61,37 @@ mx1ads_init(void)
}
static struct map_desc mx1ads_io_desc[] __initdata = {
- /* virtual physical length type */
- {IMX_CS0_VIRT, IMX_CS0_PHYS, IMX_CS0_SIZE, MT_DEVICE},
- {IMX_CS1_VIRT, IMX_CS1_PHYS, IMX_CS1_SIZE, MT_DEVICE},
- {IMX_CS2_VIRT, IMX_CS2_PHYS, IMX_CS2_SIZE, MT_DEVICE},
- {IMX_CS3_VIRT, IMX_CS3_PHYS, IMX_CS3_SIZE, MT_DEVICE},
- {IMX_CS4_VIRT, IMX_CS4_PHYS, IMX_CS4_SIZE, MT_DEVICE},
- {IMX_CS5_VIRT, IMX_CS5_PHYS, IMX_CS5_SIZE, MT_DEVICE},
+ {
+ .virtual = IMX_CS0_VIRT,
+ .pfn = __phys_to_pfn(IMX_CS0_PHYS),
+ .length = IMX_CS0_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IMX_CS1_VIRT,
+ .pfn = __phys_to_pfn(IMX_CS1_PHYS),
+ .length = IMX_CS1_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IMX_CS2_VIRT,
+ .pfn = __phys_to_pfn(IMX_CS2_PHYS),
+ .length = IMX_CS2_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IMX_CS3_VIRT,
+ .pfn = __phys_to_pfn(IMX_CS3_PHYS),
+ .length = IMX_CS3_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IMX_CS4_VIRT,
+ .pfn = __phys_to_pfn(IMX_CS4_PHYS),
+ .length = IMX_CS4_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IMX_CS5_VIRT,
+ .pfn = __phys_to_pfn(IMX_CS5_PHYS),
+ .length = IMX_CS5_SIZE,
+ .type = MT_DEVICE
+ }
};
static void __init
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 36e2b6eb67b7..f368b85f0447 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -75,19 +75,72 @@
*/
static struct map_desc ap_io_desc[] __initdata = {
- { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE },
- { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE },
- { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE },
- { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_64K, MT_DEVICE },
- { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE }
+ {
+ .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_SC_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_SC_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_UART1_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_UART1_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCI_MEMORY_VADDR,
+ .pfn = __phys_to_pfn(PHYS_PCI_MEM_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCI_CONFIG_VADDR,
+ .pfn = __phys_to_pfn(PHYS_PCI_CONFIG_BASE),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCI_V3_VADDR,
+ .pfn = __phys_to_pfn(PHYS_PCI_V3_BASE),
+ .length = SZ_64K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = PCI_IO_VADDR,
+ .pfn = __phys_to_pfn(PHYS_PCI_IO_BASE),
+ .length = SZ_64K,
+ .type = MT_DEVICE
+ }
};
static void __init ap_map_io(void)
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 2be5c03ab87f..aa34c58b96c4 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -74,17 +74,62 @@
*/
static struct map_desc intcp_io_desc[] __initdata = {
- { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE },
- { 0xfca00000, 0xca000000, SZ_4K, MT_DEVICE },
- { 0xfcb00000, 0xcb000000, SZ_4K, MT_DEVICE },
+ {
+ .virtual = IO_ADDRESS(INTEGRATOR_HDR_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_HDR_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_SC_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_SC_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_EBI_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_EBI_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_UART1_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_UART1_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(INTEGRATOR_GPIO_BASE),
+ .pfn = __phys_to_pfn(INTEGRATOR_GPIO_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = 0xfca00000,
+ .pfn = __phys_to_pfn(0xca000000),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = 0xfcb00000,
+ .pfn = __phys_to_pfn(0xcb000000),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }
};
static void __init intcp_map_io(void)
diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c
index 0f921ba2750c..bb5091223b63 100644
--- a/arch/arm/mach-iop3xx/iop321-setup.c
+++ b/arch/arm/mach-iop3xx/iop321-setup.c
@@ -38,13 +38,17 @@
* Standard IO mapping for all IOP321 based systems
*/
static struct map_desc iop321_std_desc[] __initdata = {
- /* virtual physical length type */
-
- /* mem mapped registers */
- { IOP321_VIRT_MEM_BASE, IOP321_PHYS_MEM_BASE, 0x00002000, MT_DEVICE },
-
- /* PCI IO space */
- { IOP321_PCI_LOWER_IO_VA, IOP321_PCI_LOWER_IO_PA, IOP321_PCI_IO_WINDOW_SIZE, MT_DEVICE }
+ { /* mem mapped registers */
+ .virtual = IOP321_VIRT_MEM_BASE,
+ .pfn = __phys_to_pfn(IOP321_PHYS_MEM_BASE),
+ .length = 0x00002000,
+ .type = MT_DEVICE
+ }, { /* PCI IO space */
+ .virtual = IOP321_PCI_LOWER_IO_VA,
+ .pfn = __phys_to_pfn(IOP321_PCI_LOWER_IO_PA),
+ .length = IOP321_PCI_IO_WINDOW_SIZE,
+ .type = MT_DEVICE
+ }
};
#ifdef CONFIG_ARCH_IQ80321
diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c
index fc74b722f72f..a2533c3ab42f 100644
--- a/arch/arm/mach-iop3xx/iop331-setup.c
+++ b/arch/arm/mach-iop3xx/iop331-setup.c
@@ -37,13 +37,17 @@
* Standard IO mapping for all IOP331 based systems
*/
static struct map_desc iop331_std_desc[] __initdata = {
- /* virtual physical length type */
-
- /* mem mapped registers */
- { IOP331_VIRT_MEM_BASE, IOP331_PHYS_MEM_BASE, 0x00002000, MT_DEVICE },
-
- /* PCI IO space */
- { IOP331_PCI_LOWER_IO_VA, IOP331_PCI_LOWER_IO_PA, IOP331_PCI_IO_WINDOW_SIZE, MT_DEVICE }
+ { /* mem mapped registers */
+ .virtual = IOP331_VIRT_MEM_BASE,
+ .pfn = __phys_to_pfn(IOP331_PHYS_MEM_BASE),
+ .length = 0x00002000,
+ .type = MT_DEVICE
+ }, { /* PCI IO space */
+ .virtual = IOP331_PCI_LOWER_IO_VA,
+ .pfn = __phys_to_pfn(IOP331_PCI_LOWER_IO_PA),
+ .length = IOP331_PCI_IO_WINDOW_SIZE,
+ .type = MT_DEVICE
+ }
};
static struct uart_port iop331_serial_ports[] = {
diff --git a/arch/arm/mach-iop3xx/iq31244-mm.c b/arch/arm/mach-iop3xx/iq31244-mm.c
index 55992ab586ba..e874b54eefe3 100644
--- a/arch/arm/mach-iop3xx/iq31244-mm.c
+++ b/arch/arm/mach-iop3xx/iq31244-mm.c
@@ -29,10 +29,12 @@
* We use RedBoot's setup for the onboard devices.
*/
static struct map_desc iq31244_io_desc[] __initdata = {
- /* virtual physical length type */
-
- /* on-board devices */
- { IQ31244_UART, IQ31244_UART, 0x00100000, MT_DEVICE }
+ { /* on-board devices */
+ .virtual = IQ31244_UART,
+ .pfn = __phys_to_pfn(IQ31244_UART),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
};
void __init iq31244_map_io(void)
diff --git a/arch/arm/mach-iop3xx/iq80321-mm.c b/arch/arm/mach-iop3xx/iq80321-mm.c
index bb3e9e5a9aff..d9cac5e1fc3d 100644
--- a/arch/arm/mach-iop3xx/iq80321-mm.c
+++ b/arch/arm/mach-iop3xx/iq80321-mm.c
@@ -29,10 +29,12 @@
* We use RedBoot's setup for the onboard devices.
*/
static struct map_desc iq80321_io_desc[] __initdata = {
- /* virtual physical length type */
-
- /* on-board devices */
- { IQ80321_UART, IQ80321_UART, 0x00100000, MT_DEVICE }
+ { /* on-board devices */
+ .virtual = IQ80321_UART,
+ .pfn = __phys_to_pfn(IQ80321_UART),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
};
void __init iq80321_map_io(void)
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index f4d7f1f6ef85..01c393c504d0 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -83,42 +83,42 @@ void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
static struct map_desc ixp2000_io_desc[] __initdata = {
{
.virtual = IXP2000_CAP_VIRT_BASE,
- .physical = IXP2000_CAP_PHYS_BASE,
+ .pfn = __phys_to_pfn(IXP2000_CAP_PHYS_BASE),
.length = IXP2000_CAP_SIZE,
.type = MT_DEVICE
}, {
.virtual = IXP2000_INTCTL_VIRT_BASE,
- .physical = IXP2000_INTCTL_PHYS_BASE,
+ .pfn = __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE),
.length = IXP2000_INTCTL_SIZE,
.type = MT_DEVICE
}, {
.virtual = IXP2000_PCI_CREG_VIRT_BASE,
- .physical = IXP2000_PCI_CREG_PHYS_BASE,
+ .pfn = __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE),
.length = IXP2000_PCI_CREG_SIZE,
.type = MT_DEVICE
}, {
.virtual = IXP2000_PCI_CSR_VIRT_BASE,
- .physical = IXP2000_PCI_CSR_PHYS_BASE,
+ .pfn = __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE),
.length = IXP2000_PCI_CSR_SIZE,
.type = MT_DEVICE
}, {
.virtual = IXP2000_MSF_VIRT_BASE,
- .physical = IXP2000_MSF_PHYS_BASE,
+ .pfn = __phys_to_pfn(IXP2000_MSF_PHYS_BASE),
.length = IXP2000_MSF_SIZE,
.type = MT_DEVICE
}, {
.virtual = IXP2000_PCI_IO_VIRT_BASE,
- .physical = IXP2000_PCI_IO_PHYS_BASE,
+ .pfn = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
.length = IXP2000_PCI_IO_SIZE,
.type = MT_DEVICE
}, {
.virtual = IXP2000_PCI_CFG0_VIRT_BASE,
- .physical = IXP2000_PCI_CFG0_PHYS_BASE,
+ .pfn = __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE),
.length = IXP2000_PCI_CFG0_SIZE,
.type = MT_DEVICE
}, {
.virtual = IXP2000_PCI_CFG1_VIRT_BASE,
- .physical = IXP2000_PCI_CFG1_PHYS_BASE,
+ .pfn = __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE),
.length = IXP2000_PCI_CFG1_SIZE,
.type = MT_DEVICE
}
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 63ba0191aa65..8b4a839b6279 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -176,7 +176,7 @@ void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long
*************************************************************************/
static struct map_desc ixdp2x00_io_desc __initdata = {
.virtual = IXDP2X00_VIRT_CPLD_BASE,
- .physical = IXDP2X00_PHYS_CPLD_BASE,
+ .pfn = __phys_to_pfn(IXDP2X00_PHYS_CPLD_BASE),
.length = IXDP2X00_CPLD_SIZE,
.type = MT_DEVICE
};
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index 7a5109921287..fee1d7b73503 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -136,7 +136,7 @@ void __init ixdp2x01_init_irq(void)
*************************************************************************/
static struct map_desc ixdp2x01_io_desc __initdata = {
.virtual = IXDP2X01_VIRT_CPLD_BASE,
- .physical = IXDP2X01_PHYS_CPLD_BASE,
+ .pfn = __phys_to_pfn(IXDP2X01_PHYS_CPLD_BASE),
.length = IXDP2X01_CPLD_REGION_SIZE,
.type = MT_DEVICE
};
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 36b6045213ee..6c396447c4e0 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -44,24 +44,24 @@
static struct map_desc ixp4xx_io_desc[] __initdata = {
{ /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACs, USB .... */
.virtual = IXP4XX_PERIPHERAL_BASE_VIRT,
- .physical = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .pfn = __phys_to_pfn(IXP4XX_PERIPHERAL_BASE_PHYS),
.length = IXP4XX_PERIPHERAL_REGION_SIZE,
.type = MT_DEVICE
}, { /* Expansion Bus Config Registers */
.virtual = IXP4XX_EXP_CFG_BASE_VIRT,
- .physical = IXP4XX_EXP_CFG_BASE_PHYS,
+ .pfn = __phys_to_pfn(IXP4XX_EXP_CFG_BASE_PHYS),
.length = IXP4XX_EXP_CFG_REGION_SIZE,
.type = MT_DEVICE
}, { /* PCI Registers */
.virtual = IXP4XX_PCI_CFG_BASE_VIRT,
- .physical = IXP4XX_PCI_CFG_BASE_PHYS,
+ .pfn = __phys_to_pfn(IXP4XX_PCI_CFG_BASE_PHYS),
.length = IXP4XX_PCI_CFG_REGION_SIZE,
.type = MT_DEVICE
},
#ifdef CONFIG_DEBUG_LL
{ /* Debug UART mapping */
.virtual = IXP4XX_DEBUG_UART_BASE_VIRT,
- .physical = IXP4XX_DEBUG_UART_BASE_PHYS,
+ .pfn = __phys_to_pfn(IXP4XX_DEBUG_UART_BASE_PHYS),
.length = IXP4XX_DEBUG_UART_REGION_SIZE,
.type = MT_DEVICE
}
diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c
index cb3dcd3bd00a..19f2fa2244c4 100644
--- a/arch/arm/mach-lh7a40x/arch-kev7a400.c
+++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c
@@ -26,8 +26,17 @@
/* This function calls the board specific IRQ initialization function. */
static struct map_desc kev7a400_io_desc[] __initdata = {
- { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE },
- { CPLD_VIRT, CPLD_PHYS, CPLD_SIZE, MT_DEVICE },
+ {
+ .virtual = IO_VIRT,
+ .pfn = __phys_to_pfn(IO_PHYS),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD_VIRT,
+ .pfn = __phys_to_pfn(CPLD_PHYS),
+ .length = CPLD_SIZE,
+ .type = MT_DEVICE
+ }
};
void __init kev7a400_map_io(void)
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
index 6eb61a17c63b..a20eabc132b0 100644
--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
@@ -227,23 +227,79 @@ void __init lh7a40x_init_board_irq (void)
}
static struct map_desc lpd7a400_io_desc[] __initdata = {
- { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE },
- /* Mapping added to work around chip select problems */
- { IOBARRIER_VIRT, IOBARRIER_PHYS, IOBARRIER_SIZE, MT_DEVICE },
- { CF_VIRT, CF_PHYS, CF_SIZE, MT_DEVICE },
+ {
+ .virtual = IO_VIRT,
+ .pfn = __phys_to_pfn(IO_PHYS),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ }, { /* Mapping added to work around chip select problems */
+ .virtual = IOBARRIER_VIRT,
+ .pfn = __phys_to_pfn(IOBARRIER_PHYS),
+ .length = IOBARRIER_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CF_VIRT,
+ .pfn = __phys_to_pfn(CF_PHYS),
+ .length = CF_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD02_VIRT,
+ .pfn = __phys_to_pfn(CPLD02_PHYS),
+ .length = CPLD02_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD06_VIRT,
+ .pfn = __phys_to_pfn(CPLD06_PHYS),
+ .length = CPLD06_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD08_VIRT,
+ .pfn = __phys_to_pfn(CPLD08_PHYS),
+ .length = CPLD08_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD0C_VIRT,
+ .pfn = __phys_to_pfn(CPLD0C_PHYS),
+ .length = CPLD0C_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD0E_VIRT,
+ .pfn = __phys_to_pfn(CPLD0E_PHYS),
+ .length = CPLD0E_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD10_VIRT,
+ .pfn = __phys_to_pfn(CPLD10_PHYS),
+ .length = CPLD10_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD12_VIRT,
+ .pfn = __phys_to_pfn(CPLD12_PHYS),
+ .length = CPLD12_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD14_VIRT,
+ .pfn = __phys_to_pfn(CPLD14_PHYS),
+ .length = CPLD14_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD16_VIRT,
+ .pfn = __phys_to_pfn(CPLD16_PHYS),
+ .length = CPLD16_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD18_VIRT,
+ .pfn = __phys_to_pfn(CPLD18_PHYS),
+ .length = CPLD18_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = CPLD1A_VIRT,
+ .pfn = __phys_to_pfn(CPLD1A_PHYS),
+ .length = CPLD1A_SIZE,
+ .type = MT_DEVICE
+ },
/* This mapping is redundant since the smc driver performs another. */
/* { CPLD00_VIRT, CPLD00_PHYS, CPLD00_SIZE, MT_DEVICE }, */
- { CPLD02_VIRT, CPLD02_PHYS, CPLD02_SIZE, MT_DEVICE },
- { CPLD06_VIRT, CPLD06_PHYS, CPLD06_SIZE, MT_DEVICE },
- { CPLD08_VIRT, CPLD08_PHYS, CPLD08_SIZE, MT_DEVICE },
- { CPLD0C_VIRT, CPLD0C_PHYS, CPLD0C_SIZE, MT_DEVICE },
- { CPLD0E_VIRT, CPLD0E_PHYS, CPLD0E_SIZE, MT_DEVICE },
- { CPLD10_VIRT, CPLD10_PHYS, CPLD10_SIZE, MT_DEVICE },
- { CPLD12_VIRT, CPLD12_PHYS, CPLD12_SIZE, MT_DEVICE },
- { CPLD14_VIRT, CPLD14_PHYS, CPLD14_SIZE, MT_DEVICE },
- { CPLD16_VIRT, CPLD16_PHYS, CPLD16_SIZE, MT_DEVICE },
- { CPLD18_VIRT, CPLD18_PHYS, CPLD18_SIZE, MT_DEVICE },
- { CPLD1A_VIRT, CPLD1A_PHYS, CPLD1A_SIZE, MT_DEVICE },
};
void __init
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index df0312b596e4..fd9183ff2ed5 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -103,8 +103,12 @@ static struct platform_device innovator_flash_device = {
/* Only FPGA needs to be mapped here. All others are done with ioremap */
static struct map_desc innovator1510_io_desc[] __initdata = {
-{ OMAP1510_FPGA_BASE, OMAP1510_FPGA_START, OMAP1510_FPGA_SIZE,
- MT_DEVICE },
+ {
+ .virtual = OMAP1510_FPGA_BASE,
+ .pfn = __phys_to_pfn(OMAP1510_FPGA_START),
+ .length = OMAP1510_FPGA_SIZE,
+ .type = MT_DEVICE
+ }
};
static struct resource innovator1510_smc91x_resources[] = {
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 107c68c8ab54..2ba26e239108 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -134,8 +134,12 @@ void omap_perseus2_init_irq(void)
/* Only FPGA needs to be mapped here. All others are done with ioremap */
static struct map_desc omap_perseus2_io_desc[] __initdata = {
- {H2P2_DBG_FPGA_BASE, H2P2_DBG_FPGA_START, H2P2_DBG_FPGA_SIZE,
- MT_DEVICE},
+ {
+ .virtual = H2P2_DBG_FPGA_BASE,
+ .pfn = __phys_to_pfn(H2P2_DBG_FPGA_START),
+ .length = H2P2_DBG_FPGA_SIZE,
+ .type = MT_DEVICE
+ }
};
static void __init omap_perseus2_map_io(void)
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index eb8261d7dead..79fb86535ebc 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -26,27 +26,59 @@ extern void omap_sram_init(void);
* default mapping provided here.
*/
static struct map_desc omap_io_desc[] __initdata = {
- { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE },
+ {
+ .virtual = IO_VIRT,
+ .pfn = __phys_to_pfn(IO_PHYS),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ }
};
#ifdef CONFIG_ARCH_OMAP730
static struct map_desc omap730_io_desc[] __initdata = {
- { OMAP730_DSP_BASE, OMAP730_DSP_START, OMAP730_DSP_SIZE, MT_DEVICE },
- { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE },
+ {
+ .virtual = OMAP730_DSP_BASE,
+ .pfn = __phys_to_pfn(OMAP730_DSP_START),
+ .length = OMAP730_DSP_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = OMAP730_DSPREG_BASE,
+ .pfn = __phys_to_pfn(OMAP730_DSPREG_START),
+ .length = OMAP730_DSPREG_SIZE,
+ .type = MT_DEVICE
+ }
};
#endif
#ifdef CONFIG_ARCH_OMAP1510
static struct map_desc omap1510_io_desc[] __initdata = {
- { OMAP1510_DSP_BASE, OMAP1510_DSP_START, OMAP1510_DSP_SIZE, MT_DEVICE },
- { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE },
+ {
+ .virtual = OMAP1510_DSP_BASE,
+ .pfn = __phys_to_pfn(OMAP1510_DSP_START),
+ .length = OMAP1510_DSP_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = OMAP1510_DSPREG_BASE,
+ .pfn = __phys_to_pfn(OMAP1510_DSPREG_START),
+ .length = OMAP1510_DSPREG_SIZE,
+ .type = MT_DEVICE
+ }
};
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
static struct map_desc omap16xx_io_desc[] __initdata = {
- { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE },
- { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
+ {
+ .virtual = OMAP16XX_DSP_BASE,
+ .pfn = __phys_to_pfn(OMAP16XX_DSP_START),
+ .length = OMAP16XX_DSP_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = OMAP16XX_DSPREG_BASE,
+ .pfn = __phys_to_pfn(OMAP16XX_DSPREG_START),
+ .length = OMAP16XX_DSPREG_SIZE,
+ .type = MT_DEVICE
+ }
};
#endif
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 1d7677669a76..3248bc9b9495 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
#include "generic.h"
@@ -92,14 +93,42 @@ EXPORT_SYMBOL(pxa_set_cken);
* and cache flush area.
*/
static struct map_desc standard_io_desc[] __initdata = {
- /* virtual physical length type */
- { 0xf2000000, 0x40000000, 0x02000000, MT_DEVICE }, /* Devs */
- { 0xf4000000, 0x44000000, 0x00100000, MT_DEVICE }, /* LCD */
- { 0xf6000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Mem Ctl */
- { 0xf8000000, 0x4c000000, 0x00100000, MT_DEVICE }, /* USB host */
- { 0xfa000000, 0x50000000, 0x00100000, MT_DEVICE }, /* Camera */
- { 0xfe000000, 0x58000000, 0x00100000, MT_DEVICE }, /* IMem ctl */
- { 0xff000000, 0x00000000, 0x00100000, MT_DEVICE } /* UNCACHED_PHYS_0 */
+ { /* Devs */
+ .virtual = 0xf2000000,
+ .pfn = __phys_to_pfn(0x40000000),
+ .length = 0x02000000,
+ .type = MT_DEVICE
+ }, { /* LCD */
+ .virtual = 0xf4000000,
+ .pfn = __phys_to_pfn(0x44000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* Mem Ctl */
+ .virtual = 0xf6000000,
+ .pfn = __phys_to_pfn(0x48000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* USB host */
+ .virtual = 0xf8000000,
+ .pfn = __phys_to_pfn(0x4c000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* Camera */
+ .virtual = 0xfa000000,
+ .pfn = __phys_to_pfn(0x50000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* IMem ctl */
+ .virtual = 0xfe000000,
+ .pfn = __phys_to_pfn(0x58000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* UNCACHED_PHYS_0 */
+ .virtual = 0xff000000,
+ .pfn = __phys_to_pfn(0x00000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
};
void __init pxa_map_io(void)
@@ -225,6 +254,10 @@ static struct platform_device stuart_device = {
.name = "pxa2xx-uart",
.id = 2,
};
+static struct platform_device hwuart_device = {
+ .name = "pxa2xx-uart",
+ .id = 3,
+};
static struct resource i2c_resources[] = {
{
@@ -265,10 +298,26 @@ static struct resource i2s_resources[] = {
static struct platform_device i2s_device = {
.name = "pxa2xx-i2s",
.id = -1,
- .resource = i2c_resources,
+ .resource = i2s_resources,
.num_resources = ARRAY_SIZE(i2s_resources),
};
+static u64 pxaficp_dmamask = ~(u32)0;
+
+static struct platform_device pxaficp_device = {
+ .name = "pxa2xx-ir",
+ .id = -1,
+ .dev = {
+ .dma_mask = &pxaficp_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
+void __init pxa_set_ficp_info(struct pxaficp_platform_data *info)
+{
+ pxaficp_device.dev.platform_data = info;
+}
+
static struct platform_device *devices[] __initdata = {
&pxamci_device,
&udc_device,
@@ -276,13 +325,26 @@ static struct platform_device *devices[] __initdata = {
&ffuart_device,
&btuart_device,
&stuart_device,
+ &pxaficp_device,
&i2c_device,
&i2s_device,
};
static int __init pxa_init(void)
{
- return platform_add_devices(devices, ARRAY_SIZE(devices));
+ int cpuid, ret;
+
+ ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+ if (ret)
+ return ret;
+
+ /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
+ cpuid = read_cpuid(CPUID_ID);
+ if (((cpuid >> 4) & 0xfff) == 0x2d0 ||
+ ((cpuid >> 4) & 0xfff) == 0x290)
+ ret = platform_device_register(&hwuart_device);
+
+ return ret;
}
subsys_initcall(pxa_init);
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 386e107b53cc..01a83ab09ac3 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -152,16 +152,17 @@ static void __init idp_init_irq(void)
}
static struct map_desc idp_io_desc[] __initdata = {
- /* virtual physical length type */
-
- { IDP_COREVOLT_VIRT,
- IDP_COREVOLT_PHYS,
- IDP_COREVOLT_SIZE,
- MT_DEVICE },
- { IDP_CPLD_VIRT,
- IDP_CPLD_PHYS,
- IDP_CPLD_SIZE,
- MT_DEVICE }
+ {
+ .virtual = IDP_COREVOLT_VIRT,
+ .pfn = __phys_to_pfn(IDP_COREVOLT_PHYS),
+ .length = IDP_COREVOLT_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IDP_CPLD_VIRT,
+ .pfn = __phys_to_pfn(IDP_CPLD_PHYS),
+ .length = IDP_CPLD_SIZE,
+ .type = MT_DEVICE
+ }
};
static void __init idp_map_io(void)
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 1f38033921e9..beccf455f796 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -35,6 +35,7 @@
#include
#include
#include
+#include
#include
#include
@@ -237,16 +238,40 @@ static struct pxamci_platform_data lubbock_mci_platform_data = {
.init = lubbock_mci_init,
};
+static void lubbock_irda_transceiver_mode(struct device *dev, int mode)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (mode & IR_SIRMODE) {
+ LUB_MISC_WR &= ~(1 << 4);
+ } else if (mode & IR_FIRMODE) {
+ LUB_MISC_WR |= 1 << 4;
+ }
+ local_irq_restore(flags);
+}
+
+static struct pxaficp_platform_data lubbock_ficp_platform_data = {
+ .transceiver_cap = IR_SIRMODE | IR_FIRMODE,
+ .transceiver_mode = lubbock_irda_transceiver_mode,
+};
+
static void __init lubbock_init(void)
{
pxa_set_udc_info(&udc_info);
set_pxa_fb_info(&sharp_lm8v31);
pxa_set_mci_info(&lubbock_mci_platform_data);
+ pxa_set_ficp_info(&lubbock_ficp_platform_data);
(void) platform_add_devices(devices, ARRAY_SIZE(devices));
}
static struct map_desc lubbock_io_desc[] __initdata = {
- { LUBBOCK_FPGA_VIRT, LUBBOCK_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */
+ { /* CPLD */
+ .virtual = LUBBOCK_FPGA_VIRT,
+ .pfn = __phys_to_pfn(LUBBOCK_FPGA_PHYS),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
};
static void __init lubbock_map_io(void)
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 85fdb5b1470a..a48c64026e1f 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -37,6 +37,7 @@
#include
#include
#include
+#include
#include "generic.h"
@@ -294,6 +295,29 @@ static struct pxamci_platform_data mainstone_mci_platform_data = {
.exit = mainstone_mci_exit,
};
+static void mainstone_irda_transceiver_mode(struct device *dev, int mode)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (mode & IR_SIRMODE) {
+ MST_MSCWR1 &= ~MST_MSCWR1_IRDA_FIR;
+ } else if (mode & IR_FIRMODE) {
+ MST_MSCWR1 |= MST_MSCWR1_IRDA_FIR;
+ }
+ if (mode & IR_OFF) {
+ MST_MSCWR1 = (MST_MSCWR1 & ~MST_MSCWR1_IRDA_MASK) | MST_MSCWR1_IRDA_OFF;
+ } else {
+ MST_MSCWR1 = (MST_MSCWR1 & ~MST_MSCWR1_IRDA_MASK) | MST_MSCWR1_IRDA_FULL;
+ }
+ local_irq_restore(flags);
+}
+
+static struct pxaficp_platform_data mainstone_ficp_platform_data = {
+ .transceiver_cap = IR_SIRMODE | IR_FIRMODE | IR_OFF,
+ .transceiver_mode = mainstone_irda_transceiver_mode,
+};
+
static void __init mainstone_init(void)
{
/*
@@ -313,11 +337,17 @@ static void __init mainstone_init(void)
set_pxa_fb_info(&toshiba_ltm035a776c);
pxa_set_mci_info(&mainstone_mci_platform_data);
+ pxa_set_ficp_info(&mainstone_ficp_platform_data);
}
static struct map_desc mainstone_io_desc[] __initdata = {
- { MST_FPGA_VIRT, MST_FPGA_PHYS, 0x00100000, MT_DEVICE }, /* CPLD */
+ { /* CPLD */
+ .virtual = MST_FPGA_VIRT,
+ .pfn = __phys_to_pfn(MST_FPGA_PHYS),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
};
static void __init mainstone_map_io(void)
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 7869c3b4e62f..573a5758e781 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -129,7 +129,7 @@ void pxa_cpu_pm_enter(suspend_state_t state)
case PM_SUSPEND_MEM:
/* set resume return address */
PSPR = virt_to_phys(pxa_cpu_resume);
- pxa_cpu_suspend(3);
+ pxa_cpu_suspend(PWRMODE_SLEEP);
break;
}
}
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 9a791b07118d..09a5d593f04b 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -157,7 +157,7 @@ void pxa_cpu_pm_enter(suspend_state_t state)
case PM_SUSPEND_MEM:
/* set resume return address */
PSPR = virt_to_phys(pxa_cpu_resume);
- pxa_cpu_suspend(3);
+ pxa_cpu_suspend(PWRMODE_SLEEP);
break;
}
}
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
index 5786ccad938c..c9862688ff3d 100644
--- a/arch/arm/mach-pxa/sleep.S
+++ b/arch/arm/mach-pxa/sleep.S
@@ -28,7 +28,9 @@
/*
* pxa_cpu_suspend()
*
- * Forces CPU into sleep state
+ * Forces CPU into sleep state.
+ *
+ * r0 = value for PWRMODE M field for desired sleep state
*/
ENTRY(pxa_cpu_suspend)
@@ -53,6 +55,7 @@ ENTRY(pxa_cpu_suspend)
mov r10, sp
stmfd sp!, {r3 - r10}
+ mov r5, r0 @ save sleep mode
@ preserve phys address of stack
mov r0, sp
bl sleep_phys_sp
@@ -66,7 +69,7 @@ ENTRY(pxa_cpu_suspend)
@ (also workaround for sighting 28071)
@ prepare value for sleep mode
- mov r1, #3 @ sleep mode
+ mov r1, r5 @ sleep mode
@ prepare pointer to physical address 0 (virtual mapping in generic.c)
mov r2, #UNCACHED_PHYS_0
diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S
index 8a3f27b76784..6f6dbbd08021 100644
--- a/arch/arm/mach-pxa/standby.S
+++ b/arch/arm/mach-pxa/standby.S
@@ -21,7 +21,7 @@
ENTRY(pxa_cpu_standby)
ldr r0, =PSSR
mov r1, #(PSSR_PH | PSSR_STS)
- mov r2, #2
+ mov r2, #PWRMODE_STANDBY
mov r3, #UNCACHED_PHYS_0 @ Read mem context in.
ldr ip, [r3]
b 1f
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index e3587efec4bf..5c4ac1c008a6 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -61,9 +61,22 @@ static int __init parse_tag_acorn(const struct tag *tag)
__tagtable(ATAG_ACORN, parse_tag_acorn);
static struct map_desc rpc_io_desc[] __initdata = {
- { SCREEN_BASE, SCREEN_START, 2*1048576, MT_DEVICE }, /* VRAM */
- { (u32)IO_BASE, IO_START, IO_SIZE , MT_DEVICE }, /* IO space */
- { EASI_BASE, EASI_START, EASI_SIZE, MT_DEVICE } /* EASI space */
+ { /* VRAM */
+ .virtual = SCREEN_BASE,
+ .pfn = __phys_to_pfn(SCREEN_START),
+ .length = 2*1048576,
+ .type = MT_DEVICE
+ }, { /* IO space */
+ .virtual = (u32)IO_BASE,
+ .pfn = __phys_to_pfn(IO_START),
+ .length = IO_SIZE ,
+ .type = MT_DEVICE
+ }, { /* EASI space */
+ .virtual = EASI_BASE,
+ .pfn = __phys_to_pfn(EASI_START),
+ .length = EASI_SIZE,
+ .type = MT_DEVICE
+ }
};
static void __init rpc_map_io(void)
diff --git a/arch/arm/mach-s3c2410/cpu.h b/arch/arm/mach-s3c2410/cpu.h
index 478c15c0e36a..9cbe5eef492b 100644
--- a/arch/arm/mach-s3c2410/cpu.h
+++ b/arch/arm/mach-s3c2410/cpu.h
@@ -21,7 +21,7 @@
/* todo - fix when rmk changes iodescs to use `void __iomem *` */
-#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, S3C2410_PA_##x, S3C24XX_SZ_##x, MT_DEVICE }
+#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C2410_PA_##x), S3C24XX_SZ_##x, MT_DEVICE }
#ifndef MHZ
#define MHZ (1000*1000)
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c
index 0077937a7ab8..08bc7d95a45d 100644
--- a/arch/arm/mach-s3c2410/devs.c
+++ b/arch/arm/mach-s3c2410/devs.c
@@ -47,7 +47,7 @@ struct platform_device *s3c24xx_uart_devs[3];
static struct resource s3c_usb_resource[] = {
[0] = {
.start = S3C2410_PA_USBHOST,
- .end = S3C2410_PA_USBHOST + S3C24XX_SZ_USBHOST,
+ .end = S3C2410_PA_USBHOST + S3C24XX_SZ_USBHOST - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -77,7 +77,7 @@ EXPORT_SYMBOL(s3c_device_usb);
static struct resource s3c_lcd_resource[] = {
[0] = {
.start = S3C2410_PA_LCD,
- .end = S3C2410_PA_LCD + S3C24XX_SZ_LCD,
+ .end = S3C2410_PA_LCD + S3C24XX_SZ_LCD - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -103,21 +103,25 @@ struct platform_device s3c_device_lcd = {
EXPORT_SYMBOL(s3c_device_lcd);
-static struct s3c2410fb_mach_info s3c2410fb_info;
-
-void __init set_s3c2410fb_info(struct s3c2410fb_mach_info *hard_s3c2410fb_info)
+void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)
{
- memcpy(&s3c2410fb_info,hard_s3c2410fb_info,sizeof(struct s3c2410fb_mach_info));
- s3c_device_lcd.dev.platform_data = &s3c2410fb_info;
+ struct s3c2410fb_mach_info *npd;
+
+ npd = kmalloc(sizeof(*npd), GFP_KERNEL);
+ if (npd) {
+ memcpy(npd, pd, sizeof(*npd));
+ s3c_device_lcd.dev.platform_data = npd;
+ } else {
+ printk(KERN_ERR "no memory for LCD platform data\n");
+ }
}
-EXPORT_SYMBOL(set_s3c2410fb_info);
/* NAND Controller */
static struct resource s3c_nand_resource[] = {
[0] = {
.start = S3C2410_PA_NAND,
- .end = S3C2410_PA_NAND + S3C24XX_SZ_NAND,
+ .end = S3C2410_PA_NAND + S3C24XX_SZ_NAND - 1,
.flags = IORESOURCE_MEM,
}
};
@@ -136,7 +140,7 @@ EXPORT_SYMBOL(s3c_device_nand);
static struct resource s3c_usbgadget_resource[] = {
[0] = {
.start = S3C2410_PA_USBDEV,
- .end = S3C2410_PA_USBDEV + S3C24XX_SZ_USBDEV,
+ .end = S3C2410_PA_USBDEV + S3C24XX_SZ_USBDEV - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -161,7 +165,7 @@ EXPORT_SYMBOL(s3c_device_usbgadget);
static struct resource s3c_wdt_resource[] = {
[0] = {
.start = S3C2410_PA_WATCHDOG,
- .end = S3C2410_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG,
+ .end = S3C2410_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -186,7 +190,7 @@ EXPORT_SYMBOL(s3c_device_wdt);
static struct resource s3c_i2c_resource[] = {
[0] = {
.start = S3C2410_PA_IIC,
- .end = S3C2410_PA_IIC + S3C24XX_SZ_IIC,
+ .end = S3C2410_PA_IIC + S3C24XX_SZ_IIC - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -211,7 +215,7 @@ EXPORT_SYMBOL(s3c_device_i2c);
static struct resource s3c_iis_resource[] = {
[0] = {
.start = S3C2410_PA_IIS,
- .end = S3C2410_PA_IIS + S3C24XX_SZ_IIS,
+ .end = S3C2410_PA_IIS + S3C24XX_SZ_IIS -1,
.flags = IORESOURCE_MEM,
}
};
@@ -265,7 +269,7 @@ EXPORT_SYMBOL(s3c_device_rtc);
static struct resource s3c_adc_resource[] = {
[0] = {
.start = S3C2410_PA_ADC,
- .end = S3C2410_PA_ADC + S3C24XX_SZ_ADC,
+ .end = S3C2410_PA_ADC + S3C24XX_SZ_ADC - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -288,7 +292,7 @@ struct platform_device s3c_device_adc = {
static struct resource s3c_sdi_resource[] = {
[0] = {
.start = S3C2410_PA_SDI,
- .end = S3C2410_PA_SDI + S3C24XX_SZ_SDI,
+ .end = S3C2410_PA_SDI + S3C24XX_SZ_SDI - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -465,7 +469,7 @@ EXPORT_SYMBOL(s3c_device_timer3);
static struct resource s3c_camif_resource[] = {
[0] = {
.start = S3C2440_PA_CAMIF,
- .end = S3C2440_PA_CAMIF + S3C2440_SZ_CAMIF,
+ .end = S3C2440_PA_CAMIF + S3C2440_SZ_CAMIF - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
index 94f1776cf312..23ea3d5fa09c 100644
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -30,6 +30,7 @@
* 04-Oct-2004 BJD Added irq filter controls for GPIO
* 05-Nov-2004 BJD EXPORT_SYMBOL() added for all code
* 13-Mar-2005 BJD Updates for __iomem
+ * 26-Oct-2005 BJD Added generic configuration types
*/
@@ -58,6 +59,27 @@ void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;
}
+ switch (function) {
+ case S3C2410_GPIO_LEAVE:
+ mask = 0;
+ function = 0;
+ break;
+
+ case S3C2410_GPIO_INPUT:
+ case S3C2410_GPIO_OUTPUT:
+ case S3C2410_GPIO_SFN2:
+ case S3C2410_GPIO_SFN3:
+ if (pin < S3C2410_GPIO_BANKB) {
+ function &= 1;
+ function <<= S3C2410_GPIO_OFFSET(pin);
+ } else {
+ function &= 3;
+ function <<= S3C2410_GPIO_OFFSET(pin)*2;
+ }
+ }
+
+ /* modify the specified register wwith IRQs off */
+
local_irq_save(flags);
con = __raw_readl(base + 0x00);
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 7b51bfd0ba6d..c1b5c63ec24a 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -32,6 +32,7 @@
* 25-Jul-2005 BJD Removed ASIX static mappings
* 27-Jul-2005 BJD Ensure maximum frequency of i2c bus
* 20-Sep-2005 BJD Added static to non-exported items
+ * 26-Oct-2005 BJD Added FB platform data
*/
#include
@@ -61,8 +62,10 @@
#include
#include
#include
+
#include
#include
+#include
#include
#include
@@ -399,6 +402,38 @@ static struct s3c2410_platform_i2c bast_i2c_info = {
.max_freq = 130*1000,
};
+
+static struct s3c2410fb_mach_info __initdata bast_lcd_info = {
+ .width = 640,
+ .height = 480,
+
+ .xres = {
+ .min = 320,
+ .max = 1024,
+ .defval = 640,
+ },
+
+ .yres = {
+ .min = 240,
+ .max = 600,
+ .defval = 480,
+ },
+
+ .bpp = {
+ .min = 4,
+ .max = 16,
+ .defval = 8,
+ },
+
+ .regs = {
+ .lcdcon1 = 0x00000176,
+ .lcdcon2 = 0x1d77c7c2,
+ .lcdcon3 = 0x013a7f13,
+ .lcdcon4 = 0x00000057,
+ .lcdcon5 = 0x00014b02,
+ }
+};
+
/* Standard BAST devices */
static struct platform_device *bast_devices[] __initdata = {
@@ -454,6 +489,10 @@ static void __init bast_map_io(void)
usb_simtec_init();
}
+static void __init bast_init(void)
+{
+ s3c24xx_fb_set_platdata(&bast_lcd_info);
+}
MACHINE_START(BAST, "Simtec-BAST")
/* Maintainer: Ben Dooks */
@@ -463,5 +502,6 @@ MACHINE_START(BAST, "Simtec-BAST")
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = bast_map_io,
.init_irq = s3c24xx_init_irq,
+ .init_machine = bast_init,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index fb3cb01266e5..7efeaaad2361 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -25,6 +25,7 @@
* 14-Jan-2005 BJD Added clock init
* 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
* 20-Sep-2005 BJD Added static to non-exported items
+ * 26-Oct-2005 BJD Changed name of fb init call
*/
#include
@@ -164,7 +165,7 @@ static void __init h1940_init_irq(void)
static void __init h1940_init(void)
{
- set_s3c2410fb_info(&h1940_lcdcfg);
+ s3c24xx_fb_set_platdata(&h1940_lcdcfg);
}
MACHINE_START(H1940, "IPAQ-H1940")
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
index 722ef46b630a..6950e61b7914 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -19,6 +19,7 @@
* 10-Mar-2005 LCVR Replaced S3C2410_VA by S3C24XX_VA
* 14-Mar-2005 BJD void __iomem fixes
* 20-Sep-2005 BJD Added static to non-exported items
+ * 26-Oct-2005 BJD Added framebuffer data
*/
#include
@@ -41,7 +42,10 @@
//#include
#include
#include
+#include
+
#include
+#include
#include "s3c2410.h"
#include "s3c2440.h"
@@ -86,6 +90,70 @@ static struct s3c2410_uartcfg smdk2440_uartcfgs[] = {
}
};
+/* LCD driver info */
+
+static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {
+ .regs = {
+
+ .lcdcon1 = S3C2410_LCDCON1_TFT16BPP |
+ S3C2410_LCDCON1_TFT |
+ S3C2410_LCDCON1_CLKVAL(0x04),
+
+ .lcdcon2 = S3C2410_LCDCON2_VBPD(7) |
+ S3C2410_LCDCON2_LINEVAL(319) |
+ S3C2410_LCDCON2_VFPD(6) |
+ S3C2410_LCDCON2_VSPW(3),
+
+ .lcdcon3 = S3C2410_LCDCON3_HBPD(19) |
+ S3C2410_LCDCON3_HOZVAL(239) |
+ S3C2410_LCDCON3_HFPD(7),
+
+ .lcdcon4 = S3C2410_LCDCON4_MVAL(0) |
+ S3C2410_LCDCON4_HSPW(3),
+
+ .lcdcon5 = S3C2410_LCDCON5_FRM565 |
+ S3C2410_LCDCON5_INVVLINE |
+ S3C2410_LCDCON5_INVVFRAME |
+ S3C2410_LCDCON5_PWREN |
+ S3C2410_LCDCON5_HWSWP,
+ },
+
+#if 0
+ /* currently setup by downloader */
+ .gpccon = 0xaa940659,
+ .gpccon_mask = 0xffffffff,
+ .gpcup = 0x0000ffff,
+ .gpcup_mask = 0xffffffff,
+ .gpdcon = 0xaa84aaa0,
+ .gpdcon_mask = 0xffffffff,
+ .gpdup = 0x0000faff,
+ .gpdup_mask = 0xffffffff,
+#endif
+
+ .lpcsel = ((0xCE6) & ~7) | 1<<4,
+
+ .width = 240,
+ .height = 320,
+
+ .xres = {
+ .min = 240,
+ .max = 240,
+ .defval = 240,
+ },
+
+ .yres = {
+ .min = 320,
+ .max = 320,
+ .defval = 320,
+ },
+
+ .bpp = {
+ .min = 16,
+ .max = 16,
+ .defval = 16,
+ },
+};
+
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
@@ -121,6 +189,8 @@ static void __init smdk2440_machine_init(void)
s3c2410_gpio_setpin(S3C2410_GPF6, 0);
s3c2410_gpio_setpin(S3C2410_GPF7, 0);
+ s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);
+
s3c2410_pm_init();
}
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index 24687f511bf5..75efb5da5b6d 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -388,9 +388,17 @@ static struct sa1100_port_fns assabet_port_fns __initdata = {
};
static struct map_desc assabet_io_desc[] __initdata = {
- /* virtual physical length type */
- { 0xf1000000, 0x12000000, 0x00100000, MT_DEVICE }, /* Board Control Register */
- { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE } /* MQ200 */
+ { /* Board Control Register */
+ .virtual = 0xf1000000,
+ .pfn = __phys_to_pfn(0x12000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* MQ200 */
+ .virtual = 0xf2800000,
+ .pfn = __phys_to_pfn(0x4b800000),
+ .length = 0x00800000,
+ .type = MT_DEVICE
+ }
};
static void __init assabet_map_io(void)
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index b6169cb09196..c92cebff7f8e 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -254,10 +254,22 @@ EXPORT_SYMBOL(badge4_set_5V);
static struct map_desc badge4_io_desc[] __initdata = {
- /* virtual physical length type */
- {0xf1000000, 0x08000000, 0x00100000, MT_DEVICE },/* SRAM bank 1 */
- {0xf2000000, 0x10000000, 0x00100000, MT_DEVICE },/* SRAM bank 2 */
- {0xf4000000, 0x48000000, 0x00100000, MT_DEVICE } /* SA-1111 */
+ { /* SRAM bank 1 */
+ .virtual = 0xf1000000,
+ .pfn = __phys_to_pfn(0x08000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* SRAM bank 2 */
+ .virtual = 0xf2000000,
+ .pfn = __phys_to_pfn(0x10000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* SA-1111 */
+ .virtual = 0xf4000000,
+ .pfn = __phys_to_pfn(0x48000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
};
static void
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index 9484be7dc671..23cb74885275 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -100,8 +100,12 @@ static void __init cerf_init_irq(void)
}
static struct map_desc cerf_io_desc[] __initdata = {
- /* virtual physical length type */
- { 0xf0000000, 0x08000000, 0x00100000, MT_DEVICE } /* Crystal Ethernet Chip */
+ { /* Crystal Ethernet Chip */
+ .virtual = 0xf0000000,
+ .pfn = __phys_to_pfn(0x08000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
};
static void __init cerf_map_io(void)
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 6ecab7e2c238..7fd6e29c36b7 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -171,9 +171,17 @@ static void __init collie_init(void)
}
static struct map_desc collie_io_desc[] __initdata = {
- /* virtual physical length type */
- {0xe8000000, 0x00000000, 0x02000000, MT_DEVICE}, /* 32M main flash (cs0) */
- {0xea000000, 0x08000000, 0x02000000, MT_DEVICE}, /* 32M boot flash (cs1) */
+ { /* 32M main flash (cs0) */
+ .virtual = 0xe8000000,
+ .pfn = __phys_to_pfn(0x00000000),
+ .length = 0x02000000,
+ .type = MT_DEVICE
+ }, { /* 32M boot flash (cs1) */
+ .virtual = 0xea000000,
+ .pfn = __phys_to_pfn(0x08000000),
+ .length = 0x02000000,
+ .type = MT_DEVICE
+ }
};
static void __init collie_map_io(void)
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 3f1e358455e5..93619497779c 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -369,11 +369,27 @@ EXPORT_SYMBOL(sa1100fb_lcd_power);
*/
static struct map_desc standard_io_desc[] __initdata = {
- /* virtual physical length type */
- { 0xf8000000, 0x80000000, 0x00100000, MT_DEVICE }, /* PCM */
- { 0xfa000000, 0x90000000, 0x00100000, MT_DEVICE }, /* SCM */
- { 0xfc000000, 0xa0000000, 0x00100000, MT_DEVICE }, /* MER */
- { 0xfe000000, 0xb0000000, 0x00200000, MT_DEVICE } /* LCD + DMA */
+ { /* PCM */
+ .virtual = 0xf8000000,
+ .pfn = __phys_to_pfn(0x80000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* SCM */
+ .virtual = 0xfa000000,
+ .pfn = __phys_to_pfn(0x90000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* MER */
+ .virtual = 0xfc000000,
+ .pfn = __phys_to_pfn(0xa0000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* LCD + DMA */
+ .virtual = 0xfe000000,
+ .pfn = __phys_to_pfn(0xb0000000),
+ .length = 0x00200000,
+ .type = MT_DEVICE
+ },
};
void __init sa1100_map_io(void)
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index e7aa2681ca64..e8352b7f74b0 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -223,10 +223,22 @@ static void h3xxx_lcd_power(int enable)
}
static struct map_desc h3600_io_desc[] __initdata = {
- /* virtual physical length type */
- { H3600_BANK_2_VIRT, SA1100_CS2_PHYS, 0x02800000, MT_DEVICE }, /* static memory bank 2 CS#2 */
- { H3600_BANK_4_VIRT, SA1100_CS4_PHYS, 0x00800000, MT_DEVICE }, /* static memory bank 4 CS#4 */
- { H3600_EGPIO_VIRT, H3600_EGPIO_PHYS, 0x01000000, MT_DEVICE }, /* EGPIO 0 CS#5 */
+ { /* static memory bank 2 CS#2 */
+ .virtual = H3600_BANK_2_VIRT,
+ .pfn = __phys_to_pfn(SA1100_CS2_PHYS),
+ .length = 0x02800000,
+ .type = MT_DEVICE
+ }, { /* static memory bank 4 CS#4 */
+ .virtual = H3600_BANK_4_VIRT,
+ .pfn = __phys_to_pfn(SA1100_CS4_PHYS),
+ .length = 0x00800000,
+ .type = MT_DEVICE
+ }, { /* EGPIO 0 CS#5 */
+ .virtual = H3600_EGPIO_VIRT,
+ .pfn = __phys_to_pfn(H3600_EGPIO_PHYS),
+ .length = 0x01000000,
+ .type = MT_DEVICE
+ }
};
/*
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index 502d65cfe654..c922e043c424 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -57,8 +57,12 @@ static void hackkit_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
*/
static struct map_desc hackkit_io_desc[] __initdata = {
- /* virtual physical length type */
- { 0xe8000000, 0x00000000, 0x01000000, MT_DEVICE } /* Flash bank 0 */
+ { /* Flash bank 0 */
+ .virtual = 0xe8000000,
+ .pfn = __phys_to_pfn(0x00000000),
+ .length = 0x01000000,
+ .type = MT_DEVICE
+ },
};
static struct sa1100_port_fns hackkit_port_fns __initdata = {
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index 2f497112c96a..9c363bfcf310 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -81,10 +81,22 @@ static int __init jornada720_init(void)
arch_initcall(jornada720_init);
static struct map_desc jornada720_io_desc[] __initdata = {
- /* virtual physical length type */
- { 0xf0000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Epson registers */
- { 0xf1000000, 0x48200000, 0x00100000, MT_DEVICE }, /* Epson frame buffer */
- { 0xf4000000, 0x40000000, 0x00100000, MT_DEVICE } /* SA-1111 */
+ { /* Epson registers */
+ .virtual = 0xf0000000,
+ .pfn = __phys_to_pfn(0x48000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* Epson frame buffer */
+ .virtual = 0xf1000000,
+ .pfn = __phys_to_pfn(0x48200000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }, { /* SA-1111 */
+ .virtual = 0xf4000000,
+ .pfn = __phys_to_pfn(0x40000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ }
};
static void __init jornada720_map_io(void)
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index ed6744d480af..8c9e3dd52942 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -31,9 +31,17 @@ static void __init lart_init(void)
}
static struct map_desc lart_io_desc[] __initdata = {
- /* virtual physical length type */
- { 0xe8000000, 0x00000000, 0x00400000, MT_DEVICE }, /* main flash memory */
- { 0xec000000, 0x08000000, 0x00400000, MT_DEVICE } /* main flash, alternative location */
+ { /* main flash memory */
+ .virtual = 0xe8000000,
+ .pfn = __phys_to_pfn(0x00000000),
+ .length = 0x00400000,
+ .type = MT_DEVICE
+ }, { /* main flash, alternative location */
+ .virtual = 0xec000000,
+ .pfn = __phys_to_pfn(0x08000000),
+ .length = 0x00400000,
+ .type = MT_DEVICE
+ }
};
static void __init lart_map_io(void)
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 7609d69cf1cc..052e4caedb89 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -325,9 +325,17 @@ static int __init neponset_init(void)
subsys_initcall(neponset_init);
static struct map_desc neponset_io_desc[] __initdata = {
- /* virtual physical length type */
- { 0xf3000000, 0x10000000, SZ_1M, MT_DEVICE }, /* System Registers */
- { 0xf4000000, 0x40000000, SZ_1M, MT_DEVICE } /* SA-1111 */
+ { /* System Registers */
+ .virtual = 0xf3000000,
+ .pfn = __phys_to_pfn(0x10000000),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ }, { /* SA-1111 */
+ .virtual = 0xf4000000,
+ .pfn = __phys_to_pfn(0x40000000),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ }
};
void __init neponset_map_io(void)
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 07f6d5fd7bb0..cfb6658e5cdf 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -60,11 +60,17 @@ EXPORT_SYMBOL(set_cs3_bit);
EXPORT_SYMBOL(clear_cs3_bit);
static struct map_desc simpad_io_desc[] __initdata = {
- /* virtual physical length type */
- /* MQ200 */
- { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE },
- /* Paules CS3, write only */
- { 0xf1000000, 0x18000000, 0x00100000, MT_DEVICE },
+ { /* MQ200 */
+ .virtual = 0xf2800000,
+ .pfn = __phys_to_pfn(0x4b800000),
+ .length = 0x00800000,
+ .type = MT_DEVICE
+ }, { /* Paules CS3, write only */
+ .virtual = 0xf1000000,
+ .pfn = __phys_to_pfn(0x18000000),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ },
};
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 946c0d11c73b..2d428b6dbb58 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -62,7 +62,12 @@ arch_initcall(shark_init);
extern void shark_init_irq(void);
static struct map_desc shark_io_desc[] __initdata = {
- { IO_BASE , IO_START , IO_SIZE , MT_DEVICE }
+ {
+ .virtual = IO_BASE,
+ .pfn = __phys_to_pfn(IO_START),
+ .length = IO_SIZE,
+ .type = MT_DEVICE
+ }
};
static void __init shark_map_io(void)
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index a30e0451df72..7e4bdd07f4af 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -186,25 +186,82 @@ void __init versatile_init_irq(void)
}
static struct map_desc versatile_io_desc[] __initdata = {
- { IO_ADDRESS(VERSATILE_SYS_BASE), VERSATILE_SYS_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(VERSATILE_SIC_BASE), VERSATILE_SIC_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(VERSATILE_VIC_BASE), VERSATILE_VIC_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(VERSATILE_SCTL_BASE), VERSATILE_SCTL_BASE, SZ_4K * 9, MT_DEVICE },
+ {
+ .virtual = IO_ADDRESS(VERSATILE_SYS_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_SYS_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(VERSATILE_SIC_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_SIC_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(VERSATILE_VIC_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_VIC_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(VERSATILE_SCTL_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_SCTL_BASE),
+ .length = SZ_4K * 9,
+ .type = MT_DEVICE
+ },
#ifdef CONFIG_MACH_VERSATILE_AB
- { IO_ADDRESS(VERSATILE_GPIO0_BASE), VERSATILE_GPIO0_BASE, SZ_4K, MT_DEVICE },
- { IO_ADDRESS(VERSATILE_IB2_BASE), VERSATILE_IB2_BASE, SZ_64M, MT_DEVICE },
+ {
+ .virtual = IO_ADDRESS(VERSATILE_GPIO0_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_GPIO0_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = IO_ADDRESS(VERSATILE_IB2_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_IB2_BASE),
+ .length = SZ_64M,
+ .type = MT_DEVICE
+ },
#endif
#ifdef CONFIG_DEBUG_LL
- { IO_ADDRESS(VERSATILE_UART0_BASE), VERSATILE_UART0_BASE, SZ_4K, MT_DEVICE },
+ {
+ .virtual = IO_ADDRESS(VERSATILE_UART0_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_UART0_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ },
#endif
#ifdef CONFIG_PCI
- { IO_ADDRESS(VERSATILE_PCI_CORE_BASE), VERSATILE_PCI_CORE_BASE, SZ_4K, MT_DEVICE },
- { VERSATILE_PCI_VIRT_BASE, VERSATILE_PCI_BASE, VERSATILE_PCI_BASE_SIZE, MT_DEVICE },
- { VERSATILE_PCI_CFG_VIRT_BASE, VERSATILE_PCI_CFG_BASE, VERSATILE_PCI_CFG_BASE_SIZE, MT_DEVICE },
+ {
+ .virtual = IO_ADDRESS(VERSATILE_PCI_CORE_BASE),
+ .pfn = __phys_to_pfn(VERSATILE_PCI_CORE_BASE),
+ .length = SZ_4K,
+ .type = MT_DEVICE
+ }, {
+ .virtual = VERSATILE_PCI_VIRT_BASE,
+ .pfn = __phys_to_pfn(VERSATILE_PCI_BASE),
+ .length = VERSATILE_PCI_BASE_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = VERSATILE_PCI_CFG_VIRT_BASE,
+ .pfn = __phys_to_pfn(VERSATILE_PCI_CFG_BASE),
+ .length = VERSATILE_PCI_CFG_BASE_SIZE,
+ .type = MT_DEVICE
+ },
#if 0
- { VERSATILE_PCI_VIRT_MEM_BASE0, VERSATILE_PCI_MEM_BASE0, SZ_16M, MT_DEVICE },
- { VERSATILE_PCI_VIRT_MEM_BASE1, VERSATILE_PCI_MEM_BASE1, SZ_16M, MT_DEVICE },
- { VERSATILE_PCI_VIRT_MEM_BASE2, VERSATILE_PCI_MEM_BASE2, SZ_16M, MT_DEVICE },
+ {
+ .virtual = VERSATILE_PCI_VIRT_MEM_BASE0,
+ .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE0),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = VERSATILE_PCI_VIRT_MEM_BASE1,
+ .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE1),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = VERSATILE_PCI_VIRT_MEM_BASE2,
+ .pfn = __phys_to_pfn(VERSATILE_PCI_MEM_BASE2),
+ .length = SZ_16M,
+ .type = MT_DEVICE
+ },
#endif
#endif
};
diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
index 26356ce4da54..82f4d5e27c54 100644
--- a/arch/arm/mm/consistent.c
+++ b/arch/arm/mm/consistent.c
@@ -75,7 +75,7 @@ static struct vm_region consistent_head = {
};
static struct vm_region *
-vm_region_alloc(struct vm_region *head, size_t size, int gfp)
+vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp)
{
unsigned long addr = head->vm_start, end = head->vm_end - size;
unsigned long flags;
@@ -133,7 +133,7 @@ static struct vm_region *vm_region_find(struct vm_region *head, unsigned long ad
#endif
static void *
-__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
+__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
pgprot_t prot)
{
struct page *page;
@@ -251,7 +251,7 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
* virtual and bus address for that space.
*/
void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
return __dma_alloc(dev, size, handle, gfp,
pgprot_noncached(pgprot_kernel));
@@ -263,7 +263,7 @@ EXPORT_SYMBOL(dma_alloc_coherent);
* dma_alloc_coherent above.
*/
void *
-dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
+dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
return __dma_alloc(dev, size, handle, gfp,
pgprot_writecombine(pgprot_kernel));
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index edffa47a4b2a..f4496813615a 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/mm/init.c
*
- * Copyright (C) 1995-2002 Russell King
+ * Copyright (C) 1995-2005 Russell King
*
* 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
@@ -86,14 +86,19 @@ void show_mem(void)
printk("%d pages swap cached\n", cached);
}
-struct node_info {
- unsigned int start;
- unsigned int end;
- int bootmap_pages;
-};
+static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
+{
+ return pmd_offset(pgd, virt);
+}
-#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT)
-#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT)
+static inline pmd_t *pmd_off_k(unsigned long virt)
+{
+ return pmd_off(pgd_offset_k(virt), virt);
+}
+
+#define for_each_nodebank(iter,mi,no) \
+ for (iter = 0; iter < mi->nr_banks; iter++) \
+ if (mi->bank[iter].node == no)
/*
* FIXME: We really want to avoid allocating the bootmap bitmap
@@ -106,15 +111,12 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
{
unsigned int start_pfn, bank, bootmap_pfn;
- start_pfn = O_PFN_UP(__pa(&_end));
+ start_pfn = PAGE_ALIGN(__pa(&_end)) >> PAGE_SHIFT;
bootmap_pfn = 0;
- for (bank = 0; bank < mi->nr_banks; bank ++) {
+ for_each_nodebank(bank, mi, node) {
unsigned int start, end;
- if (mi->bank[bank].node != node)
- continue;
-
start = mi->bank[bank].start >> PAGE_SHIFT;
end = (mi->bank[bank].size +
mi->bank[bank].start) >> PAGE_SHIFT;
@@ -140,92 +142,6 @@ find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
return bootmap_pfn;
}
-/*
- * Scan the memory info structure and pull out:
- * - the end of memory
- * - the number of nodes
- * - the pfn range of each node
- * - the number of bootmem bitmap pages
- */
-static unsigned int __init
-find_memend_and_nodes(struct meminfo *mi, struct node_info *np)
-{
- unsigned int i, bootmem_pages = 0, memend_pfn = 0;
-
- for (i = 0; i < MAX_NUMNODES; i++) {
- np[i].start = -1U;
- np[i].end = 0;
- np[i].bootmap_pages = 0;
- }
-
- for (i = 0; i < mi->nr_banks; i++) {
- unsigned long start, end;
- int node;
-
- if (mi->bank[i].size == 0) {
- /*
- * Mark this bank with an invalid node number
- */
- mi->bank[i].node = -1;
- continue;
- }
-
- node = mi->bank[i].node;
-
- /*
- * Make sure we haven't exceeded the maximum number of nodes
- * that we have in this configuration. If we have, we're in
- * trouble. (maybe we ought to limit, instead of bugging?)
- */
- if (node >= MAX_NUMNODES)
- BUG();
- node_set_online(node);
-
- /*
- * Get the start and end pfns for this bank
- */
- start = mi->bank[i].start >> PAGE_SHIFT;
- end = (mi->bank[i].start + mi->bank[i].size) >> PAGE_SHIFT;
-
- if (np[node].start > start)
- np[node].start = start;
-
- if (np[node].end < end)
- np[node].end = end;
-
- if (memend_pfn < end)
- memend_pfn = end;
- }
-
- /*
- * Calculate the number of pages we require to
- * store the bootmem bitmaps.
- */
- for_each_online_node(i) {
- if (np[i].end == 0)
- continue;
-
- np[i].bootmap_pages = bootmem_bootmap_pages(np[i].end -
- np[i].start);
- bootmem_pages += np[i].bootmap_pages;
- }
-
- high_memory = __va(memend_pfn << PAGE_SHIFT);
-
- /*
- * This doesn't seem to be used by the Linux memory
- * manager any more. If we can get rid of it, we
- * also get rid of some of the stuff above as well.
- *
- * Note: max_low_pfn and max_pfn reflect the number
- * of _pages_ in the system, not the maximum PFN.
- */
- max_low_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET);
- max_pfn = memend_pfn - O_PFN_DOWN(PHYS_OFFSET);
-
- return bootmem_pages;
-}
-
static int __init check_initrd(struct meminfo *mi)
{
int initrd_node = -2;
@@ -266,9 +182,8 @@ static int __init check_initrd(struct meminfo *mi)
/*
* Reserve the various regions of node 0
*/
-static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int bootmap_pages)
+static __init void reserve_node_zero(pg_data_t *pgdat)
{
- pg_data_t *pgdat = NODE_DATA(0);
unsigned long res_size = 0;
/*
@@ -288,13 +203,6 @@ static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int boot
reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
PTRS_PER_PGD * sizeof(pgd_t));
- /*
- * And don't forget to reserve the allocator bitmap,
- * which will be freed later.
- */
- reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT,
- bootmap_pages << PAGE_SHIFT);
-
/*
* Hmm... This should go elsewhere, but we really really need to
* stop things allocating the low memory; ideally we need a better
@@ -324,93 +232,256 @@ static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int boot
reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
}
-/*
- * Register all available RAM in this node with the bootmem allocator.
- */
-static inline void free_bootmem_node_bank(int node, struct meminfo *mi)
+void __init build_mem_type_table(void);
+void __init create_mapping(struct map_desc *md);
+
+static unsigned long __init
+bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
{
- pg_data_t *pgdat = NODE_DATA(node);
- int bank;
+ unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
+ unsigned long start_pfn, end_pfn, boot_pfn;
+ unsigned int boot_pages;
+ pg_data_t *pgdat;
+ int i;
- for (bank = 0; bank < mi->nr_banks; bank++)
- if (mi->bank[bank].node == node)
- free_bootmem_node(pgdat, mi->bank[bank].start,
- mi->bank[bank].size);
-}
-
-/*
- * Initialise the bootmem allocator for all nodes. This is called
- * early during the architecture specific initialisation.
- */
-static void __init bootmem_init(struct meminfo *mi)
-{
- struct node_info node_info[MAX_NUMNODES], *np = node_info;
- unsigned int bootmap_pages, bootmap_pfn, map_pg;
- int node, initrd_node;
-
- bootmap_pages = find_memend_and_nodes(mi, np);
- bootmap_pfn = find_bootmap_pfn(0, mi, bootmap_pages);
- initrd_node = check_initrd(mi);
-
- map_pg = bootmap_pfn;
+ start_pfn = -1UL;
+ end_pfn = 0;
/*
- * Initialise the bootmem nodes.
- *
- * What we really want to do is:
- *
- * unmap_all_regions_except_kernel();
- * for_each_node_in_reverse_order(node) {
- * map_node(node);
- * allocate_bootmem_map(node);
- * init_bootmem_node(node);
- * free_bootmem_node(node);
- * }
- *
- * but this is a 2.5-type change. For now, we just set
- * the nodes up in reverse order.
- *
- * (we could also do with rolling bootmem_init and paging_init
- * into one generic "memory_init" type function).
+ * Calculate the pfn range, and map the memory banks for this node.
*/
- np += num_online_nodes() - 1;
- for (node = num_online_nodes() - 1; node >= 0; node--, np--) {
- /*
- * If there are no pages in this node, ignore it.
- * Note that node 0 must always have some pages.
- */
- if (np->end == 0 || !node_online(node)) {
- if (node == 0)
- BUG();
- continue;
- }
+ for_each_nodebank(i, mi, node) {
+ unsigned long start, end;
+ struct map_desc map;
- /*
- * Initialise the bootmem allocator.
- */
- init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end);
- free_bootmem_node_bank(node, mi);
- map_pg += np->bootmap_pages;
+ start = mi->bank[i].start >> PAGE_SHIFT;
+ end = (mi->bank[i].start + mi->bank[i].size) >> PAGE_SHIFT;
- /*
- * If this is node 0, we need to reserve some areas ASAP -
- * we may use bootmem on node 0 to setup the other nodes.
- */
- if (node == 0)
- reserve_node_zero(bootmap_pfn, bootmap_pages);
+ if (start_pfn > start)
+ start_pfn = start;
+ if (end_pfn < end)
+ end_pfn = end;
+
+ map.pfn = __phys_to_pfn(mi->bank[i].start);
+ map.virtual = __phys_to_virt(mi->bank[i].start);
+ map.length = mi->bank[i].size;
+ map.type = MT_MEMORY;
+
+ create_mapping(&map);
}
+ /*
+ * If there is no memory in this node, ignore it.
+ */
+ if (end_pfn == 0)
+ return end_pfn;
+
+ /*
+ * Allocate the bootmem bitmap page.
+ */
+ boot_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
+ boot_pfn = find_bootmap_pfn(node, mi, boot_pages);
+
+ /*
+ * Initialise the bootmem allocator for this node, handing the
+ * memory banks over to bootmem.
+ */
+ node_set_online(node);
+ pgdat = NODE_DATA(node);
+ init_bootmem_node(pgdat, boot_pfn, start_pfn, end_pfn);
+
+ for_each_nodebank(i, mi, node)
+ free_bootmem_node(pgdat, mi->bank[i].start, mi->bank[i].size);
+
+ /*
+ * Reserve the bootmem bitmap for this node.
+ */
+ reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT,
+ boot_pages << PAGE_SHIFT);
#ifdef CONFIG_BLK_DEV_INITRD
- if (phys_initrd_size && initrd_node >= 0) {
- reserve_bootmem_node(NODE_DATA(initrd_node), phys_initrd_start,
+ /*
+ * If the initrd is in this node, reserve its memory.
+ */
+ if (node == initrd_node) {
+ reserve_bootmem_node(pgdat, phys_initrd_start,
phys_initrd_size);
initrd_start = __phys_to_virt(phys_initrd_start);
initrd_end = initrd_start + phys_initrd_size;
}
#endif
- BUG_ON(map_pg != bootmap_pfn + bootmap_pages);
+ /*
+ * Finally, reserve any node zero regions.
+ */
+ if (node == 0)
+ reserve_node_zero(pgdat);
+
+ /*
+ * initialise the zones within this node.
+ */
+ memset(zone_size, 0, sizeof(zone_size));
+ memset(zhole_size, 0, sizeof(zhole_size));
+
+ /*
+ * The size of this node has already been determined. If we need
+ * to do anything fancy with the allocation of this memory to the
+ * zones, now is the time to do it.
+ */
+ zone_size[0] = end_pfn - start_pfn;
+
+ /*
+ * For each bank in this node, calculate the size of the holes.
+ * holes = node_size - sum(bank_sizes_in_node)
+ */
+ zhole_size[0] = zone_size[0];
+ for_each_nodebank(i, mi, node)
+ zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT;
+
+ /*
+ * Adjust the sizes according to any special requirements for
+ * this machine type.
+ */
+ arch_adjust_zones(node, zone_size, zhole_size);
+
+ free_area_init_node(node, pgdat, zone_size, start_pfn, zhole_size);
+
+ return end_pfn;
+}
+
+static void __init bootmem_init(struct meminfo *mi)
+{
+ unsigned long addr, memend_pfn = 0;
+ int node, initrd_node, i;
+
+ /*
+ * Invalidate the node number for empty or invalid memory banks
+ */
+ for (i = 0; i < mi->nr_banks; i++)
+ if (mi->bank[i].size == 0 || mi->bank[i].node >= MAX_NUMNODES)
+ mi->bank[i].node = -1;
+
+ memcpy(&meminfo, mi, sizeof(meminfo));
+
+#ifdef CONFIG_XIP_KERNEL
+#error needs fixing
+ p->pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & PMD_MASK);
+ p->virtual = (unsigned long)&_stext & PMD_MASK;
+ p->length = ((unsigned long)&_etext - p->virtual + ~PMD_MASK) & PMD_MASK;
+ p->type = MT_ROM;
+ p ++;
+#endif
+
+ /*
+ * Clear out all the mappings below the kernel image.
+ * FIXME: what about XIP?
+ */
+ for (addr = 0; addr < PAGE_OFFSET; addr += PGDIR_SIZE)
+ pmd_clear(pmd_off_k(addr));
+
+ /*
+ * Clear out all the kernel space mappings, except for the first
+ * memory bank, up to the end of the vmalloc region.
+ */
+ for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size);
+ addr < VMALLOC_END; addr += PGDIR_SIZE)
+ pmd_clear(pmd_off_k(addr));
+
+ /*
+ * Locate which node contains the ramdisk image, if any.
+ */
+ initrd_node = check_initrd(mi);
+
+ /*
+ * Run through each node initialising the bootmem allocator.
+ */
+ for_each_node(node) {
+ unsigned long end_pfn;
+
+ end_pfn = bootmem_init_node(node, initrd_node, mi);
+
+ /*
+ * Remember the highest memory PFN.
+ */
+ if (end_pfn > memend_pfn)
+ memend_pfn = end_pfn;
+ }
+
+ high_memory = __va(memend_pfn << PAGE_SHIFT);
+
+ /*
+ * This doesn't seem to be used by the Linux memory manager any
+ * more, but is used by ll_rw_block. If we can get rid of it, we
+ * also get rid of some of the stuff above as well.
+ *
+ * Note: max_low_pfn and max_pfn reflect the number of _pages_ in
+ * the system, not the maximum PFN.
+ */
+ max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET;
+}
+
+/*
+ * Set up device the mappings. Since we clear out the page tables for all
+ * mappings above VMALLOC_END, we will remove any debug device mappings.
+ * This means you have to be careful how you debug this function, or any
+ * called function. (Do it by code inspection!)
+ */
+static void __init devicemaps_init(struct machine_desc *mdesc)
+{
+ struct map_desc map;
+ unsigned long addr;
+ void *vectors;
+
+ for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
+ pmd_clear(pmd_off_k(addr));
+
+ /*
+ * Map the cache flushing regions.
+ */
+#ifdef FLUSH_BASE
+ map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS);
+ map.virtual = FLUSH_BASE;
+ map.length = PGDIR_SIZE;
+ map.type = MT_CACHECLEAN;
+ create_mapping(&map);
+#endif
+#ifdef FLUSH_BASE_MINICACHE
+ map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + PGDIR_SIZE);
+ map.virtual = FLUSH_BASE_MINICACHE;
+ map.length = PGDIR_SIZE;
+ map.type = MT_MINICLEAN;
+ create_mapping(&map);
+#endif
+
+ flush_cache_all();
+ local_flush_tlb_all();
+
+ vectors = alloc_bootmem_low_pages(PAGE_SIZE);
+ BUG_ON(!vectors);
+
+ /*
+ * Create a mapping for the machine vectors at the high-vectors
+ * location (0xffff0000). If we aren't using high-vectors, also
+ * create a mapping at the low-vectors virtual address.
+ */
+ map.pfn = __phys_to_pfn(virt_to_phys(vectors));
+ map.virtual = 0xffff0000;
+ map.length = PAGE_SIZE;
+ map.type = MT_HIGH_VECTORS;
+ create_mapping(&map);
+
+ if (!vectors_high()) {
+ map.virtual = 0;
+ map.type = MT_LOW_VECTORS;
+ create_mapping(&map);
+ }
+
+ /*
+ * Ask the machine support to map in the statically mapped devices.
+ * After this point, we can start to touch devices again.
+ */
+ if (mdesc->map_io)
+ mdesc->map_io();
}
/*
@@ -420,87 +491,17 @@ static void __init bootmem_init(struct meminfo *mi)
void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
{
void *zero_page;
- int node;
+ build_mem_type_table();
bootmem_init(mi);
+ devicemaps_init(mdesc);
- memcpy(&meminfo, mi, sizeof(meminfo));
+ top_pmd = pmd_off_k(0xffff0000);
/*
* allocate the zero page. Note that we count on this going ok.
*/
zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
-
- /*
- * initialise the page tables.
- */
- memtable_init(mi);
- if (mdesc->map_io)
- mdesc->map_io();
- local_flush_tlb_all();
-
- /*
- * initialise the zones within each node
- */
- for_each_online_node(node) {
- unsigned long zone_size[MAX_NR_ZONES];
- unsigned long zhole_size[MAX_NR_ZONES];
- struct bootmem_data *bdata;
- pg_data_t *pgdat;
- int i;
-
- /*
- * Initialise the zone size information.
- */
- for (i = 0; i < MAX_NR_ZONES; i++) {
- zone_size[i] = 0;
- zhole_size[i] = 0;
- }
-
- pgdat = NODE_DATA(node);
- bdata = pgdat->bdata;
-
- /*
- * The size of this node has already been determined.
- * If we need to do anything fancy with the allocation
- * of this memory to the zones, now is the time to do
- * it.
- */
- zone_size[0] = bdata->node_low_pfn -
- (bdata->node_boot_start >> PAGE_SHIFT);
-
- /*
- * If this zone has zero size, skip it.
- */
- if (!zone_size[0])
- continue;
-
- /*
- * For each bank in this node, calculate the size of the
- * holes. holes = node_size - sum(bank_sizes_in_node)
- */
- zhole_size[0] = zone_size[0];
- for (i = 0; i < mi->nr_banks; i++) {
- if (mi->bank[i].node != node)
- continue;
-
- zhole_size[0] -= mi->bank[i].size >> PAGE_SHIFT;
- }
-
- /*
- * Adjust the sizes according to any special
- * requirements for this machine type.
- */
- arch_adjust_zones(node, zone_size, zhole_size);
-
- free_area_init_node(node, pgdat, zone_size,
- bdata->node_boot_start >> PAGE_SHIFT, zhole_size);
- }
-
- /*
- * finish off the bad pages once
- * the mem_map is initialised
- */
memzero(zero_page, PAGE_SIZE);
empty_zero_page = virt_to_page(zero_page);
flush_dcache_page(empty_zero_page);
@@ -562,10 +563,7 @@ static void __init free_unused_memmap_node(int node, struct meminfo *mi)
* may not be the case, especially if the user has provided the
* information on the command line.
*/
- for (i = 0; i < mi->nr_banks; i++) {
- if (mi->bank[i].size == 0 || mi->bank[i].node != node)
- continue;
-
+ for_each_nodebank(i, mi, node) {
bank_start = mi->bank[i].start >> PAGE_SHIFT;
if (bank_start < prev_bank_end) {
printk(KERN_ERR "MEM: unordered memory banks. "
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 7110e54182b1..6fb1258df1b5 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -26,6 +26,7 @@
#include
#include
+#include
#include
#include
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index d125a3dc061c..61bc2fa0511e 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/mm/mm-armv.c
*
- * Copyright (C) 1998-2002 Russell King
+ * Copyright (C) 1998-2005 Russell King
*
* 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
@@ -305,16 +305,6 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg
set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
}
-/*
- * Clear any PGD mapping. On a two-level page table system,
- * the clearance is done by the middle-level functions (pmd)
- * rather than the top-level (pgd) functions.
- */
-static inline void clear_mapping(unsigned long virt)
-{
- pmd_clear(pmd_off_k(virt));
-}
-
struct mem_types {
unsigned int prot_pte;
unsigned int prot_l1;
@@ -373,7 +363,7 @@ static struct mem_types mem_types[] __initdata = {
/*
* Adjust the PMD section entries according to the CPU in use.
*/
-static void __init build_mem_type_table(void)
+void __init build_mem_type_table(void)
{
struct cachepolicy *cp;
unsigned int cr = get_cr();
@@ -483,25 +473,25 @@ static void __init build_mem_type_table(void)
* offsets, and we take full advantage of sections and
* supersections.
*/
-static void __init create_mapping(struct map_desc *md)
+void __init create_mapping(struct map_desc *md)
{
unsigned long virt, length;
int prot_sect, prot_l1, domain;
pgprot_t prot_pte;
- long off;
+ unsigned long off = (u32)__pfn_to_phys(md->pfn);
if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
printk(KERN_WARNING "BUG: not creating mapping for "
- "0x%08lx at 0x%08lx in user region\n",
- md->physical, md->virtual);
+ "0x%016llx at 0x%08lx in user region\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
return;
}
if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
- printk(KERN_WARNING "BUG: mapping for 0x%08lx at 0x%08lx "
+ printk(KERN_WARNING "BUG: mapping for 0x%016llx at 0x%08lx "
"overlaps vmalloc space\n",
- md->physical, md->virtual);
+ __pfn_to_phys((u64)md->pfn), md->virtual);
}
domain = mem_types[md->type].domain;
@@ -509,15 +499,40 @@ static void __init create_mapping(struct map_desc *md)
prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
+ /*
+ * Catch 36-bit addresses
+ */
+ if(md->pfn >= 0x100000) {
+ if(domain) {
+ printk(KERN_ERR "MM: invalid domain in supersection "
+ "mapping for 0x%016llx at 0x%08lx\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
+ return;
+ }
+ if((md->virtual | md->length | __pfn_to_phys(md->pfn))
+ & ~SUPERSECTION_MASK) {
+ printk(KERN_ERR "MM: cannot create mapping for "
+ "0x%016llx at 0x%08lx invalid alignment\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
+ return;
+ }
+
+ /*
+ * Shift bits [35:32] of address into bits [23:20] of PMD
+ * (See ARMv6 spec).
+ */
+ off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
+ }
+
virt = md->virtual;
- off = md->physical - virt;
+ off -= virt;
length = md->length;
if (mem_types[md->type].prot_l1 == 0 &&
(virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
"be mapped using pages, ignoring.\n",
- md->physical, md->virtual);
+ __pfn_to_phys(md->pfn), md->virtual);
return;
}
@@ -535,13 +550,22 @@ static void __init create_mapping(struct map_desc *md)
* of the actual domain assignments in use.
*/
if (cpu_architecture() >= CPU_ARCH_ARMv6 && domain == 0) {
- /* Align to supersection boundary */
- while ((virt & ~SUPERSECTION_MASK || (virt + off) &
- ~SUPERSECTION_MASK) && length >= (PGDIR_SIZE / 2)) {
- alloc_init_section(virt, virt + off, prot_sect);
+ /*
+ * Align to supersection boundary if !high pages.
+ * High pages have already been checked for proper
+ * alignment above and they will fail the SUPSERSECTION_MASK
+ * check because of the way the address is encoded into
+ * offset.
+ */
+ if (md->pfn <= 0x100000) {
+ while ((virt & ~SUPERSECTION_MASK ||
+ (virt + off) & ~SUPERSECTION_MASK) &&
+ length >= (PGDIR_SIZE / 2)) {
+ alloc_init_section(virt, virt + off, prot_sect);
- virt += (PGDIR_SIZE / 2);
- length -= (PGDIR_SIZE / 2);
+ virt += (PGDIR_SIZE / 2);
+ length -= (PGDIR_SIZE / 2);
+ }
}
while (length >= SUPERSECTION_SIZE) {
@@ -601,100 +625,6 @@ void setup_mm_for_reboot(char mode)
}
}
-extern void _stext, _etext;
-
-/*
- * Setup initial mappings. We use the page we allocated for zero page to hold
- * the mappings, which will get overwritten by the vectors in traps_init().
- * The mappings must be in virtual address order.
- */
-void __init memtable_init(struct meminfo *mi)
-{
- struct map_desc *init_maps, *p, *q;
- unsigned long address = 0;
- int i;
-
- build_mem_type_table();
-
- init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE);
-
-#ifdef CONFIG_XIP_KERNEL
- p->physical = CONFIG_XIP_PHYS_ADDR & PMD_MASK;
- p->virtual = (unsigned long)&_stext & PMD_MASK;
- p->length = ((unsigned long)&_etext - p->virtual + ~PMD_MASK) & PMD_MASK;
- p->type = MT_ROM;
- p ++;
-#endif
-
- for (i = 0; i < mi->nr_banks; i++) {
- if (mi->bank[i].size == 0)
- continue;
-
- p->physical = mi->bank[i].start;
- p->virtual = __phys_to_virt(p->physical);
- p->length = mi->bank[i].size;
- p->type = MT_MEMORY;
- p ++;
- }
-
-#ifdef FLUSH_BASE
- p->physical = FLUSH_BASE_PHYS;
- p->virtual = FLUSH_BASE;
- p->length = PGDIR_SIZE;
- p->type = MT_CACHECLEAN;
- p ++;
-#endif
-
-#ifdef FLUSH_BASE_MINICACHE
- p->physical = FLUSH_BASE_PHYS + PGDIR_SIZE;
- p->virtual = FLUSH_BASE_MINICACHE;
- p->length = PGDIR_SIZE;
- p->type = MT_MINICLEAN;
- p ++;
-#endif
-
- /*
- * Go through the initial mappings, but clear out any
- * pgdir entries that are not in the description.
- */
- q = init_maps;
- do {
- if (address < q->virtual || q == p) {
- clear_mapping(address);
- address += PGDIR_SIZE;
- } else {
- create_mapping(q);
-
- address = q->virtual + q->length;
- address = (address + PGDIR_SIZE - 1) & PGDIR_MASK;
-
- q ++;
- }
- } while (address != 0);
-
- /*
- * Create a mapping for the machine vectors at the high-vectors
- * location (0xffff0000). If we aren't using high-vectors, also
- * create a mapping at the low-vectors virtual address.
- */
- init_maps->physical = virt_to_phys(init_maps);
- init_maps->virtual = 0xffff0000;
- init_maps->length = PAGE_SIZE;
- init_maps->type = MT_HIGH_VECTORS;
- create_mapping(init_maps);
-
- if (!vectors_high()) {
- init_maps->virtual = 0;
- init_maps->type = MT_LOW_VECTORS;
- create_mapping(init_maps);
- }
-
- flush_cache_all();
- local_flush_tlb_all();
-
- top_pmd = pmd_off_k(0xffff0000);
-}
-
/*
* Create the architecture specific mappings
*/
diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
index 8ffb523e6c77..6a94e54848fd 100644
--- a/arch/arm/oprofile/Makefile
+++ b/arch/arm/oprofile/Makefile
@@ -6,6 +6,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprofilefs.o oprofile_stats.o \
timer_int.o )
-oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
-oprofile-$(CONFIG_CPU_XSCALE) += common.o op_model_xscale.o
+oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
+oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index e57dde882898..1415930ceee1 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -10,40 +10,94 @@
#include
#include
#include
-#include
#include
+#include
#include "op_counter.h"
#include "op_arm_model.h"
-static struct op_arm_model_spec *pmu_model;
-static int pmu_enabled;
-static struct semaphore pmu_sem;
+static struct op_arm_model_spec *op_arm_model;
+static int op_arm_enabled;
+static struct semaphore op_arm_sem;
-static int pmu_start(void);
-static int pmu_setup(void);
-static void pmu_stop(void);
-static int pmu_create_files(struct super_block *, struct dentry *);
+struct op_counter_config counter_config[OP_MAX_COUNTER];
-#ifdef CONFIG_PM
-static int pmu_suspend(struct sys_device *dev, pm_message_t state)
+static int op_arm_create_files(struct super_block *sb, struct dentry *root)
{
- if (pmu_enabled)
- pmu_stop();
+ unsigned int i;
+
+ for (i = 0; i < op_arm_model->num_counters; i++) {
+ struct dentry *dir;
+ char buf[2];
+
+ snprintf(buf, sizeof buf, "%d", i);
+ dir = oprofilefs_mkdir(sb, root, buf);
+ oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
+ oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
+ oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
+ oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
+ oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
+ oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
+ }
+
return 0;
}
-static int pmu_resume(struct sys_device *dev)
+static int op_arm_setup(void)
{
- if (pmu_enabled)
- pmu_start();
+ int ret;
+
+ spin_lock(&oprofilefs_lock);
+ ret = op_arm_model->setup_ctrs();
+ spin_unlock(&oprofilefs_lock);
+ return ret;
+}
+
+static int op_arm_start(void)
+{
+ int ret = -EBUSY;
+
+ down(&op_arm_sem);
+ if (!op_arm_enabled) {
+ ret = op_arm_model->start();
+ op_arm_enabled = !ret;
+ }
+ up(&op_arm_sem);
+ return ret;
+}
+
+static void op_arm_stop(void)
+{
+ down(&op_arm_sem);
+ if (op_arm_enabled)
+ op_arm_model->stop();
+ op_arm_enabled = 0;
+ up(&op_arm_sem);
+}
+
+#ifdef CONFIG_PM
+static int op_arm_suspend(struct sys_device *dev, pm_message_t state)
+{
+ down(&op_arm_sem);
+ if (op_arm_enabled)
+ op_arm_model->stop();
+ up(&op_arm_sem);
+ return 0;
+}
+
+static int op_arm_resume(struct sys_device *dev)
+{
+ down(&op_arm_sem);
+ if (op_arm_enabled && op_arm_model->start())
+ op_arm_enabled = 0;
+ up(&op_arm_sem);
return 0;
}
static struct sysdev_class oprofile_sysclass = {
set_kset_name("oprofile"),
- .resume = pmu_resume,
- .suspend = pmu_suspend,
+ .resume = op_arm_resume,
+ .suspend = op_arm_suspend,
};
static struct sys_device device_oprofile = {
@@ -71,86 +125,41 @@ static void exit_driverfs(void)
#define exit_driverfs() do { } while (0)
#endif /* CONFIG_PM */
-struct op_counter_config counter_config[OP_MAX_COUNTER];
-
-static int pmu_create_files(struct super_block *sb, struct dentry *root)
+int __init oprofile_arch_init(struct oprofile_operations *ops)
{
- unsigned int i;
+ struct op_arm_model_spec *spec = NULL;
+ int ret = -ENODEV;
- for (i = 0; i < pmu_model->num_counters; i++) {
- struct dentry *dir;
- char buf[2];
+#ifdef CONFIG_CPU_XSCALE
+ spec = &op_xscale_spec;
+#endif
- snprintf(buf, sizeof buf, "%d", i);
- dir = oprofilefs_mkdir(sb, root, buf);
- oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
- oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
- oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
- oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
- oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
- oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
+ if (spec) {
+ init_MUTEX(&op_arm_sem);
+
+ if (spec->init() < 0)
+ return -ENODEV;
+
+ op_arm_model = spec;
+ init_driverfs();
+ ops->create_files = op_arm_create_files;
+ ops->setup = op_arm_setup;
+ ops->shutdown = op_arm_stop;
+ ops->start = op_arm_start;
+ ops->stop = op_arm_stop;
+ ops->cpu_type = op_arm_model->name;
+ ops->backtrace = arm_backtrace;
+ printk(KERN_INFO "oprofile: using %s\n", spec->name);
}
- return 0;
-}
-
-static int pmu_setup(void)
-{
- int ret;
-
- spin_lock(&oprofilefs_lock);
- ret = pmu_model->setup_ctrs();
- spin_unlock(&oprofilefs_lock);
return ret;
}
-static int pmu_start(void)
+void oprofile_arch_exit(void)
{
- int ret = -EBUSY;
-
- down(&pmu_sem);
- if (!pmu_enabled) {
- ret = pmu_model->start();
- pmu_enabled = !ret;
- }
- up(&pmu_sem);
- return ret;
-}
-
-static void pmu_stop(void)
-{
- down(&pmu_sem);
- if (pmu_enabled)
- pmu_model->stop();
- pmu_enabled = 0;
- up(&pmu_sem);
-}
-
-int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec)
-{
- init_MUTEX(&pmu_sem);
-
- if (spec->init() < 0)
- return -ENODEV;
-
- pmu_model = spec;
- init_driverfs();
- ops->create_files = pmu_create_files;
- ops->setup = pmu_setup;
- ops->shutdown = pmu_stop;
- ops->start = pmu_start;
- ops->stop = pmu_stop;
- ops->cpu_type = pmu_model->name;
- printk(KERN_INFO "oprofile: using %s PMU\n", spec->name);
-
- return 0;
-}
-
-void pmu_exit(void)
-{
- if (pmu_model) {
+ if (op_arm_model) {
exit_driverfs();
- pmu_model = NULL;
+ op_arm_model = NULL;
}
}
diff --git a/arch/arm/oprofile/init.c b/arch/arm/oprofile/init.c
deleted file mode 100644
index d315a3a86c86..000000000000
--- a/arch/arm/oprofile/init.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * @file init.c
- *
- * @remark Copyright 2004 Oprofile Authors
- * @remark Read the file COPYING
- *
- * @author Zwane Mwaikambo
- */
-
-#include
-#include
-#include
-#include "op_arm_model.h"
-
-int __init oprofile_arch_init(struct oprofile_operations *ops)
-{
- int ret = -ENODEV;
-
-#ifdef CONFIG_CPU_XSCALE
- ret = pmu_init(ops, &op_xscale_spec);
-#endif
-
- ops->backtrace = arm_backtrace;
-
- return ret;
-}
-
-void oprofile_arch_exit(void)
-{
-#ifdef CONFIG_CPU_XSCALE
- pmu_exit();
-#endif
-}
diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h
index 2148d07484b7..38c6ad158547 100644
--- a/arch/arm/oprofile/op_arm_model.h
+++ b/arch/arm/oprofile/op_arm_model.h
@@ -26,6 +26,6 @@ extern struct op_arm_model_spec op_xscale_spec;
extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
-extern int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec);
-extern void pmu_exit(void);
+extern int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec);
+extern void op_arm_exit(void);
#endif /* OP_ARM_MODEL_H */
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 7719a4062e3a..7ad69f14a3e7 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -59,7 +59,11 @@ void __init omap_detect_sram(void)
}
static struct map_desc omap_sram_io_desc[] __initdata = {
- { OMAP1_SRAM_BASE, OMAP1_SRAM_START, 0, MT_DEVICE }
+ { /* .length gets filled in at runtime */
+ .virtual = OMAP1_SRAM_BASE,
+ .pfn = __phys_to_pfn(OMAP1_SRAM_START),
+ .type = MT_DEVICE
+ }
};
/*
diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c
index 819895cf0b9e..2082a9647f4f 100644
--- a/arch/frv/mb93090-mb00/pci-dma-nommu.c
+++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c
@@ -33,7 +33,7 @@ struct dma_alloc_record {
static DEFINE_SPINLOCK(dma_alloc_lock);
static LIST_HEAD(dma_alloc_list);
-void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, int gfp)
+void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t gfp)
{
struct dma_alloc_record *new;
struct list_head *this = &dma_alloc_list;
diff --git a/arch/frv/mb93090-mb00/pci-dma.c b/arch/frv/mb93090-mb00/pci-dma.c
index 27eb12066507..86fbdadc51b6 100644
--- a/arch/frv/mb93090-mb00/pci-dma.c
+++ b/arch/frv/mb93090-mb00/pci-dma.c
@@ -17,7 +17,7 @@
#include
#include
-void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, int gfp)
+void *dma_alloc_coherent(struct device *hwdev, size_t size, dma_addr_t *dma_handle, gfp_t gfp)
{
void *ret;
diff --git a/arch/frv/mm/dma-alloc.c b/arch/frv/mm/dma-alloc.c
index 4b38d45435f6..cfc4f97490c6 100644
--- a/arch/frv/mm/dma-alloc.c
+++ b/arch/frv/mm/dma-alloc.c
@@ -81,7 +81,7 @@ static int map_page(unsigned long va, unsigned long pa, pgprot_t prot)
* portions of the kernel with single large page TLB entries, and
* still get unique uncached pages for consistent DMA.
*/
-void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
+void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle)
{
struct vm_struct *area;
unsigned long page, va, pa;
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c
index 80f8ef013939..1ba02baf2f94 100644
--- a/arch/ia64/hp/common/hwsw_iommu.c
+++ b/arch/ia64/hp/common/hwsw_iommu.c
@@ -71,7 +71,7 @@ hwsw_init (void)
}
void *
-hwsw_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, int flags)
+hwsw_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags)
{
if (use_swiotlb(dev))
return swiotlb_alloc_coherent(dev, size, dma_handle, flags);
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 11957598a8b9..21bffba78b6d 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -1076,7 +1076,7 @@ void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir)
* See Documentation/DMA-mapping.txt
*/
void *
-sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, int flags)
+sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags)
{
struct ioc *ioc;
void *addr;
diff --git a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
index a604efc7f6c9..3ebbb3c8ba36 100644
--- a/arch/ia64/lib/swiotlb.c
+++ b/arch/ia64/lib/swiotlb.c
@@ -314,7 +314,7 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
void *
swiotlb_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, int flags)
+ dma_addr_t *dma_handle, gfp_t flags)
{
unsigned long dev_addr;
void *ret;
diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h
index d0ee635daf2e..e5f5a4e51f70 100644
--- a/arch/ia64/sn/kernel/xpc.h
+++ b/arch/ia64/sn/kernel/xpc.h
@@ -939,7 +939,7 @@ xpc_map_bte_errors(bte_result_t error)
static inline void *
-xpc_kmalloc_cacheline_aligned(size_t size, int flags, void **base)
+xpc_kmalloc_cacheline_aligned(size_t size, gfp_t flags, void **base)
{
/* see if kmalloc will give us cachline aligned memory by default */
*base = kmalloc(size, flags);
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
index 0e4b9ad9ef02..75e6e874bebf 100644
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -75,7 +75,7 @@ EXPORT_SYMBOL(sn_dma_set_mask);
* more information.
*/
void *sn_dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int flags)
+ dma_addr_t * dma_handle, gfp_t flags)
{
void *cpuaddr;
unsigned long phys_addr;
diff --git a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c
index 97a50d38c98f..a617f8c327e8 100644
--- a/arch/mips/mm/dma-coherent.c
+++ b/arch/mips/mm/dma-coherent.c
@@ -18,7 +18,7 @@
#include
void *dma_alloc_noncoherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle, gfp_t gfp)
{
void *ret;
/* ignore region specifiers */
@@ -39,7 +39,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size,
EXPORT_SYMBOL(dma_alloc_noncoherent);
void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle, gfp_t gfp)
__attribute__((alias("dma_alloc_noncoherent")));
EXPORT_SYMBOL(dma_alloc_coherent);
diff --git a/arch/mips/mm/dma-ip27.c b/arch/mips/mm/dma-ip27.c
index aa7c94b5d781..8da19fd22ac6 100644
--- a/arch/mips/mm/dma-ip27.c
+++ b/arch/mips/mm/dma-ip27.c
@@ -22,7 +22,7 @@
pdev_to_baddr(to_pci_dev(dev), (addr))
void *dma_alloc_noncoherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle, gfp_t gfp)
{
void *ret;
@@ -44,7 +44,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size,
EXPORT_SYMBOL(dma_alloc_noncoherent);
void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle, gfp_t gfp)
__attribute__((alias("dma_alloc_noncoherent")));
EXPORT_SYMBOL(dma_alloc_coherent);
diff --git a/arch/mips/mm/dma-ip32.c b/arch/mips/mm/dma-ip32.c
index 2cbe196c35fb..a7e3072ff78d 100644
--- a/arch/mips/mm/dma-ip32.c
+++ b/arch/mips/mm/dma-ip32.c
@@ -37,7 +37,7 @@
#define RAM_OFFSET_MASK 0x3fffffff
void *dma_alloc_noncoherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle, gfp_t gfp)
{
void *ret;
/* ignore region specifiers */
@@ -61,7 +61,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size,
EXPORT_SYMBOL(dma_alloc_noncoherent);
void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle, gfp_t gfp)
{
void *ret;
diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c
index 59e54f12212e..4ce02028a292 100644
--- a/arch/mips/mm/dma-noncoherent.c
+++ b/arch/mips/mm/dma-noncoherent.c
@@ -24,7 +24,7 @@
*/
void *dma_alloc_noncoherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle, gfp_t gfp)
{
void *ret;
/* ignore region specifiers */
@@ -45,7 +45,7 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size,
EXPORT_SYMBOL(dma_alloc_noncoherent);
void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle, int gfp)
+ dma_addr_t * dma_handle, gfp_t gfp)
{
void *ret;
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
index 368cc095c99f..844c2877a2e3 100644
--- a/arch/parisc/kernel/pci-dma.c
+++ b/arch/parisc/kernel/pci-dma.c
@@ -349,7 +349,7 @@ pcxl_dma_init(void)
__initcall(pcxl_dma_init);
-static void * pa11_dma_alloc_consistent (struct device *dev, size_t size, dma_addr_t *dma_handle, int flag)
+static void * pa11_dma_alloc_consistent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag)
{
unsigned long vaddr;
unsigned long paddr;
@@ -502,13 +502,13 @@ struct hppa_dma_ops pcxl_dma_ops = {
};
static void *fail_alloc_consistent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, int flag)
+ dma_addr_t *dma_handle, gfp_t flag)
{
return NULL;
}
static void *pa11_dma_alloc_noncoherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, int flag)
+ dma_addr_t *dma_handle, gfp_t flag)
{
void *addr = NULL;
diff --git a/arch/ppc/8xx_io/cs4218.h b/arch/ppc/8xx_io/cs4218.h
index a3c38c5a5db2..f1c7392255f8 100644
--- a/arch/ppc/8xx_io/cs4218.h
+++ b/arch/ppc/8xx_io/cs4218.h
@@ -78,7 +78,7 @@ typedef struct {
const char *name2;
void (*open)(void);
void (*release)(void);
- void *(*dma_alloc)(unsigned int, int);
+ void *(*dma_alloc)(unsigned int, gfp_t);
void (*dma_free)(void *, unsigned int);
int (*irqinit)(void);
#ifdef MODULE
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
index 2ca9ec7ec3a7..532caa388dc2 100644
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ b/arch/ppc/8xx_io/cs4218_tdm.c
@@ -318,7 +318,7 @@ struct cs_sound_settings {
static struct cs_sound_settings sound;
-static void *CS_Alloc(unsigned int size, int flags);
+static void *CS_Alloc(unsigned int size, gfp_t flags);
static void CS_Free(void *ptr, unsigned int size);
static int CS_IrqInit(void);
#ifdef MODULE
@@ -959,7 +959,7 @@ static TRANS transCSNormalRead = {
/*** Low level stuff *********************************************************/
-static void *CS_Alloc(unsigned int size, int flags)
+static void *CS_Alloc(unsigned int size, gfp_t flags)
{
int order;
diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c
index 8edee806dae7..0f710d2baec6 100644
--- a/arch/ppc/kernel/dma-mapping.c
+++ b/arch/ppc/kernel/dma-mapping.c
@@ -115,7 +115,7 @@ static struct vm_region consistent_head = {
};
static struct vm_region *
-vm_region_alloc(struct vm_region *head, size_t size, int gfp)
+vm_region_alloc(struct vm_region *head, size_t size, gfp_t gfp)
{
unsigned long addr = head->vm_start, end = head->vm_end - size;
unsigned long flags;
@@ -173,7 +173,7 @@ static struct vm_region *vm_region_find(struct vm_region *head, unsigned long ad
* virtual and bus address for that space.
*/
void *
-__dma_alloc_coherent(size_t size, dma_addr_t *handle, int gfp)
+__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
{
struct page *page;
struct vm_region *c;
diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
index 81a3d7446d37..43505b1fc5d8 100644
--- a/arch/ppc/mm/pgtable.c
+++ b/arch/ppc/mm/pgtable.c
@@ -114,9 +114,9 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
struct page *ptepage;
#ifdef CONFIG_HIGHPTE
- int flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT;
+ gfp_t flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_REPEAT;
#else
- int flags = GFP_KERNEL | __GFP_REPEAT;
+ gfp_t flags = GFP_KERNEL | __GFP_REPEAT;
#endif
ptepage = alloc_pages(flags, 0);
diff --git a/arch/sh/boards/renesas/rts7751r2d/mach.c b/arch/sh/boards/renesas/rts7751r2d/mach.c
index 1efc18e786d5..610740512d56 100644
--- a/arch/sh/boards/renesas/rts7751r2d/mach.c
+++ b/arch/sh/boards/renesas/rts7751r2d/mach.c
@@ -23,7 +23,7 @@ extern void init_rts7751r2d_IRQ(void);
extern void *rts7751r2d_ioremap(unsigned long, unsigned long);
extern int rts7751r2d_irq_demux(int irq);
-extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, int);
+extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
/*
diff --git a/arch/sh/cchips/voyagergx/consistent.c b/arch/sh/cchips/voyagergx/consistent.c
index 5b92585a38d2..3d9a02c093a3 100644
--- a/arch/sh/cchips/voyagergx/consistent.c
+++ b/arch/sh/cchips/voyagergx/consistent.c
@@ -31,7 +31,7 @@ static LIST_HEAD(voya_alloc_list);
#define OHCI_SRAM_SIZE 0x10000
void *voyagergx_consistent_alloc(struct device *dev, size_t size,
- dma_addr_t *handle, int flag)
+ dma_addr_t *handle, gfp_t flag)
{
struct list_head *list = &voya_alloc_list;
struct voya_alloc_entry *entry;
diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c
index 83de7ef4e7df..e12418bb1fa5 100644
--- a/arch/sh/drivers/pci/dma-dreamcast.c
+++ b/arch/sh/drivers/pci/dma-dreamcast.c
@@ -33,7 +33,7 @@
static int gapspci_dma_used = 0;
void *dreamcast_consistent_alloc(struct device *dev, size_t size,
- dma_addr_t *dma_handle, int flag)
+ dma_addr_t *dma_handle, gfp_t flag)
{
unsigned long buf;
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index 1f7af0c73cf4..df3a9e452cc5 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -11,7 +11,7 @@
#include
#include
-void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle)
+void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
{
struct page *page, *end, *free;
void *ret;
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
index d7c1c76582cc..fc6669e8dde1 100644
--- a/arch/sparc64/solaris/socksys.c
+++ b/arch/sparc64/solaris/socksys.c
@@ -49,7 +49,7 @@ IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW,
#else
-extern void * mykmalloc(size_t s, int gfp);
+extern void * mykmalloc(size_t s, gfp_t gfp);
extern void mykfree(void *);
#endif
diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
index aaad29c35c83..b84e5456b025 100644
--- a/arch/sparc64/solaris/timod.c
+++ b/arch/sparc64/solaris/timod.c
@@ -39,7 +39,7 @@ static char * page = NULL ;
#else
-void * mykmalloc(size_t s, int gfp)
+void * mykmalloc(size_t s, gfp_t gfp)
{
static char * page;
static size_t free;
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index ea008b031a8f..462cc9d65386 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -252,7 +252,7 @@ void paging_init(void)
#endif
}
-struct page *arch_validate(struct page *page, int mask, int order)
+struct page *arch_validate(struct page *page, gfp_t mask, int order)
{
unsigned long addr, zero = 0;
int i;
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index ea65db679e9c..0d73ceeece72 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -80,7 +80,7 @@ void free_stack(unsigned long stack, int order)
unsigned long alloc_stack(int order, int atomic)
{
unsigned long page;
- int flags = GFP_KERNEL;
+ gfp_t flags = GFP_KERNEL;
if (atomic)
flags = GFP_ATOMIC;
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index cf0a0315d586..88be97c96987 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -187,7 +187,7 @@ static void flush_gart(struct device *dev)
/* Allocate DMA memory on node near device */
noinline
-static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order)
+static void *dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order)
{
struct page *page;
int node;
@@ -204,7 +204,7 @@ static void *dma_alloc_pages(struct device *dev, unsigned gfp, unsigned order)
*/
void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
- unsigned gfp)
+ gfp_t gfp)
{
void *memory;
unsigned long dma_mask = 0;
diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
index 67d90b89af0b..5a981dca87ff 100644
--- a/arch/x86_64/kernel/pci-nommu.c
+++ b/arch/x86_64/kernel/pci-nommu.c
@@ -24,7 +24,7 @@ EXPORT_SYMBOL(iommu_sac_force);
*/
void *dma_alloc_coherent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, unsigned gfp)
+ dma_addr_t *dma_handle, gfp_t gfp)
{
void *ret;
u64 mask;
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
index 84fde258cf85..1ff82268e8ea 100644
--- a/arch/xtensa/kernel/pci-dma.c
+++ b/arch/xtensa/kernel/pci-dma.c
@@ -29,7 +29,7 @@
*/
void *
-dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
void *ret;
diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c
index 95c0a3690b0f..4081c36c8c19 100644
--- a/drivers/block/as-iosched.c
+++ b/drivers/block/as-iosched.c
@@ -98,7 +98,6 @@ struct as_data {
struct as_rq *next_arq[2]; /* next in sort order */
sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */
- struct list_head *dispatch; /* driver dispatch queue */
struct list_head *hash; /* request hash */
unsigned long exit_prob; /* probability a task will exit while
@@ -239,6 +238,25 @@ static struct io_context *as_get_io_context(void)
return ioc;
}
+static void as_put_io_context(struct as_rq *arq)
+{
+ struct as_io_context *aic;
+
+ if (unlikely(!arq->io_context))
+ return;
+
+ aic = arq->io_context->aic;
+
+ if (arq->is_sync == REQ_SYNC && aic) {
+ spin_lock(&aic->lock);
+ set_bit(AS_TASK_IORUNNING, &aic->state);
+ aic->last_end_request = jiffies;
+ spin_unlock(&aic->lock);
+ }
+
+ put_io_context(arq->io_context);
+}
+
/*
* the back merge hash support functions
*/
@@ -261,14 +279,6 @@ static inline void as_del_arq_hash(struct as_rq *arq)
__as_del_arq_hash(arq);
}
-static void as_remove_merge_hints(request_queue_t *q, struct as_rq *arq)
-{
- as_del_arq_hash(arq);
-
- if (q->last_merge == arq->request)
- q->last_merge = NULL;
-}
-
static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq)
{
struct request *rq = arq->request;
@@ -312,7 +322,7 @@ static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset)
BUG_ON(!arq->on_hash);
if (!rq_mergeable(__rq)) {
- as_remove_merge_hints(ad->q, arq);
+ as_del_arq_hash(arq);
continue;
}
@@ -950,23 +960,12 @@ static void as_completed_request(request_queue_t *q, struct request *rq)
WARN_ON(!list_empty(&rq->queuelist));
- if (arq->state == AS_RQ_PRESCHED) {
- WARN_ON(arq->io_context);
- goto out;
- }
-
- if (arq->state == AS_RQ_MERGED)
- goto out_ioc;
-
if (arq->state != AS_RQ_REMOVED) {
printk("arq->state %d\n", arq->state);
WARN_ON(1);
goto out;
}
- if (!blk_fs_request(rq))
- goto out;
-
if (ad->changed_batch && ad->nr_dispatched == 1) {
kblockd_schedule_work(&ad->antic_work);
ad->changed_batch = 0;
@@ -1001,21 +1000,7 @@ static void as_completed_request(request_queue_t *q, struct request *rq)
}
}
-out_ioc:
- if (!arq->io_context)
- goto out;
-
- if (arq->is_sync == REQ_SYNC) {
- struct as_io_context *aic = arq->io_context->aic;
- if (aic) {
- spin_lock(&aic->lock);
- set_bit(AS_TASK_IORUNNING, &aic->state);
- aic->last_end_request = jiffies;
- spin_unlock(&aic->lock);
- }
- }
-
- put_io_context(arq->io_context);
+ as_put_io_context(arq);
out:
arq->state = AS_RQ_POSTSCHED;
}
@@ -1047,72 +1032,10 @@ static void as_remove_queued_request(request_queue_t *q, struct request *rq)
ad->next_arq[data_dir] = as_find_next_arq(ad, arq);
list_del_init(&arq->fifo);
- as_remove_merge_hints(q, arq);
+ as_del_arq_hash(arq);
as_del_arq_rb(ad, arq);
}
-/*
- * as_remove_dispatched_request is called to remove a request which has gone
- * to the dispatch list.
- */
-static void as_remove_dispatched_request(request_queue_t *q, struct request *rq)
-{
- struct as_rq *arq = RQ_DATA(rq);
- struct as_io_context *aic;
-
- if (!arq) {
- WARN_ON(1);
- return;
- }
-
- WARN_ON(arq->state != AS_RQ_DISPATCHED);
- WARN_ON(ON_RB(&arq->rb_node));
- if (arq->io_context && arq->io_context->aic) {
- aic = arq->io_context->aic;
- if (aic) {
- WARN_ON(!atomic_read(&aic->nr_dispatched));
- atomic_dec(&aic->nr_dispatched);
- }
- }
-}
-
-/*
- * as_remove_request is called when a driver has finished with a request.
- * This should be only called for dispatched requests, but for some reason
- * a POWER4 box running hwscan it does not.
- */
-static void as_remove_request(request_queue_t *q, struct request *rq)
-{
- struct as_rq *arq = RQ_DATA(rq);
-
- if (unlikely(arq->state == AS_RQ_NEW))
- goto out;
-
- if (ON_RB(&arq->rb_node)) {
- if (arq->state != AS_RQ_QUEUED) {
- printk("arq->state %d\n", arq->state);
- WARN_ON(1);
- goto out;
- }
- /*
- * We'll lose the aliased request(s) here. I don't think this
- * will ever happen, but if it does, hopefully someone will
- * report it.
- */
- WARN_ON(!list_empty(&rq->queuelist));
- as_remove_queued_request(q, rq);
- } else {
- if (arq->state != AS_RQ_DISPATCHED) {
- printk("arq->state %d\n", arq->state);
- WARN_ON(1);
- goto out;
- }
- as_remove_dispatched_request(q, rq);
- }
-out:
- arq->state = AS_RQ_REMOVED;
-}
-
/*
* as_fifo_expired returns 0 if there are no expired reads on the fifo,
* 1 otherwise. It is ratelimited so that we only perform the check once per
@@ -1165,7 +1088,6 @@ static inline int as_batch_expired(struct as_data *ad)
static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
{
struct request *rq = arq->request;
- struct list_head *insert;
const int data_dir = arq->is_sync;
BUG_ON(!ON_RB(&arq->rb_node));
@@ -1198,13 +1120,13 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
/*
* take it off the sort and fifo list, add to dispatch queue
*/
- insert = ad->dispatch->prev;
-
while (!list_empty(&rq->queuelist)) {
struct request *__rq = list_entry_rq(rq->queuelist.next);
struct as_rq *__arq = RQ_DATA(__rq);
- list_move_tail(&__rq->queuelist, ad->dispatch);
+ list_del(&__rq->queuelist);
+
+ elv_dispatch_add_tail(ad->q, __rq);
if (__arq->io_context && __arq->io_context->aic)
atomic_inc(&__arq->io_context->aic->nr_dispatched);
@@ -1218,7 +1140,8 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
as_remove_queued_request(ad->q, rq);
WARN_ON(arq->state != AS_RQ_QUEUED);
- list_add(&rq->queuelist, insert);
+ elv_dispatch_sort(ad->q, rq);
+
arq->state = AS_RQ_DISPATCHED;
if (arq->io_context && arq->io_context->aic)
atomic_inc(&arq->io_context->aic->nr_dispatched);
@@ -1230,12 +1153,42 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
* read/write expire, batch expire, etc, and moves it to the dispatch
* queue. Returns 1 if a request was found, 0 otherwise.
*/
-static int as_dispatch_request(struct as_data *ad)
+static int as_dispatch_request(request_queue_t *q, int force)
{
+ struct as_data *ad = q->elevator->elevator_data;
struct as_rq *arq;
const int reads = !list_empty(&ad->fifo_list[REQ_SYNC]);
const int writes = !list_empty(&ad->fifo_list[REQ_ASYNC]);
+ if (unlikely(force)) {
+ /*
+ * Forced dispatch, accounting is useless. Reset
+ * accounting states and dump fifo_lists. Note that
+ * batch_data_dir is reset to REQ_SYNC to avoid
+ * screwing write batch accounting as write batch
+ * accounting occurs on W->R transition.
+ */
+ int dispatched = 0;
+
+ ad->batch_data_dir = REQ_SYNC;
+ ad->changed_batch = 0;
+ ad->new_batch = 0;
+
+ while (ad->next_arq[REQ_SYNC]) {
+ as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]);
+ dispatched++;
+ }
+ ad->last_check_fifo[REQ_SYNC] = jiffies;
+
+ while (ad->next_arq[REQ_ASYNC]) {
+ as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]);
+ dispatched++;
+ }
+ ad->last_check_fifo[REQ_ASYNC] = jiffies;
+
+ return dispatched;
+ }
+
/* Signal that the write batch was uncontended, so we can't time it */
if (ad->batch_data_dir == REQ_ASYNC && !reads) {
if (ad->current_write_count == 0 || !writes)
@@ -1359,20 +1312,6 @@ fifo_expired:
return 1;
}
-static struct request *as_next_request(request_queue_t *q)
-{
- struct as_data *ad = q->elevator->elevator_data;
- struct request *rq = NULL;
-
- /*
- * if there are still requests on the dispatch queue, grab the first
- */
- if (!list_empty(ad->dispatch) || as_dispatch_request(ad))
- rq = list_entry_rq(ad->dispatch->next);
-
- return rq;
-}
-
/*
* Add arq to a list behind alias
*/
@@ -1404,17 +1343,25 @@ as_add_aliased_request(struct as_data *ad, struct as_rq *arq, struct as_rq *alia
/*
* Don't want to have to handle merges.
*/
- as_remove_merge_hints(ad->q, arq);
+ as_del_arq_hash(arq);
}
/*
* add arq to rbtree and fifo
*/
-static void as_add_request(struct as_data *ad, struct as_rq *arq)
+static void as_add_request(request_queue_t *q, struct request *rq)
{
+ struct as_data *ad = q->elevator->elevator_data;
+ struct as_rq *arq = RQ_DATA(rq);
struct as_rq *alias;
int data_dir;
+ if (arq->state != AS_RQ_PRESCHED) {
+ printk("arq->state: %d\n", arq->state);
+ WARN_ON(1);
+ }
+ arq->state = AS_RQ_NEW;
+
if (rq_data_dir(arq->request) == READ
|| current->flags&PF_SYNCWRITE)
arq->is_sync = 1;
@@ -1437,12 +1384,8 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq)
arq->expires = jiffies + ad->fifo_expire[data_dir];
list_add_tail(&arq->fifo, &ad->fifo_list[data_dir]);
- if (rq_mergeable(arq->request)) {
+ if (rq_mergeable(arq->request))
as_add_arq_hash(ad, arq);
-
- if (!ad->q->last_merge)
- ad->q->last_merge = arq->request;
- }
as_update_arq(ad, arq); /* keep state machine up to date */
} else {
@@ -1463,96 +1406,24 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq)
arq->state = AS_RQ_QUEUED;
}
+static void as_activate_request(request_queue_t *q, struct request *rq)
+{
+ struct as_rq *arq = RQ_DATA(rq);
+
+ WARN_ON(arq->state != AS_RQ_DISPATCHED);
+ arq->state = AS_RQ_REMOVED;
+ if (arq->io_context && arq->io_context->aic)
+ atomic_dec(&arq->io_context->aic->nr_dispatched);
+}
+
static void as_deactivate_request(request_queue_t *q, struct request *rq)
{
- struct as_data *ad = q->elevator->elevator_data;
struct as_rq *arq = RQ_DATA(rq);
- if (arq) {
- if (arq->state == AS_RQ_REMOVED) {
- arq->state = AS_RQ_DISPATCHED;
- if (arq->io_context && arq->io_context->aic)
- atomic_inc(&arq->io_context->aic->nr_dispatched);
- }
- } else
- WARN_ON(blk_fs_request(rq)
- && (!(rq->flags & (REQ_HARDBARRIER|REQ_SOFTBARRIER))) );
-
- /* Stop anticipating - let this request get through */
- as_antic_stop(ad);
-}
-
-/*
- * requeue the request. The request has not been completed, nor is it a
- * new request, so don't touch accounting.
- */
-static void as_requeue_request(request_queue_t *q, struct request *rq)
-{
- as_deactivate_request(q, rq);
- list_add(&rq->queuelist, &q->queue_head);
-}
-
-/*
- * Account a request that is inserted directly onto the dispatch queue.
- * arq->io_context->aic->nr_dispatched should not need to be incremented
- * because only new requests should come through here: requeues go through
- * our explicit requeue handler.
- */
-static void as_account_queued_request(struct as_data *ad, struct request *rq)
-{
- if (blk_fs_request(rq)) {
- struct as_rq *arq = RQ_DATA(rq);
- arq->state = AS_RQ_DISPATCHED;
- ad->nr_dispatched++;
- }
-}
-
-static void
-as_insert_request(request_queue_t *q, struct request *rq, int where)
-{
- struct as_data *ad = q->elevator->elevator_data;
- struct as_rq *arq = RQ_DATA(rq);
-
- if (arq) {
- if (arq->state != AS_RQ_PRESCHED) {
- printk("arq->state: %d\n", arq->state);
- WARN_ON(1);
- }
- arq->state = AS_RQ_NEW;
- }
-
- /* barriers must flush the reorder queue */
- if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)
- && where == ELEVATOR_INSERT_SORT)) {
- WARN_ON(1);
- where = ELEVATOR_INSERT_BACK;
- }
-
- switch (where) {
- case ELEVATOR_INSERT_BACK:
- while (ad->next_arq[REQ_SYNC])
- as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]);
-
- while (ad->next_arq[REQ_ASYNC])
- as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]);
-
- list_add_tail(&rq->queuelist, ad->dispatch);
- as_account_queued_request(ad, rq);
- as_antic_stop(ad);
- break;
- case ELEVATOR_INSERT_FRONT:
- list_add(&rq->queuelist, ad->dispatch);
- as_account_queued_request(ad, rq);
- as_antic_stop(ad);
- break;
- case ELEVATOR_INSERT_SORT:
- BUG_ON(!blk_fs_request(rq));
- as_add_request(ad, arq);
- break;
- default:
- BUG();
- return;
- }
+ WARN_ON(arq->state != AS_RQ_REMOVED);
+ arq->state = AS_RQ_DISPATCHED;
+ if (arq->io_context && arq->io_context->aic)
+ atomic_inc(&arq->io_context->aic->nr_dispatched);
}
/*
@@ -1565,12 +1436,8 @@ static int as_queue_empty(request_queue_t *q)
{
struct as_data *ad = q->elevator->elevator_data;
- if (!list_empty(&ad->fifo_list[REQ_ASYNC])
- || !list_empty(&ad->fifo_list[REQ_SYNC])
- || !list_empty(ad->dispatch))
- return 0;
-
- return 1;
+ return list_empty(&ad->fifo_list[REQ_ASYNC])
+ && list_empty(&ad->fifo_list[REQ_SYNC]);
}
static struct request *
@@ -1607,15 +1474,6 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio)
struct request *__rq;
int ret;
- /*
- * try last_merge to avoid going to hash
- */
- ret = elv_try_last_merge(q, bio);
- if (ret != ELEVATOR_NO_MERGE) {
- __rq = q->last_merge;
- goto out_insert;
- }
-
/*
* see if the merge hash can satisfy a back merge
*/
@@ -1644,9 +1502,6 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio)
return ELEVATOR_NO_MERGE;
out:
- if (rq_mergeable(__rq))
- q->last_merge = __rq;
-out_insert:
if (ret) {
if (rq_mergeable(__rq))
as_hot_arq_hash(ad, RQ_DATA(__rq));
@@ -1693,9 +1548,6 @@ static void as_merged_request(request_queue_t *q, struct request *req)
* behind the disk head. We currently don't bother adjusting.
*/
}
-
- if (arq->on_hash)
- q->last_merge = req;
}
static void
@@ -1763,6 +1615,7 @@ as_merged_requests(request_queue_t *q, struct request *req,
* kill knowledge of next, this one is a goner
*/
as_remove_queued_request(q, next);
+ as_put_io_context(anext);
anext->state = AS_RQ_MERGED;
}
@@ -1782,7 +1635,7 @@ static void as_work_handler(void *data)
unsigned long flags;
spin_lock_irqsave(q->queue_lock, flags);
- if (as_next_request(q))
+ if (!as_queue_empty(q))
q->request_fn(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
@@ -1797,7 +1650,9 @@ static void as_put_request(request_queue_t *q, struct request *rq)
return;
}
- if (arq->state != AS_RQ_POSTSCHED && arq->state != AS_RQ_PRESCHED) {
+ if (unlikely(arq->state != AS_RQ_POSTSCHED &&
+ arq->state != AS_RQ_PRESCHED &&
+ arq->state != AS_RQ_MERGED)) {
printk("arq->state %d\n", arq->state);
WARN_ON(1);
}
@@ -1807,7 +1662,7 @@ static void as_put_request(request_queue_t *q, struct request *rq)
}
static int as_set_request(request_queue_t *q, struct request *rq,
- struct bio *bio, int gfp_mask)
+ struct bio *bio, gfp_t gfp_mask)
{
struct as_data *ad = q->elevator->elevator_data;
struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
@@ -1907,7 +1762,6 @@ static int as_init_queue(request_queue_t *q, elevator_t *e)
INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]);
ad->sort_list[REQ_SYNC] = RB_ROOT;
ad->sort_list[REQ_ASYNC] = RB_ROOT;
- ad->dispatch = &q->queue_head;
ad->fifo_expire[REQ_SYNC] = default_read_expire;
ad->fifo_expire[REQ_ASYNC] = default_write_expire;
ad->antic_expire = default_antic_expire;
@@ -2072,10 +1926,9 @@ static struct elevator_type iosched_as = {
.elevator_merge_fn = as_merge,
.elevator_merged_fn = as_merged_request,
.elevator_merge_req_fn = as_merged_requests,
- .elevator_next_req_fn = as_next_request,
- .elevator_add_req_fn = as_insert_request,
- .elevator_remove_req_fn = as_remove_request,
- .elevator_requeue_req_fn = as_requeue_request,
+ .elevator_dispatch_fn = as_dispatch_request,
+ .elevator_add_req_fn = as_add_request,
+ .elevator_activate_req_fn = as_activate_request,
.elevator_deactivate_req_fn = as_deactivate_request,
.elevator_queue_empty_fn = as_queue_empty,
.elevator_completed_req_fn = as_completed_request,
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c
index cd056e7e64ec..94690e4d41e0 100644
--- a/drivers/block/cfq-iosched.c
+++ b/drivers/block/cfq-iosched.c
@@ -84,7 +84,6 @@ static int cfq_max_depth = 2;
(node)->rb_left = NULL; \
} while (0)
#define RB_CLEAR_ROOT(root) ((root)->rb_node = NULL)
-#define ON_RB(node) ((node)->rb_color != RB_NONE)
#define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node)
#define rq_rb_key(rq) (rq)->sector
@@ -271,10 +270,7 @@ CFQ_CFQQ_FNS(expired);
#undef CFQ_CFQQ_FNS
enum cfq_rq_state_flags {
- CFQ_CRQ_FLAG_in_flight = 0,
- CFQ_CRQ_FLAG_in_driver,
- CFQ_CRQ_FLAG_is_sync,
- CFQ_CRQ_FLAG_requeued,
+ CFQ_CRQ_FLAG_is_sync = 0,
};
#define CFQ_CRQ_FNS(name) \
@@ -291,14 +287,11 @@ static inline int cfq_crq_##name(const struct cfq_rq *crq) \
return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \
}
-CFQ_CRQ_FNS(in_flight);
-CFQ_CRQ_FNS(in_driver);
CFQ_CRQ_FNS(is_sync);
-CFQ_CRQ_FNS(requeued);
#undef CFQ_CRQ_FNS
static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
-static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *);
+static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *);
static void cfq_put_cfqd(struct cfq_data *cfqd);
#define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE)
@@ -311,14 +304,6 @@ static inline void cfq_del_crq_hash(struct cfq_rq *crq)
hlist_del_init(&crq->hash);
}
-static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq)
-{
- cfq_del_crq_hash(crq);
-
- if (q->last_merge == crq->request)
- q->last_merge = NULL;
-}
-
static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
{
const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request));
@@ -347,18 +332,13 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
return NULL;
}
-static inline int cfq_pending_requests(struct cfq_data *cfqd)
-{
- return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues;
-}
-
/*
* scheduler run of queue, if there are requests pending and no one in the
* driver that will restart queueing
*/
static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
{
- if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd))
+ if (!cfqd->rq_in_driver && cfqd->busy_queues)
kblockd_schedule_work(&cfqd->unplug_work);
}
@@ -366,7 +346,7 @@ static int cfq_queue_empty(request_queue_t *q)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- return !cfq_pending_requests(cfqd);
+ return !cfqd->busy_queues;
}
/*
@@ -386,11 +366,6 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
if (crq2 == NULL)
return crq1;
- if (cfq_crq_requeued(crq1) && !cfq_crq_requeued(crq2))
- return crq1;
- else if (cfq_crq_requeued(crq2) && !cfq_crq_requeued(crq1))
- return crq2;
-
if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2))
return crq1;
else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1))
@@ -461,10 +436,7 @@ cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_rq *crq_next = NULL, *crq_prev = NULL;
struct rb_node *rbnext, *rbprev;
- rbnext = NULL;
- if (ON_RB(&last->rb_node))
- rbnext = rb_next(&last->rb_node);
- if (!rbnext) {
+ if (!(rbnext = rb_next(&last->rb_node))) {
rbnext = rb_first(&cfqq->sort_list);
if (rbnext == &last->rb_node)
rbnext = NULL;
@@ -545,13 +517,13 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
* the pending list according to last request service
*/
static inline void
-cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue)
+cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
BUG_ON(cfq_cfqq_on_rr(cfqq));
cfq_mark_cfqq_on_rr(cfqq);
cfqd->busy_queues++;
- cfq_resort_rr_list(cfqq, requeue);
+ cfq_resort_rr_list(cfqq, 0);
}
static inline void
@@ -571,22 +543,19 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
static inline void cfq_del_crq_rb(struct cfq_rq *crq)
{
struct cfq_queue *cfqq = crq->cfq_queue;
+ struct cfq_data *cfqd = cfqq->cfqd;
+ const int sync = cfq_crq_is_sync(crq);
- if (ON_RB(&crq->rb_node)) {
- struct cfq_data *cfqd = cfqq->cfqd;
- const int sync = cfq_crq_is_sync(crq);
+ BUG_ON(!cfqq->queued[sync]);
+ cfqq->queued[sync]--;
- BUG_ON(!cfqq->queued[sync]);
- cfqq->queued[sync]--;
+ cfq_update_next_crq(crq);
- cfq_update_next_crq(crq);
+ rb_erase(&crq->rb_node, &cfqq->sort_list);
+ RB_CLEAR_COLOR(&crq->rb_node);
- rb_erase(&crq->rb_node, &cfqq->sort_list);
- RB_CLEAR_COLOR(&crq->rb_node);
-
- if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list))
- cfq_del_cfqq_rr(cfqd, cfqq);
- }
+ if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list))
+ cfq_del_cfqq_rr(cfqd, cfqq);
}
static struct cfq_rq *
@@ -627,12 +596,12 @@ static void cfq_add_crq_rb(struct cfq_rq *crq)
* if that happens, put the alias on the dispatch list
*/
while ((__alias = __cfq_add_crq_rb(crq)) != NULL)
- cfq_dispatch_sort(cfqd->queue, __alias);
+ cfq_dispatch_insert(cfqd->queue, __alias);
rb_insert_color(&crq->rb_node, &cfqq->sort_list);
if (!cfq_cfqq_on_rr(cfqq))
- cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq));
+ cfq_add_cfqq_rr(cfqd, cfqq);
/*
* check if this request is a better next-serve candidate
@@ -643,10 +612,8 @@ static void cfq_add_crq_rb(struct cfq_rq *crq)
static inline void
cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
{
- if (ON_RB(&crq->rb_node)) {
- rb_erase(&crq->rb_node, &cfqq->sort_list);
- cfqq->queued[cfq_crq_is_sync(crq)]--;
- }
+ rb_erase(&crq->rb_node, &cfqq->sort_list);
+ cfqq->queued[cfq_crq_is_sync(crq)]--;
cfq_add_crq_rb(crq);
}
@@ -676,49 +643,28 @@ out:
return NULL;
}
+static void cfq_activate_request(request_queue_t *q, struct request *rq)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+
+ cfqd->rq_in_driver++;
+}
+
static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_rq *crq = RQ_DATA(rq);
- if (crq) {
- struct cfq_queue *cfqq = crq->cfq_queue;
-
- if (cfq_crq_in_driver(crq)) {
- cfq_clear_crq_in_driver(crq);
- WARN_ON(!cfqd->rq_in_driver);
- cfqd->rq_in_driver--;
- }
- if (cfq_crq_in_flight(crq)) {
- const int sync = cfq_crq_is_sync(crq);
-
- cfq_clear_crq_in_flight(crq);
- WARN_ON(!cfqq->on_dispatch[sync]);
- cfqq->on_dispatch[sync]--;
- }
- cfq_mark_crq_requeued(crq);
- }
+ WARN_ON(!cfqd->rq_in_driver);
+ cfqd->rq_in_driver--;
}
-/*
- * make sure the service time gets corrected on reissue of this request
- */
-static void cfq_requeue_request(request_queue_t *q, struct request *rq)
-{
- cfq_deactivate_request(q, rq);
- list_add(&rq->queuelist, &q->queue_head);
-}
-
-static void cfq_remove_request(request_queue_t *q, struct request *rq)
+static void cfq_remove_request(struct request *rq)
{
struct cfq_rq *crq = RQ_DATA(rq);
- if (crq) {
- list_del_init(&rq->queuelist);
- cfq_del_crq_rb(crq);
- cfq_remove_merge_hints(q, crq);
-
- }
+ list_del_init(&rq->queuelist);
+ cfq_del_crq_rb(crq);
+ cfq_del_crq_hash(crq);
}
static int
@@ -728,12 +674,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
struct request *__rq;
int ret;
- ret = elv_try_last_merge(q, bio);
- if (ret != ELEVATOR_NO_MERGE) {
- __rq = q->last_merge;
- goto out_insert;
- }
-
__rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
if (__rq && elv_rq_merge_ok(__rq, bio)) {
ret = ELEVATOR_BACK_MERGE;
@@ -748,8 +688,6 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
return ELEVATOR_NO_MERGE;
out:
- q->last_merge = __rq;
-out_insert:
*req = __rq;
return ret;
}
@@ -762,14 +700,12 @@ static void cfq_merged_request(request_queue_t *q, struct request *req)
cfq_del_crq_hash(crq);
cfq_add_crq_hash(cfqd, crq);
- if (ON_RB(&crq->rb_node) && (rq_rb_key(req) != crq->rb_key)) {
+ if (rq_rb_key(req) != crq->rb_key) {
struct cfq_queue *cfqq = crq->cfq_queue;
cfq_update_next_crq(crq);
cfq_reposition_crq_rb(cfqq, crq);
}
-
- q->last_merge = req;
}
static void
@@ -785,7 +721,7 @@ cfq_merged_requests(request_queue_t *q, struct request *rq,
time_before(next->start_time, rq->start_time))
list_move(&rq->queuelist, &next->queuelist);
- cfq_remove_request(q, next);
+ cfq_remove_request(next);
}
static inline void
@@ -992,53 +928,15 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
return 1;
}
-/*
- * we dispatch cfqd->cfq_quantum requests in total from the rr_list queues,
- * this function sector sorts the selected request to minimize seeks. we start
- * at cfqd->last_sector, not 0.
- */
-static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq)
+static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_queue *cfqq = crq->cfq_queue;
- struct list_head *head = &q->queue_head, *entry = head;
- struct request *__rq;
- sector_t last;
-
- list_del(&crq->request->queuelist);
-
- last = cfqd->last_sector;
- list_for_each_entry_reverse(__rq, head, queuelist) {
- struct cfq_rq *__crq = RQ_DATA(__rq);
-
- if (blk_barrier_rq(__rq))
- break;
- if (!blk_fs_request(__rq))
- break;
- if (cfq_crq_requeued(__crq))
- break;
-
- if (__rq->sector <= crq->request->sector)
- break;
- if (__rq->sector > last && crq->request->sector < last) {
- last = crq->request->sector + crq->request->nr_sectors;
- break;
- }
- entry = &__rq->queuelist;
- }
-
- cfqd->last_sector = last;
cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq);
-
- cfq_del_crq_rb(crq);
- cfq_remove_merge_hints(q, crq);
-
- cfq_mark_crq_in_flight(crq);
- cfq_clear_crq_requeued(crq);
-
+ cfq_remove_request(crq->request);
cfqq->on_dispatch[cfq_crq_is_sync(crq)]++;
- list_add_tail(&crq->request->queuelist, entry);
+ elv_dispatch_sort(q, crq->request);
}
/*
@@ -1159,7 +1057,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
/*
* finally, insert request into driver dispatch list
*/
- cfq_dispatch_sort(cfqd->queue, crq);
+ cfq_dispatch_insert(cfqd->queue, crq);
cfqd->dispatch_slice++;
dispatched++;
@@ -1194,7 +1092,7 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
}
static int
-cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force)
+cfq_dispatch_requests(request_queue_t *q, int force)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_queue *cfqq;
@@ -1204,12 +1102,25 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force)
cfqq = cfq_select_queue(cfqd, force);
if (cfqq) {
+ int max_dispatch;
+
+ /*
+ * if idle window is disabled, allow queue buildup
+ */
+ if (!cfq_cfqq_idle_window(cfqq) &&
+ cfqd->rq_in_driver >= cfqd->cfq_max_depth)
+ return 0;
+
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_wait_request(cfqq);
del_timer(&cfqd->idle_slice_timer);
- if (cfq_class_idle(cfqq))
- max_dispatch = 1;
+ if (!force) {
+ max_dispatch = cfqd->cfq_quantum;
+ if (cfq_class_idle(cfqq))
+ max_dispatch = 1;
+ } else
+ max_dispatch = INT_MAX;
return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
}
@@ -1217,93 +1128,6 @@ cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force)
return 0;
}
-static inline void cfq_account_dispatch(struct cfq_rq *crq)
-{
- struct cfq_queue *cfqq = crq->cfq_queue;
- struct cfq_data *cfqd = cfqq->cfqd;
-
- if (unlikely(!blk_fs_request(crq->request)))
- return;
-
- /*
- * accounted bit is necessary since some drivers will call
- * elv_next_request() many times for the same request (eg ide)
- */
- if (cfq_crq_in_driver(crq))
- return;
-
- cfq_mark_crq_in_driver(crq);
- cfqd->rq_in_driver++;
-}
-
-static inline void
-cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq)
-{
- struct cfq_data *cfqd = cfqq->cfqd;
- unsigned long now;
-
- if (!cfq_crq_in_driver(crq))
- return;
-
- now = jiffies;
-
- WARN_ON(!cfqd->rq_in_driver);
- cfqd->rq_in_driver--;
-
- if (!cfq_class_idle(cfqq))
- cfqd->last_end_request = now;
-
- if (!cfq_cfqq_dispatched(cfqq)) {
- if (cfq_cfqq_on_rr(cfqq)) {
- cfqq->service_last = now;
- cfq_resort_rr_list(cfqq, 0);
- }
- if (cfq_cfqq_expired(cfqq)) {
- __cfq_slice_expired(cfqd, cfqq, 0);
- cfq_schedule_dispatch(cfqd);
- }
- }
-
- if (cfq_crq_is_sync(crq))
- crq->io_context->last_end_request = now;
-}
-
-static struct request *cfq_next_request(request_queue_t *q)
-{
- struct cfq_data *cfqd = q->elevator->elevator_data;
- struct request *rq;
-
- if (!list_empty(&q->queue_head)) {
- struct cfq_rq *crq;
-dispatch:
- rq = list_entry_rq(q->queue_head.next);
-
- crq = RQ_DATA(rq);
- if (crq) {
- struct cfq_queue *cfqq = crq->cfq_queue;
-
- /*
- * if idle window is disabled, allow queue buildup
- */
- if (!cfq_crq_in_driver(crq) &&
- !cfq_cfqq_idle_window(cfqq) &&
- !blk_barrier_rq(rq) &&
- cfqd->rq_in_driver >= cfqd->cfq_max_depth)
- return NULL;
-
- cfq_remove_merge_hints(q, crq);
- cfq_account_dispatch(crq);
- }
-
- return rq;
- }
-
- if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0))
- goto dispatch;
-
- return NULL;
-}
-
/*
* task holds one reference to the queue, dropped when task exits. each crq
* in-flight on this queue also holds a reference, dropped when crq is freed.
@@ -1422,7 +1246,7 @@ static void cfq_exit_io_context(struct cfq_io_context *cic)
}
static struct cfq_io_context *
-cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask)
+cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
{
struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
@@ -1517,7 +1341,7 @@ static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
static struct cfq_queue *
cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio,
- int gfp_mask)
+ gfp_t gfp_mask)
{
const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
struct cfq_queue *cfqq, *new_cfqq = NULL;
@@ -1578,7 +1402,7 @@ out:
* cfqq, so we don't need to worry about it disappearing
*/
static struct cfq_io_context *
-cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask)
+cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask)
{
struct io_context *ioc = NULL;
struct cfq_io_context *cic;
@@ -1816,8 +1640,9 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
}
}
-static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq)
+static void cfq_insert_request(request_queue_t *q, struct request *rq)
{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_rq *crq = RQ_DATA(rq);
struct cfq_queue *cfqq = crq->cfq_queue;
@@ -1827,66 +1652,43 @@ static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq)
list_add_tail(&rq->queuelist, &cfqq->fifo);
- if (rq_mergeable(rq)) {
+ if (rq_mergeable(rq))
cfq_add_crq_hash(cfqd, crq);
- if (!cfqd->queue->last_merge)
- cfqd->queue->last_merge = rq;
- }
-
cfq_crq_enqueued(cfqd, cfqq, crq);
}
-static void
-cfq_insert_request(request_queue_t *q, struct request *rq, int where)
-{
- struct cfq_data *cfqd = q->elevator->elevator_data;
-
- switch (where) {
- case ELEVATOR_INSERT_BACK:
- while (cfq_dispatch_requests(q, INT_MAX, 1))
- ;
- list_add_tail(&rq->queuelist, &q->queue_head);
- /*
- * If we were idling with pending requests on
- * inactive cfqqs, force dispatching will
- * remove the idle timer and the queue won't
- * be kicked by __make_request() afterward.
- * Kick it here.
- */
- cfq_schedule_dispatch(cfqd);
- break;
- case ELEVATOR_INSERT_FRONT:
- list_add(&rq->queuelist, &q->queue_head);
- break;
- case ELEVATOR_INSERT_SORT:
- BUG_ON(!blk_fs_request(rq));
- cfq_enqueue(cfqd, rq);
- break;
- default:
- printk("%s: bad insert point %d\n", __FUNCTION__,where);
- return;
- }
-}
-
static void cfq_completed_request(request_queue_t *q, struct request *rq)
{
struct cfq_rq *crq = RQ_DATA(rq);
- struct cfq_queue *cfqq;
+ struct cfq_queue *cfqq = crq->cfq_queue;
+ struct cfq_data *cfqd = cfqq->cfqd;
+ const int sync = cfq_crq_is_sync(crq);
+ unsigned long now;
- if (unlikely(!blk_fs_request(rq)))
- return;
+ now = jiffies;
- cfqq = crq->cfq_queue;
+ WARN_ON(!cfqd->rq_in_driver);
+ WARN_ON(!cfqq->on_dispatch[sync]);
+ cfqd->rq_in_driver--;
+ cfqq->on_dispatch[sync]--;
- if (cfq_crq_in_flight(crq)) {
- const int sync = cfq_crq_is_sync(crq);
+ if (!cfq_class_idle(cfqq))
+ cfqd->last_end_request = now;
- WARN_ON(!cfqq->on_dispatch[sync]);
- cfqq->on_dispatch[sync]--;
+ if (!cfq_cfqq_dispatched(cfqq)) {
+ if (cfq_cfqq_on_rr(cfqq)) {
+ cfqq->service_last = now;
+ cfq_resort_rr_list(cfqq, 0);
+ }
+ if (cfq_cfqq_expired(cfqq)) {
+ __cfq_slice_expired(cfqd, cfqq, 0);
+ cfq_schedule_dispatch(cfqd);
+ }
}
- cfq_account_completion(cfqq, crq);
+ if (cfq_crq_is_sync(crq))
+ crq->io_context->last_end_request = now;
}
static struct request *
@@ -2075,7 +1877,7 @@ static void cfq_put_request(request_queue_t *q, struct request *rq)
*/
static int
cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
- int gfp_mask)
+ gfp_t gfp_mask)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct task_struct *tsk = current;
@@ -2118,9 +1920,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
INIT_HLIST_NODE(&crq->hash);
crq->cfq_queue = cfqq;
crq->io_context = cic;
- cfq_clear_crq_in_flight(crq);
- cfq_clear_crq_in_driver(crq);
- cfq_clear_crq_requeued(crq);
if (rw == READ || process_sync(tsk))
cfq_mark_crq_is_sync(crq);
@@ -2201,7 +2000,7 @@ static void cfq_idle_slice_timer(unsigned long data)
* only expire and reinvoke request handler, if there are
* other queues with pending requests
*/
- if (!cfq_pending_requests(cfqd)) {
+ if (!cfqd->busy_queues) {
cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end);
add_timer(&cfqd->idle_slice_timer);
goto out_cont;
@@ -2576,10 +2375,9 @@ static struct elevator_type iosched_cfq = {
.elevator_merge_fn = cfq_merge,
.elevator_merged_fn = cfq_merged_request,
.elevator_merge_req_fn = cfq_merged_requests,
- .elevator_next_req_fn = cfq_next_request,
+ .elevator_dispatch_fn = cfq_dispatch_requests,
.elevator_add_req_fn = cfq_insert_request,
- .elevator_remove_req_fn = cfq_remove_request,
- .elevator_requeue_req_fn = cfq_requeue_request,
+ .elevator_activate_req_fn = cfq_activate_request,
.elevator_deactivate_req_fn = cfq_deactivate_request,
.elevator_queue_empty_fn = cfq_queue_empty,
.elevator_completed_req_fn = cfq_completed_request,
diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
index 52a3ae5289a0..7929471d7df7 100644
--- a/drivers/block/deadline-iosched.c
+++ b/drivers/block/deadline-iosched.c
@@ -50,7 +50,6 @@ struct deadline_data {
* next in sort order. read, write or both are NULL
*/
struct deadline_rq *next_drq[2];
- struct list_head *dispatch; /* driver dispatch queue */
struct list_head *hash; /* request hash */
unsigned int batching; /* number of sequential requests made */
sector_t last_sector; /* head position */
@@ -113,15 +112,6 @@ static inline void deadline_del_drq_hash(struct deadline_rq *drq)
__deadline_del_drq_hash(drq);
}
-static void
-deadline_remove_merge_hints(request_queue_t *q, struct deadline_rq *drq)
-{
- deadline_del_drq_hash(drq);
-
- if (q->last_merge == drq->request)
- q->last_merge = NULL;
-}
-
static inline void
deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq)
{
@@ -239,10 +229,9 @@ deadline_del_drq_rb(struct deadline_data *dd, struct deadline_rq *drq)
dd->next_drq[data_dir] = rb_entry_drq(rbnext);
}
- if (ON_RB(&drq->rb_node)) {
- rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq));
- RB_CLEAR(&drq->rb_node);
- }
+ BUG_ON(!ON_RB(&drq->rb_node));
+ rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq));
+ RB_CLEAR(&drq->rb_node);
}
static struct request *
@@ -286,7 +275,7 @@ deadline_find_first_drq(struct deadline_data *dd, int data_dir)
/*
* add drq to rbtree and fifo
*/
-static inline void
+static void
deadline_add_request(struct request_queue *q, struct request *rq)
{
struct deadline_data *dd = q->elevator->elevator_data;
@@ -301,12 +290,8 @@ deadline_add_request(struct request_queue *q, struct request *rq)
drq->expires = jiffies + dd->fifo_expire[data_dir];
list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]);
- if (rq_mergeable(rq)) {
+ if (rq_mergeable(rq))
deadline_add_drq_hash(dd, drq);
-
- if (!q->last_merge)
- q->last_merge = rq;
- }
}
/*
@@ -315,14 +300,11 @@ deadline_add_request(struct request_queue *q, struct request *rq)
static void deadline_remove_request(request_queue_t *q, struct request *rq)
{
struct deadline_rq *drq = RQ_DATA(rq);
+ struct deadline_data *dd = q->elevator->elevator_data;
- if (drq) {
- struct deadline_data *dd = q->elevator->elevator_data;
-
- list_del_init(&drq->fifo);
- deadline_remove_merge_hints(q, drq);
- deadline_del_drq_rb(dd, drq);
- }
+ list_del_init(&drq->fifo);
+ deadline_del_drq_rb(dd, drq);
+ deadline_del_drq_hash(drq);
}
static int
@@ -332,15 +314,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
struct request *__rq;
int ret;
- /*
- * try last_merge to avoid going to hash
- */
- ret = elv_try_last_merge(q, bio);
- if (ret != ELEVATOR_NO_MERGE) {
- __rq = q->last_merge;
- goto out_insert;
- }
-
/*
* see if the merge hash can satisfy a back merge
*/
@@ -373,8 +346,6 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
return ELEVATOR_NO_MERGE;
out:
- q->last_merge = __rq;
-out_insert:
if (ret)
deadline_hot_drq_hash(dd, RQ_DATA(__rq));
*req = __rq;
@@ -399,8 +370,6 @@ static void deadline_merged_request(request_queue_t *q, struct request *req)
deadline_del_drq_rb(dd, drq);
deadline_add_drq_rb(dd, drq);
}
-
- q->last_merge = req;
}
static void
@@ -452,7 +421,7 @@ deadline_move_to_dispatch(struct deadline_data *dd, struct deadline_rq *drq)
request_queue_t *q = drq->request->q;
deadline_remove_request(q, drq->request);
- list_add_tail(&drq->request->queuelist, dd->dispatch);
+ elv_dispatch_add_tail(q, drq->request);
}
/*
@@ -502,8 +471,9 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
* deadline_dispatch_requests selects the best request according to
* read/write expire, fifo_batch, etc
*/
-static int deadline_dispatch_requests(struct deadline_data *dd)
+static int deadline_dispatch_requests(request_queue_t *q, int force)
{
+ struct deadline_data *dd = q->elevator->elevator_data;
const int reads = !list_empty(&dd->fifo_list[READ]);
const int writes = !list_empty(&dd->fifo_list[WRITE]);
struct deadline_rq *drq;
@@ -597,65 +567,12 @@ dispatch_request:
return 1;
}
-static struct request *deadline_next_request(request_queue_t *q)
-{
- struct deadline_data *dd = q->elevator->elevator_data;
- struct request *rq;
-
- /*
- * if there are still requests on the dispatch queue, grab the first one
- */
- if (!list_empty(dd->dispatch)) {
-dispatch:
- rq = list_entry_rq(dd->dispatch->next);
- return rq;
- }
-
- if (deadline_dispatch_requests(dd))
- goto dispatch;
-
- return NULL;
-}
-
-static void
-deadline_insert_request(request_queue_t *q, struct request *rq, int where)
-{
- struct deadline_data *dd = q->elevator->elevator_data;
-
- /* barriers must flush the reorder queue */
- if (unlikely(rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)
- && where == ELEVATOR_INSERT_SORT))
- where = ELEVATOR_INSERT_BACK;
-
- switch (where) {
- case ELEVATOR_INSERT_BACK:
- while (deadline_dispatch_requests(dd))
- ;
- list_add_tail(&rq->queuelist, dd->dispatch);
- break;
- case ELEVATOR_INSERT_FRONT:
- list_add(&rq->queuelist, dd->dispatch);
- break;
- case ELEVATOR_INSERT_SORT:
- BUG_ON(!blk_fs_request(rq));
- deadline_add_request(q, rq);
- break;
- default:
- printk("%s: bad insert point %d\n", __FUNCTION__,where);
- return;
- }
-}
-
static int deadline_queue_empty(request_queue_t *q)
{
struct deadline_data *dd = q->elevator->elevator_data;
- if (!list_empty(&dd->fifo_list[WRITE])
- || !list_empty(&dd->fifo_list[READ])
- || !list_empty(dd->dispatch))
- return 0;
-
- return 1;
+ return list_empty(&dd->fifo_list[WRITE])
+ && list_empty(&dd->fifo_list[READ]);
}
static struct request *
@@ -733,7 +650,6 @@ static int deadline_init_queue(request_queue_t *q, elevator_t *e)
INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
dd->sort_list[READ] = RB_ROOT;
dd->sort_list[WRITE] = RB_ROOT;
- dd->dispatch = &q->queue_head;
dd->fifo_expire[READ] = read_expire;
dd->fifo_expire[WRITE] = write_expire;
dd->writes_starved = writes_starved;
@@ -748,15 +664,13 @@ static void deadline_put_request(request_queue_t *q, struct request *rq)
struct deadline_data *dd = q->elevator->elevator_data;
struct deadline_rq *drq = RQ_DATA(rq);
- if (drq) {
- mempool_free(drq, dd->drq_pool);
- rq->elevator_private = NULL;
- }
+ mempool_free(drq, dd->drq_pool);
+ rq->elevator_private = NULL;
}
static int
deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
- int gfp_mask)
+ gfp_t gfp_mask)
{
struct deadline_data *dd = q->elevator->elevator_data;
struct deadline_rq *drq;
@@ -917,9 +831,8 @@ static struct elevator_type iosched_deadline = {
.elevator_merge_fn = deadline_merge,
.elevator_merged_fn = deadline_merged_request,
.elevator_merge_req_fn = deadline_merged_requests,
- .elevator_next_req_fn = deadline_next_request,
- .elevator_add_req_fn = deadline_insert_request,
- .elevator_remove_req_fn = deadline_remove_request,
+ .elevator_dispatch_fn = deadline_dispatch_requests,
+ .elevator_add_req_fn = deadline_add_request,
.elevator_queue_empty_fn = deadline_queue_empty,
.elevator_former_req_fn = deadline_former_request,
.elevator_latter_req_fn = deadline_latter_request,
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index 98f0126a2deb..55621d5c5774 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
@@ -83,21 +84,11 @@ inline int elv_try_merge(struct request *__rq, struct bio *bio)
}
EXPORT_SYMBOL(elv_try_merge);
-inline int elv_try_last_merge(request_queue_t *q, struct bio *bio)
-{
- if (q->last_merge)
- return elv_try_merge(q->last_merge, bio);
-
- return ELEVATOR_NO_MERGE;
-}
-EXPORT_SYMBOL(elv_try_last_merge);
-
static struct elevator_type *elevator_find(const char *name)
{
struct elevator_type *e = NULL;
struct list_head *entry;
- spin_lock_irq(&elv_list_lock);
list_for_each(entry, &elv_list) {
struct elevator_type *__e;
@@ -108,7 +99,6 @@ static struct elevator_type *elevator_find(const char *name)
break;
}
}
- spin_unlock_irq(&elv_list_lock);
return e;
}
@@ -120,12 +110,15 @@ static void elevator_put(struct elevator_type *e)
static struct elevator_type *elevator_get(const char *name)
{
- struct elevator_type *e = elevator_find(name);
+ struct elevator_type *e;
- if (!e)
- return NULL;
- if (!try_module_get(e->elevator_owner))
- return NULL;
+ spin_lock_irq(&elv_list_lock);
+
+ e = elevator_find(name);
+ if (e && !try_module_get(e->elevator_owner))
+ e = NULL;
+
+ spin_unlock_irq(&elv_list_lock);
return e;
}
@@ -139,8 +132,6 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e,
eq->ops = &e->ops;
eq->elevator_type = e;
- INIT_LIST_HEAD(&q->queue_head);
- q->last_merge = NULL;
q->elevator = eq;
if (eq->ops->elevator_init_fn)
@@ -153,11 +144,15 @@ static char chosen_elevator[16];
static void elevator_setup_default(void)
{
+ struct elevator_type *e;
+
/*
* check if default is set and exists
*/
- if (chosen_elevator[0] && elevator_find(chosen_elevator))
+ if (chosen_elevator[0] && (e = elevator_get(chosen_elevator))) {
+ elevator_put(e);
return;
+ }
#if defined(CONFIG_IOSCHED_AS)
strcpy(chosen_elevator, "anticipatory");
@@ -186,6 +181,11 @@ int elevator_init(request_queue_t *q, char *name)
struct elevator_queue *eq;
int ret = 0;
+ INIT_LIST_HEAD(&q->queue_head);
+ q->last_merge = NULL;
+ q->end_sector = 0;
+ q->boundary_rq = NULL;
+
elevator_setup_default();
if (!name)
@@ -220,9 +220,52 @@ void elevator_exit(elevator_t *e)
kfree(e);
}
+/*
+ * Insert rq into dispatch queue of q. Queue lock must be held on
+ * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be
+ * appended to the dispatch queue. To be used by specific elevators.
+ */
+void elv_dispatch_sort(request_queue_t *q, struct request *rq)
+{
+ sector_t boundary;
+ struct list_head *entry;
+
+ if (q->last_merge == rq)
+ q->last_merge = NULL;
+
+ boundary = q->end_sector;
+
+ list_for_each_prev(entry, &q->queue_head) {
+ struct request *pos = list_entry_rq(entry);
+
+ if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED))
+ break;
+ if (rq->sector >= boundary) {
+ if (pos->sector < boundary)
+ continue;
+ } else {
+ if (pos->sector >= boundary)
+ break;
+ }
+ if (rq->sector >= pos->sector)
+ break;
+ }
+
+ list_add(&rq->queuelist, entry);
+}
+
int elv_merge(request_queue_t *q, struct request **req, struct bio *bio)
{
elevator_t *e = q->elevator;
+ int ret;
+
+ if (q->last_merge) {
+ ret = elv_try_merge(q->last_merge, bio);
+ if (ret != ELEVATOR_NO_MERGE) {
+ *req = q->last_merge;
+ return ret;
+ }
+ }
if (e->ops->elevator_merge_fn)
return e->ops->elevator_merge_fn(q, req, bio);
@@ -236,6 +279,8 @@ void elv_merged_request(request_queue_t *q, struct request *rq)
if (e->ops->elevator_merged_fn)
e->ops->elevator_merged_fn(q, rq);
+
+ q->last_merge = rq;
}
void elv_merge_requests(request_queue_t *q, struct request *rq,
@@ -243,20 +288,13 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
{
elevator_t *e = q->elevator;
- if (q->last_merge == next)
- q->last_merge = NULL;
-
if (e->ops->elevator_merge_req_fn)
e->ops->elevator_merge_req_fn(q, rq, next);
+
+ q->last_merge = rq;
}
-/*
- * For careful internal use by the block layer. Essentially the same as
- * a requeue in that it tells the io scheduler that this request is not
- * active in the driver or hardware anymore, but we don't want the request
- * added back to the scheduler. Function is not exported.
- */
-void elv_deactivate_request(request_queue_t *q, struct request *rq)
+void elv_requeue_request(request_queue_t *q, struct request *rq)
{
elevator_t *e = q->elevator;
@@ -264,19 +302,14 @@ void elv_deactivate_request(request_queue_t *q, struct request *rq)
* it already went through dequeue, we need to decrement the
* in_flight count again
*/
- if (blk_account_rq(rq))
+ if (blk_account_rq(rq)) {
q->in_flight--;
+ if (blk_sorted_rq(rq) && e->ops->elevator_deactivate_req_fn)
+ e->ops->elevator_deactivate_req_fn(q, rq);
+ }
rq->flags &= ~REQ_STARTED;
- if (e->ops->elevator_deactivate_req_fn)
- e->ops->elevator_deactivate_req_fn(q, rq);
-}
-
-void elv_requeue_request(request_queue_t *q, struct request *rq)
-{
- elv_deactivate_request(q, rq);
-
/*
* if this is the flush, requeue the original instead and drop the flush
*/
@@ -285,31 +318,27 @@ void elv_requeue_request(request_queue_t *q, struct request *rq)
rq = rq->end_io_data;
}
- /*
- * the request is prepped and may have some resources allocated.
- * allowing unprepped requests to pass this one may cause resource
- * deadlock. turn on softbarrier.
- */
- rq->flags |= REQ_SOFTBARRIER;
-
- /*
- * if iosched has an explicit requeue hook, then use that. otherwise
- * just put the request at the front of the queue
- */
- if (q->elevator->ops->elevator_requeue_req_fn)
- q->elevator->ops->elevator_requeue_req_fn(q, rq);
- else
- __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0);
+ __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0);
}
void __elv_add_request(request_queue_t *q, struct request *rq, int where,
int plug)
{
- /*
- * barriers implicitly indicate back insertion
- */
- if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) &&
- where == ELEVATOR_INSERT_SORT)
+ if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
+ /*
+ * barriers implicitly indicate back insertion
+ */
+ if (where == ELEVATOR_INSERT_SORT)
+ where = ELEVATOR_INSERT_BACK;
+
+ /*
+ * this request is scheduling boundary, update end_sector
+ */
+ if (blk_fs_request(rq)) {
+ q->end_sector = rq_end_sector(rq);
+ q->boundary_rq = rq;
+ }
+ } else if (!(rq->flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT)
where = ELEVATOR_INSERT_BACK;
if (plug)
@@ -317,23 +346,54 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where,
rq->q = q;
- if (!test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) {
- q->elevator->ops->elevator_add_req_fn(q, rq, where);
+ switch (where) {
+ case ELEVATOR_INSERT_FRONT:
+ rq->flags |= REQ_SOFTBARRIER;
- if (blk_queue_plugged(q)) {
- int nrq = q->rq.count[READ] + q->rq.count[WRITE]
- - q->in_flight;
+ list_add(&rq->queuelist, &q->queue_head);
+ break;
- if (nrq >= q->unplug_thresh)
- __generic_unplug_device(q);
- }
- } else
+ case ELEVATOR_INSERT_BACK:
+ rq->flags |= REQ_SOFTBARRIER;
+
+ while (q->elevator->ops->elevator_dispatch_fn(q, 1))
+ ;
+ list_add_tail(&rq->queuelist, &q->queue_head);
/*
- * if drain is set, store the request "locally". when the drain
- * is finished, the requests will be handed ordered to the io
- * scheduler
+ * We kick the queue here for the following reasons.
+ * - The elevator might have returned NULL previously
+ * to delay requests and returned them now. As the
+ * queue wasn't empty before this request, ll_rw_blk
+ * won't run the queue on return, resulting in hang.
+ * - Usually, back inserted requests won't be merged
+ * with anything. There's no point in delaying queue
+ * processing.
*/
- list_add_tail(&rq->queuelist, &q->drain_list);
+ blk_remove_plug(q);
+ q->request_fn(q);
+ break;
+
+ case ELEVATOR_INSERT_SORT:
+ BUG_ON(!blk_fs_request(rq));
+ rq->flags |= REQ_SORTED;
+ q->elevator->ops->elevator_add_req_fn(q, rq);
+ if (q->last_merge == NULL && rq_mergeable(rq))
+ q->last_merge = rq;
+ break;
+
+ default:
+ printk(KERN_ERR "%s: bad insertion point %d\n",
+ __FUNCTION__, where);
+ BUG();
+ }
+
+ if (blk_queue_plugged(q)) {
+ int nrq = q->rq.count[READ] + q->rq.count[WRITE]
+ - q->in_flight;
+
+ if (nrq >= q->unplug_thresh)
+ __generic_unplug_device(q);
+ }
}
void elv_add_request(request_queue_t *q, struct request *rq, int where,
@@ -348,13 +408,19 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where,
static inline struct request *__elv_next_request(request_queue_t *q)
{
- struct request *rq = q->elevator->ops->elevator_next_req_fn(q);
+ struct request *rq;
+
+ if (unlikely(list_empty(&q->queue_head) &&
+ !q->elevator->ops->elevator_dispatch_fn(q, 0)))
+ return NULL;
+
+ rq = list_entry_rq(q->queue_head.next);
/*
* if this is a barrier write and the device has to issue a
* flush sequence to support it, check how far we are
*/
- if (rq && blk_fs_request(rq) && blk_barrier_rq(rq)) {
+ if (blk_fs_request(rq) && blk_barrier_rq(rq)) {
BUG_ON(q->ordered == QUEUE_ORDERED_NONE);
if (q->ordered == QUEUE_ORDERED_FLUSH &&
@@ -371,15 +437,30 @@ struct request *elv_next_request(request_queue_t *q)
int ret;
while ((rq = __elv_next_request(q)) != NULL) {
- /*
- * just mark as started even if we don't start it, a request
- * that has been delayed should not be passed by new incoming
- * requests
- */
- rq->flags |= REQ_STARTED;
+ if (!(rq->flags & REQ_STARTED)) {
+ elevator_t *e = q->elevator;
- if (rq == q->last_merge)
- q->last_merge = NULL;
+ /*
+ * This is the first time the device driver
+ * sees this request (possibly after
+ * requeueing). Notify IO scheduler.
+ */
+ if (blk_sorted_rq(rq) &&
+ e->ops->elevator_activate_req_fn)
+ e->ops->elevator_activate_req_fn(q, rq);
+
+ /*
+ * just mark as started even if we don't start
+ * it, a request that has been delayed should
+ * not be passed by new incoming requests
+ */
+ rq->flags |= REQ_STARTED;
+ }
+
+ if (!q->boundary_rq || q->boundary_rq == rq) {
+ q->end_sector = rq_end_sector(rq);
+ q->boundary_rq = NULL;
+ }
if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn)
break;
@@ -391,9 +472,9 @@ struct request *elv_next_request(request_queue_t *q)
/*
* the request may have been (partially) prepped.
* we need to keep this request in the front to
- * avoid resource deadlock. turn on softbarrier.
+ * avoid resource deadlock. REQ_STARTED will
+ * prevent other fs requests from passing this one.
*/
- rq->flags |= REQ_SOFTBARRIER;
rq = NULL;
break;
} else if (ret == BLKPREP_KILL) {
@@ -416,42 +497,32 @@ struct request *elv_next_request(request_queue_t *q)
return rq;
}
-void elv_remove_request(request_queue_t *q, struct request *rq)
+void elv_dequeue_request(request_queue_t *q, struct request *rq)
{
- elevator_t *e = q->elevator;
+ BUG_ON(list_empty(&rq->queuelist));
+
+ list_del_init(&rq->queuelist);
/*
* the time frame between a request being removed from the lists
* and to it is freed is accounted as io that is in progress at
- * the driver side. note that we only account requests that the
- * driver has seen (REQ_STARTED set), to avoid false accounting
- * for request-request merges
+ * the driver side.
*/
if (blk_account_rq(rq))
q->in_flight++;
-
- /*
- * the main clearing point for q->last_merge is on retrieval of
- * request by driver (it calls elv_next_request()), but it _can_
- * also happen here if a request is added to the queue but later
- * deleted without ever being given to driver (merged with another
- * request).
- */
- if (rq == q->last_merge)
- q->last_merge = NULL;
-
- if (e->ops->elevator_remove_req_fn)
- e->ops->elevator_remove_req_fn(q, rq);
}
int elv_queue_empty(request_queue_t *q)
{
elevator_t *e = q->elevator;
+ if (!list_empty(&q->queue_head))
+ return 0;
+
if (e->ops->elevator_queue_empty_fn)
return e->ops->elevator_queue_empty_fn(q);
- return list_empty(&q->queue_head);
+ return 1;
}
struct request *elv_latter_request(request_queue_t *q, struct request *rq)
@@ -487,7 +558,7 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
}
int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
- int gfp_mask)
+ gfp_t gfp_mask)
{
elevator_t *e = q->elevator;
@@ -523,11 +594,11 @@ void elv_completed_request(request_queue_t *q, struct request *rq)
/*
* request is released from the driver, io must be done
*/
- if (blk_account_rq(rq))
+ if (blk_account_rq(rq)) {
q->in_flight--;
-
- if (e->ops->elevator_completed_req_fn)
- e->ops->elevator_completed_req_fn(q, rq);
+ if (blk_sorted_rq(rq) && e->ops->elevator_completed_req_fn)
+ e->ops->elevator_completed_req_fn(q, rq);
+ }
}
int elv_register_queue(struct request_queue *q)
@@ -555,10 +626,9 @@ void elv_unregister_queue(struct request_queue *q)
int elv_register(struct elevator_type *e)
{
+ spin_lock_irq(&elv_list_lock);
if (elevator_find(e->elevator_name))
BUG();
-
- spin_lock_irq(&elv_list_lock);
list_add_tail(&e->list, &elv_list);
spin_unlock_irq(&elv_list_lock);
@@ -582,25 +652,36 @@ EXPORT_SYMBOL_GPL(elv_unregister);
* switch to new_e io scheduler. be careful not to introduce deadlocks -
* we don't free the old io scheduler, before we have allocated what we
* need for the new one. this way we have a chance of going back to the old
- * one, if the new one fails init for some reason. we also do an intermediate
- * switch to noop to ensure safety with stack-allocated requests, since they
- * don't originate from the block layer allocator. noop is safe here, because
- * it never needs to touch the elevator itself for completion events. DRAIN
- * flags will make sure we don't touch it for additions either.
+ * one, if the new one fails init for some reason.
*/
static void elevator_switch(request_queue_t *q, struct elevator_type *new_e)
{
- elevator_t *e = kmalloc(sizeof(elevator_t), GFP_KERNEL);
- struct elevator_type *noop_elevator = NULL;
- elevator_t *old_elevator;
+ elevator_t *old_elevator, *e;
+ /*
+ * Allocate new elevator
+ */
+ e = kmalloc(sizeof(elevator_t), GFP_KERNEL);
if (!e)
goto error;
/*
- * first step, drain requests from the block freelist
+ * Turn on BYPASS and drain all requests w/ elevator private data
*/
- blk_wait_queue_drained(q, 0);
+ spin_lock_irq(q->queue_lock);
+
+ set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
+
+ while (q->elevator->ops->elevator_dispatch_fn(q, 1))
+ ;
+
+ while (q->rq.elvpriv) {
+ spin_unlock_irq(q->queue_lock);
+ msleep(10);
+ spin_lock_irq(q->queue_lock);
+ }
+
+ spin_unlock_irq(q->queue_lock);
/*
* unregister old elevator data
@@ -608,18 +689,6 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e)
elv_unregister_queue(q);
old_elevator = q->elevator;
- /*
- * next step, switch to noop since it uses no private rq structures
- * and doesn't allocate any memory for anything. then wait for any
- * non-fs requests in-flight
- */
- noop_elevator = elevator_get("noop");
- spin_lock_irq(q->queue_lock);
- elevator_attach(q, noop_elevator, e);
- spin_unlock_irq(q->queue_lock);
-
- blk_wait_queue_drained(q, 1);
-
/*
* attach and start new elevator
*/
@@ -630,11 +699,10 @@ static void elevator_switch(request_queue_t *q, struct elevator_type *new_e)
goto fail_register;
/*
- * finally exit old elevator and start queue again
+ * finally exit old elevator and turn off BYPASS.
*/
elevator_exit(old_elevator);
- blk_finish_queue_drain(q);
- elevator_put(noop_elevator);
+ clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
return;
fail_register:
@@ -643,13 +711,13 @@ fail_register:
* one again (along with re-adding the sysfs dir)
*/
elevator_exit(e);
+ e = NULL;
fail:
q->elevator = old_elevator;
elv_register_queue(q);
- blk_finish_queue_drain(q);
+ clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
+ kfree(e);
error:
- if (noop_elevator)
- elevator_put(noop_elevator);
elevator_put(new_e);
printk(KERN_ERR "elevator: switch to %s failed\n",new_e->elevator_name);
}
@@ -701,11 +769,12 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
return len;
}
+EXPORT_SYMBOL(elv_dispatch_sort);
EXPORT_SYMBOL(elv_add_request);
EXPORT_SYMBOL(__elv_add_request);
EXPORT_SYMBOL(elv_requeue_request);
EXPORT_SYMBOL(elv_next_request);
-EXPORT_SYMBOL(elv_remove_request);
+EXPORT_SYMBOL(elv_dequeue_request);
EXPORT_SYMBOL(elv_queue_empty);
EXPORT_SYMBOL(elv_completed_request);
EXPORT_SYMBOL(elevator_exit);
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index baedac522945..0af73512b9a8 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -263,8 +263,6 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
blk_queue_activity_fn(q, NULL, NULL);
-
- INIT_LIST_HEAD(&q->drain_list);
}
EXPORT_SYMBOL(blk_queue_make_request);
@@ -353,6 +351,8 @@ static void blk_pre_flush_end_io(struct request *flush_rq)
struct request *rq = flush_rq->end_io_data;
request_queue_t *q = rq->q;
+ elv_completed_request(q, flush_rq);
+
rq->flags |= REQ_BAR_PREFLUSH;
if (!flush_rq->errors)
@@ -369,6 +369,8 @@ static void blk_post_flush_end_io(struct request *flush_rq)
struct request *rq = flush_rq->end_io_data;
request_queue_t *q = rq->q;
+ elv_completed_request(q, flush_rq);
+
rq->flags |= REQ_BAR_POSTFLUSH;
q->end_flush_fn(q, flush_rq);
@@ -408,8 +410,6 @@ struct request *blk_start_pre_flush(request_queue_t *q, struct request *rq)
if (!list_empty(&rq->queuelist))
blkdev_dequeue_request(rq);
- elv_deactivate_request(q, rq);
-
flush_rq->end_io_data = rq;
flush_rq->end_io = blk_pre_flush_end_io;
@@ -1040,6 +1040,7 @@ EXPORT_SYMBOL(blk_queue_invalidate_tags);
static char *rq_flags[] = {
"REQ_RW",
"REQ_FAILFAST",
+ "REQ_SORTED",
"REQ_SOFTBARRIER",
"REQ_HARDBARRIER",
"REQ_CMD",
@@ -1047,6 +1048,7 @@ static char *rq_flags[] = {
"REQ_STARTED",
"REQ_DONTPREP",
"REQ_QUEUED",
+ "REQ_ELVPRIV",
"REQ_PC",
"REQ_BLOCK_PC",
"REQ_SENSE",
@@ -1637,9 +1639,9 @@ static int blk_init_free_list(request_queue_t *q)
rl->count[READ] = rl->count[WRITE] = 0;
rl->starved[READ] = rl->starved[WRITE] = 0;
+ rl->elvpriv = 0;
init_waitqueue_head(&rl->wait[READ]);
init_waitqueue_head(&rl->wait[WRITE]);
- init_waitqueue_head(&rl->drain);
rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
mempool_free_slab, request_cachep, q->node);
@@ -1652,13 +1654,13 @@ static int blk_init_free_list(request_queue_t *q)
static int __make_request(request_queue_t *, struct bio *);
-request_queue_t *blk_alloc_queue(int gfp_mask)
+request_queue_t *blk_alloc_queue(gfp_t gfp_mask)
{
return blk_alloc_queue_node(gfp_mask, -1);
}
EXPORT_SYMBOL(blk_alloc_queue);
-request_queue_t *blk_alloc_queue_node(int gfp_mask, int node_id)
+request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
{
request_queue_t *q;
@@ -1782,12 +1784,14 @@ EXPORT_SYMBOL(blk_get_queue);
static inline void blk_free_request(request_queue_t *q, struct request *rq)
{
- elv_put_request(q, rq);
+ if (rq->flags & REQ_ELVPRIV)
+ elv_put_request(q, rq);
mempool_free(rq, q->rq.rq_pool);
}
static inline struct request *
-blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask)
+blk_alloc_request(request_queue_t *q, int rw, struct bio *bio,
+ int priv, gfp_t gfp_mask)
{
struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
@@ -1800,11 +1804,15 @@ blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask)
*/
rq->flags = rw;
- if (!elv_set_request(q, rq, bio, gfp_mask))
- return rq;
+ if (priv) {
+ if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) {
+ mempool_free(rq, q->rq.rq_pool);
+ return NULL;
+ }
+ rq->flags |= REQ_ELVPRIV;
+ }
- mempool_free(rq, q->rq.rq_pool);
- return NULL;
+ return rq;
}
/*
@@ -1860,22 +1868,18 @@ static void __freed_request(request_queue_t *q, int rw)
* A request has just been released. Account for it, update the full and
* congestion status, wake up any waiters. Called under q->queue_lock.
*/
-static void freed_request(request_queue_t *q, int rw)
+static void freed_request(request_queue_t *q, int rw, int priv)
{
struct request_list *rl = &q->rq;
rl->count[rw]--;
+ if (priv)
+ rl->elvpriv--;
__freed_request(q, rw);
if (unlikely(rl->starved[rw ^ 1]))
__freed_request(q, rw ^ 1);
-
- if (!rl->count[READ] && !rl->count[WRITE]) {
- smp_mb();
- if (unlikely(waitqueue_active(&rl->drain)))
- wake_up(&rl->drain);
- }
}
#define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist)
@@ -1885,14 +1889,12 @@ static void freed_request(request_queue_t *q, int rw)
* Returns !NULL on success, with queue_lock *not held*.
*/
static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
- int gfp_mask)
+ gfp_t gfp_mask)
{
struct request *rq = NULL;
struct request_list *rl = &q->rq;
struct io_context *ioc = current_io_context(GFP_ATOMIC);
-
- if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)))
- goto out;
+ int priv;
if (rl->count[rw]+1 >= q->nr_requests) {
/*
@@ -1937,9 +1939,14 @@ get_rq:
rl->starved[rw] = 0;
if (rl->count[rw] >= queue_congestion_on_threshold(q))
set_queue_congested(q, rw);
+
+ priv = !test_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
+ if (priv)
+ rl->elvpriv++;
+
spin_unlock_irq(q->queue_lock);
- rq = blk_alloc_request(q, rw, bio, gfp_mask);
+ rq = blk_alloc_request(q, rw, bio, priv, gfp_mask);
if (!rq) {
/*
* Allocation failed presumably due to memory. Undo anything
@@ -1949,7 +1956,7 @@ get_rq:
* wait queue, but this is pretty rare.
*/
spin_lock_irq(q->queue_lock);
- freed_request(q, rw);
+ freed_request(q, rw, priv);
/*
* in the very unlikely event that allocation failed and no
@@ -2019,7 +2026,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw,
return rq;
}
-struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask)
+struct request *blk_get_request(request_queue_t *q, int rw, gfp_t gfp_mask)
{
struct request *rq;
@@ -2251,7 +2258,7 @@ EXPORT_SYMBOL(blk_rq_unmap_user);
* @gfp_mask: memory allocation flags
*/
int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf,
- unsigned int len, unsigned int gfp_mask)
+ unsigned int len, gfp_t gfp_mask)
{
struct bio *bio;
@@ -2433,13 +2440,15 @@ void disk_round_stats(struct gendisk *disk)
{
unsigned long now = jiffies;
- __disk_stat_add(disk, time_in_queue,
- disk->in_flight * (now - disk->stamp));
- disk->stamp = now;
+ if (now == disk->stamp)
+ return;
- if (disk->in_flight)
- __disk_stat_add(disk, io_ticks, (now - disk->stamp_idle));
- disk->stamp_idle = now;
+ if (disk->in_flight) {
+ __disk_stat_add(disk, time_in_queue,
+ disk->in_flight * (now - disk->stamp));
+ __disk_stat_add(disk, io_ticks, (now - disk->stamp));
+ }
+ disk->stamp = now;
}
/*
@@ -2454,6 +2463,8 @@ static void __blk_put_request(request_queue_t *q, struct request *req)
if (unlikely(--req->ref_count))
return;
+ elv_completed_request(q, req);
+
req->rq_status = RQ_INACTIVE;
req->rl = NULL;
@@ -2463,26 +2474,25 @@ static void __blk_put_request(request_queue_t *q, struct request *req)
*/
if (rl) {
int rw = rq_data_dir(req);
-
- elv_completed_request(q, req);
+ int priv = req->flags & REQ_ELVPRIV;
BUG_ON(!list_empty(&req->queuelist));
blk_free_request(q, req);
- freed_request(q, rw);
+ freed_request(q, rw, priv);
}
}
void blk_put_request(struct request *req)
{
- /*
- * if req->rl isn't set, this request didnt originate from the
- * block layer, so it's safe to just disregard it
- */
- if (req->rl) {
- unsigned long flags;
- request_queue_t *q = req->q;
+ unsigned long flags;
+ request_queue_t *q = req->q;
+ /*
+ * Gee, IDE calls in w/ NULL q. Fix IDE and remove the
+ * following if (q) test.
+ */
+ if (q) {
spin_lock_irqsave(q->queue_lock, flags);
__blk_put_request(q, req);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -2797,97 +2807,6 @@ static inline void blk_partition_remap(struct bio *bio)
}
}
-void blk_finish_queue_drain(request_queue_t *q)
-{
- struct request_list *rl = &q->rq;
- struct request *rq;
- int requeued = 0;
-
- spin_lock_irq(q->queue_lock);
- clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
-
- while (!list_empty(&q->drain_list)) {
- rq = list_entry_rq(q->drain_list.next);
-
- list_del_init(&rq->queuelist);
- elv_requeue_request(q, rq);
- requeued++;
- }
-
- if (requeued)
- q->request_fn(q);
-
- spin_unlock_irq(q->queue_lock);
-
- wake_up(&rl->wait[0]);
- wake_up(&rl->wait[1]);
- wake_up(&rl->drain);
-}
-
-static int wait_drain(request_queue_t *q, struct request_list *rl, int dispatch)
-{
- int wait = rl->count[READ] + rl->count[WRITE];
-
- if (dispatch)
- wait += !list_empty(&q->queue_head);
-
- return wait;
-}
-
-/*
- * We rely on the fact that only requests allocated through blk_alloc_request()
- * have io scheduler private data structures associated with them. Any other
- * type of request (allocated on stack or through kmalloc()) should not go
- * to the io scheduler core, but be attached to the queue head instead.
- */
-void blk_wait_queue_drained(request_queue_t *q, int wait_dispatch)
-{
- struct request_list *rl = &q->rq;
- DEFINE_WAIT(wait);
-
- spin_lock_irq(q->queue_lock);
- set_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
-
- while (wait_drain(q, rl, wait_dispatch)) {
- prepare_to_wait(&rl->drain, &wait, TASK_UNINTERRUPTIBLE);
-
- if (wait_drain(q, rl, wait_dispatch)) {
- __generic_unplug_device(q);
- spin_unlock_irq(q->queue_lock);
- io_schedule();
- spin_lock_irq(q->queue_lock);
- }
-
- finish_wait(&rl->drain, &wait);
- }
-
- spin_unlock_irq(q->queue_lock);
-}
-
-/*
- * block waiting for the io scheduler being started again.
- */
-static inline void block_wait_queue_running(request_queue_t *q)
-{
- DEFINE_WAIT(wait);
-
- while (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) {
- struct request_list *rl = &q->rq;
-
- prepare_to_wait_exclusive(&rl->drain, &wait,
- TASK_UNINTERRUPTIBLE);
-
- /*
- * re-check the condition. avoids using prepare_to_wait()
- * in the fast path (queue is running)
- */
- if (test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))
- io_schedule();
-
- finish_wait(&rl->drain, &wait);
- }
-}
-
static void handle_bad_sector(struct bio *bio)
{
char b[BDEVNAME_SIZE];
@@ -2983,8 +2902,6 @@ end_io:
if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)))
goto end_io;
- block_wait_queue_running(q);
-
/*
* If this device has partitions, remap block n
* of partition p to block n+start(p) of the disk.
@@ -3393,7 +3310,7 @@ void exit_io_context(void)
* but since the current task itself holds a reference, the context can be
* used in general code, so long as it stays within `current` context.
*/
-struct io_context *current_io_context(int gfp_flags)
+struct io_context *current_io_context(gfp_t gfp_flags)
{
struct task_struct *tsk = current;
struct io_context *ret;
@@ -3424,7 +3341,7 @@ EXPORT_SYMBOL(current_io_context);
*
* This is always called in the context of the task which submitted the I/O.
*/
-struct io_context *get_io_context(int gfp_flags)
+struct io_context *get_io_context(gfp_t gfp_flags)
{
struct io_context *ret;
ret = current_io_context(gfp_flags);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index b35e08876dd4..96c664af8d06 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -881,7 +881,7 @@ loop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer,
static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
{
struct file *filp = lo->lo_backing_file;
- int gfp = lo->old_gfp_mask;
+ gfp_t gfp = lo->old_gfp_mask;
if (lo->lo_state != Lo_bound)
return -ENXIO;
diff --git a/drivers/block/noop-iosched.c b/drivers/block/noop-iosched.c
index b1730b62c37e..f56b8edb06e4 100644
--- a/drivers/block/noop-iosched.c
+++ b/drivers/block/noop-iosched.c
@@ -7,57 +7,19 @@
#include
#include
-/*
- * See if we can find a request that this buffer can be coalesced with.
- */
-static int elevator_noop_merge(request_queue_t *q, struct request **req,
- struct bio *bio)
+static void elevator_noop_add_request(request_queue_t *q, struct request *rq)
{
- int ret;
-
- ret = elv_try_last_merge(q, bio);
- if (ret != ELEVATOR_NO_MERGE)
- *req = q->last_merge;
-
- return ret;
+ elv_dispatch_add_tail(q, rq);
}
-static void elevator_noop_merge_requests(request_queue_t *q, struct request *req,
- struct request *next)
+static int elevator_noop_dispatch(request_queue_t *q, int force)
{
- list_del_init(&next->queuelist);
-}
-
-static void elevator_noop_add_request(request_queue_t *q, struct request *rq,
- int where)
-{
- if (where == ELEVATOR_INSERT_FRONT)
- list_add(&rq->queuelist, &q->queue_head);
- else
- list_add_tail(&rq->queuelist, &q->queue_head);
-
- /*
- * new merges must not precede this barrier
- */
- if (rq->flags & REQ_HARDBARRIER)
- q->last_merge = NULL;
- else if (!q->last_merge)
- q->last_merge = rq;
-}
-
-static struct request *elevator_noop_next_request(request_queue_t *q)
-{
- if (!list_empty(&q->queue_head))
- return list_entry_rq(q->queue_head.next);
-
- return NULL;
+ return 0;
}
static struct elevator_type elevator_noop = {
.ops = {
- .elevator_merge_fn = elevator_noop_merge,
- .elevator_merge_req_fn = elevator_noop_merge_requests,
- .elevator_next_req_fn = elevator_noop_next_request,
+ .elevator_dispatch_fn = elevator_noop_dispatch,
.elevator_add_req_fn = elevator_noop_add_request,
},
.elevator_name = "noop",
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 145c1fbffe01..68c60a5bcdab 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -348,7 +348,7 @@ static int rd_open(struct inode *inode, struct file *filp)
struct block_device *bdev = inode->i_bdev;
struct address_space *mapping;
unsigned bsize;
- int gfp_mask;
+ gfp_t gfp_mask;
inode = igrab(bdev->bd_inode);
rd_bdev[unit] = bdev;
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index d57007b92f77..1ded3b433459 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -1,7 +1,7 @@
/*
* sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware
*
- * Copyright 2004 Red Hat, Inc.
+ * Copyright 2004-2005 Red Hat, Inc.
*
* Author/maintainer: Jeff Garzik
*
@@ -31,10 +31,6 @@
#include
#include
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Promise SATA SX8 block driver");
-
#if 0
#define CARM_DEBUG
#define CARM_VERBOSE_DEBUG
@@ -45,9 +41,35 @@ MODULE_DESCRIPTION("Promise SATA SX8 block driver");
#undef CARM_NDEBUG
#define DRV_NAME "sx8"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "1.0"
#define PFX DRV_NAME ": "
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Promise SATA SX8 block driver");
+MODULE_VERSION(DRV_VERSION);
+
+/*
+ * SX8 hardware has a single message queue for all ATA ports.
+ * When this driver was written, the hardware (firmware?) would
+ * corrupt data eventually, if more than one request was outstanding.
+ * As one can imagine, having 8 ports bottlenecking on a single
+ * command hurts performance.
+ *
+ * Based on user reports, later versions of the hardware (firmware?)
+ * seem to be able to survive with more than one command queued.
+ *
+ * Therefore, we default to the safe option -- 1 command -- but
+ * allow the user to increase this.
+ *
+ * SX8 should be able to support up to ~60 queued commands (CARM_MAX_REQ),
+ * but problems seem to occur when you exceed ~30, even on newer hardware.
+ */
+static int max_queue = 1;
+module_param(max_queue, int, 0444);
+MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30, safe==1)");
+
+
#define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN)
/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */
@@ -90,12 +112,10 @@ enum {
/* command message queue limits */
CARM_MAX_REQ = 64, /* max command msgs per host */
- CARM_MAX_Q = 1, /* one command at a time */
CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */
/* S/G limits, host-wide and per-request */
CARM_MAX_REQ_SG = 32, /* max s/g entries per request */
- CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */
CARM_MAX_HOST_SG = 600, /* max s/g entries per host */
CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */
@@ -181,6 +201,10 @@ enum {
FL_DYN_MAJOR = (1 << 17),
};
+enum {
+ CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */
+};
+
enum scatter_gather_types {
SGT_32BIT = 0,
SGT_64BIT = 1,
@@ -218,7 +242,6 @@ static const char *state_name[] = {
struct carm_port {
unsigned int port_no;
- unsigned int n_queued;
struct gendisk *disk;
struct carm_host *host;
@@ -448,7 +471,7 @@ static inline int carm_lookup_bucket(u32 msg_size)
for (i = 0; i < ARRAY_SIZE(msg_sizes); i++)
if (msg_size <= msg_sizes[i])
return i;
-
+
return -ENOENT;
}
@@ -509,7 +532,7 @@ static struct carm_request *carm_get_request(struct carm_host *host)
if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG))
return NULL;
- for (i = 0; i < CARM_MAX_Q; i++)
+ for (i = 0; i < max_queue; i++)
if ((host->msg_alloc & (1ULL << i)) == 0) {
struct carm_request *crq = &host->req[i];
crq->port = NULL;
@@ -521,14 +544,14 @@ static struct carm_request *carm_get_request(struct carm_host *host)
assert(host->n_msgs <= CARM_MAX_REQ);
return crq;
}
-
+
DPRINTK("no request available, returning NULL\n");
return NULL;
}
static int carm_put_request(struct carm_host *host, struct carm_request *crq)
{
- assert(crq->tag < CARM_MAX_Q);
+ assert(crq->tag < max_queue);
if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0))
return -EINVAL; /* tried to clear a tag that was not active */
@@ -791,7 +814,7 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
int is_ok)
{
carm_end_request_queued(host, crq, is_ok);
- if (CARM_MAX_Q == 1)
+ if (max_queue == 1)
carm_round_robin(host);
else if ((host->n_msgs <= CARM_MSG_LOW_WATER) &&
(host->hw_sg_used <= CARM_SG_LOW_WATER)) {
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index c9bdf544ed2c..c556f4d3ccd7 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -62,7 +62,7 @@
static inline unsigned char *alloc_buf(void)
{
- unsigned int prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+ gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
if (PAGE_SIZE != N_TTY_BUF_SIZE)
return kmalloc(N_TTY_BUF_SIZE, prio);
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 1af733d07321..9e24bbd4090c 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -32,9 +32,11 @@
* added changelog
* 1.2 Erik Gilling: Cobalt Networks support
* Tim Hockin: general cleanup, Cobalt support
+ * 1.3 Jon Ringle: Comdial MP1000 support
+ *
*/
-#define NVRAM_VERSION "1.2"
+#define NVRAM_VERSION "1.3"
#include
#include
@@ -45,6 +47,7 @@
#define PC 1
#define ATARI 2
#define COBALT 3
+#define MP1000 4
/* select machine configuration */
#if defined(CONFIG_ATARI)
@@ -54,6 +57,9 @@
# if defined(CONFIG_COBALT)
# include
# define MACH COBALT
+# elif defined(CONFIG_MACH_MP1000)
+# undef MACH
+# define MACH MP1000
# else
# define MACH PC
# endif
@@ -112,6 +118,23 @@
#endif
+#if MACH == MP1000
+
+/* RTC in a MP1000 */
+#define CHECK_DRIVER_INIT() 1
+
+#define MP1000_CKS_RANGE_START 0
+#define MP1000_CKS_RANGE_END 111
+#define MP1000_CKS_LOC 112
+
+#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE)
+
+#define mach_check_checksum mp1000_check_checksum
+#define mach_set_checksum mp1000_set_checksum
+#define mach_proc_infos mp1000_proc_infos
+
+#endif
+
/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
* rtc_lock held. Due to the index-port/data-port design of the RTC, we
* don't want two different things trying to get to it at once. (e.g. the
@@ -915,6 +938,91 @@ atari_proc_infos(unsigned char *nvram, char *buffer, int *len,
#endif /* MACH == ATARI */
+#if MACH == MP1000
+
+static int
+mp1000_check_checksum(void)
+{
+ int i;
+ unsigned short sum = 0;
+ unsigned short expect;
+
+ for (i = MP1000_CKS_RANGE_START; i <= MP1000_CKS_RANGE_END; ++i)
+ sum += __nvram_read_byte(i);
+
+ expect = __nvram_read_byte(MP1000_CKS_LOC+1)<<8 |
+ __nvram_read_byte(MP1000_CKS_LOC);
+ return ((sum & 0xffff) == expect);
+}
+
+static void
+mp1000_set_checksum(void)
+{
+ int i;
+ unsigned short sum = 0;
+
+ for (i = MP1000_CKS_RANGE_START; i <= MP1000_CKS_RANGE_END; ++i)
+ sum += __nvram_read_byte(i);
+ __nvram_write_byte(sum >> 8, MP1000_CKS_LOC + 1);
+ __nvram_write_byte(sum & 0xff, MP1000_CKS_LOC);
+}
+
+#ifdef CONFIG_PROC_FS
+
+#define SERVER_N_LEN 32
+#define PATH_N_LEN 32
+#define FILE_N_LEN 32
+#define NVRAM_MAGIC_SIG 0xdead
+
+typedef struct NvRamImage
+{
+ unsigned short int magic;
+ unsigned short int mode;
+ char fname[FILE_N_LEN];
+ char path[PATH_N_LEN];
+ char server[SERVER_N_LEN];
+ char pad[12];
+} NvRam;
+
+static int
+mp1000_proc_infos(unsigned char *nvram, char *buffer, int *len,
+ off_t *begin, off_t offset, int size)
+{
+ int checksum;
+ NvRam* nv = (NvRam*)nvram;
+
+ spin_lock_irq(&rtc_lock);
+ checksum = __nvram_check_checksum();
+ spin_unlock_irq(&rtc_lock);
+
+ PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not ");
+
+ switch( nv->mode )
+ {
+ case 0 :
+ PRINT_PROC( "\tMode 0, tftp prompt\n" );
+ break;
+ case 1 :
+ PRINT_PROC( "\tMode 1, booting from disk\n" );
+ break;
+ case 2 :
+ PRINT_PROC( "\tMode 2, Alternate boot from disk /boot/%s\n", nv->fname );
+ break;
+ case 3 :
+ PRINT_PROC( "\tMode 3, Booting from net:\n" );
+ PRINT_PROC( "\t\t%s:%s%s\n",nv->server, nv->path, nv->fname );
+ break;
+ default:
+ PRINT_PROC( "\tInconsistant nvram?\n" );
+ break;
+ }
+
+ return 1;
+}
+#endif
+
+#endif /* MACH == MP1000 */
+
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(__nvram_read_byte);
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 4802bbbb6dc9..c9e92d85c893 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -1630,7 +1630,7 @@ static void ether1394_complete_cb(void *__ptask)
/* Transmit a packet (called by kernel) */
static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
{
- int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+ gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
struct eth1394hdr *eth;
struct eth1394_priv *priv = netdev_priv(dev);
int proto;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index f6a8ac026557..378646b5a1b8 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -524,7 +524,7 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
}
struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
- unsigned int gfp_mask)
+ gfp_t gfp_mask)
{
struct mthca_mailbox *mailbox;
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h
index 65f976a13e02..18175bec84c2 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -248,7 +248,7 @@ void mthca_cmd_event(struct mthca_dev *dev, u16 token,
u8 status, u64 out_param);
struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
- unsigned int gfp_mask);
+ gfp_t gfp_mask);
void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox);
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status);
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 7bd7a4bec7b4..9ad8b3b6cfef 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -82,7 +82,7 @@ void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm)
}
struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
- unsigned int gfp_mask)
+ gfp_t gfp_mask)
{
struct mthca_icm *icm;
struct mthca_icm_chunk *chunk = NULL;
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index bafa51544aa3..29433f295253 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -77,7 +77,7 @@ struct mthca_icm_iter {
struct mthca_dev;
struct mthca_icm *mthca_alloc_icm(struct mthca_dev *dev, int npages,
- unsigned int gfp_mask);
+ gfp_t gfp_mask);
void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm);
struct mthca_icm_table *mthca_alloc_icm_table(struct mthca_dev *dev,
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 2fba2bbe72d8..01654fcabc52 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -91,7 +91,7 @@ int bitmap_active(struct bitmap *bitmap)
#define WRITE_POOL_SIZE 256
/* mempool for queueing pending writes on the bitmap file */
-static void *write_pool_alloc(unsigned int gfp_flags, void *data)
+static void *write_pool_alloc(gfp_t gfp_flags, void *data)
{
return kmalloc(sizeof(struct page_list), gfp_flags);
}
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index b6148f6f7836..28c1a628621f 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -331,7 +331,7 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
{
struct bio *bio;
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- int gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
+ gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
unsigned int i;
/*
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 91c74843dc0d..1e6bdba26756 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index 55f21ddec3df..6a8e0caf9fdc 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -21,6 +21,7 @@
#include
#include
+#include
#include
#include
#include
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index bc537440ca02..f822cd3025ff 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -1027,8 +1027,7 @@ static void cp_reset_hw (struct cp_private *cp)
if (!(cpr8(Cmd) & CmdReset))
return;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(10);
+ schedule_timeout_uninterruptible(10);
}
printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name);
@@ -1575,6 +1574,7 @@ static struct ethtool_ops cp_ethtool_ops = {
.set_wol = cp_set_wol,
.get_strings = cp_get_strings,
.get_ethtool_stats = cp_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1773,6 +1773,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
for (i = 0; i < 3; i++)
((u16 *) (dev->dev_addr))[i] =
le16_to_cpu (read_eeprom (regs, i + 7, addr_len));
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
dev->open = cp_open;
dev->stop = cp_close;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 4c2cf7bbd252..30bee11c48bd 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -552,7 +552,8 @@ const static struct {
{ "RTL-8100B/8139D",
HW_REVID(1, 1, 1, 0, 1, 0, 1),
- HasLWake,
+ HasHltClk /* XXX undocumented? */
+ | HasLWake,
},
{ "RTL-8101",
@@ -970,6 +971,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
for (i = 0; i < 3; i++)
((u16 *) (dev->dev_addr))[i] =
le16_to_cpu (read_eeprom (ioaddr, i + 7, addr_len));
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* The Rtl8139-specific entries in the device structure. */
dev->open = rtl8139_open;
@@ -2465,6 +2467,7 @@ static struct ethtool_ops rtl8139_ethtool_ops = {
.get_strings = rtl8139_get_strings,
.get_stats_count = rtl8139_get_stats_count,
.get_ethtool_stats = rtl8139_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c748b0e16419..fee8c5cf1f3a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -475,6 +475,14 @@ config SGI_IOC3_ETH_HW_TX_CSUM
the moment only acceleration of IPv4 is supported. This option
enables offloading for checksums on transmit. If unsure, say Y.
+config MIPS_SIM_NET
+ tristate "MIPS simulator Network device (EXPERIMENTAL)"
+ depends on NETDEVICES && MIPS_SIM && EXPERIMENTAL
+ help
+ The MIPSNET device is a simple Ethernet network device which is
+ emulated by the MIPS Simulator.
+ If you are not using a MIPSsim or are unsure, say N.
+
config SGI_O2MACE_ETH
tristate "SGI O2 MACE Fast Ethernet support"
depends on NET_ETHERNET && SGI_IP32=y
@@ -1330,7 +1338,7 @@ config FORCEDETH
config CS89x0
tristate "CS89x0 support"
- depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105
+ depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105 || MACH_MP1000
---help---
Support for CS89x0 chipset based Ethernet cards. If you have a
network (Ethernet) card of this type, say Y and read the
@@ -2083,6 +2091,7 @@ config SPIDER_NET
config GIANFAR
tristate "Gianfar Ethernet"
depends on 85xx || 83xx
+ select PHYLIB
help
This driver supports the Gigabit TSEC on the MPC85xx
family of chips, and the FEC on the 8540
@@ -2243,6 +2252,20 @@ config ISERIES_VETH
tristate "iSeries Virtual Ethernet driver support"
depends on PPC_ISERIES
+config RIONET
+ tristate "RapidIO Ethernet over messaging driver support"
+ depends on NETDEVICES && RAPIDIO
+
+config RIONET_TX_SIZE
+ int "Number of outbound queue entries"
+ depends on RIONET
+ default "128"
+
+config RIONET_RX_SIZE
+ int "Number of inbound queue entries"
+ depends on RIONET
+ default "128"
+
config FDDI
bool "FDDI driver support"
depends on (PCI || EISA)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 8aeec9f2495b..1a84e0435f64 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_CHELSIO_T1) += chelsio/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
-gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_phy.o
+gianfar_driver-objs := gianfar.o gianfar_ethtool.o gianfar_mii.o
#
# link order important here
@@ -64,6 +64,7 @@ obj-$(CONFIG_SKFP) += skfp/
obj-$(CONFIG_VIA_RHINE) += via-rhine.o
obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
+obj-$(CONFIG_RIONET) += rionet.o
#
# end link order section
@@ -166,6 +167,7 @@ obj-$(CONFIG_EQUALIZER) += eql.o
obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
+obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
obj-$(CONFIG_DECLANCE) += declance.o
obj-$(CONFIG_ATARILANCE) += atarilance.o
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index c56d86d371a9..3d50e953faaa 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -29,6 +29,7 @@
#include
#include
+#include
#include
#define TX_BUFFERS 15
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index c82b9cd1c924..78506911d656 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -151,13 +151,6 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES];
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
SUPPORTED_Autoneg
-static char *phy_link[] =
-{ "unknown",
- "10Base2", "10BaseT",
- "AUI",
- "100BaseT", "100BaseTX", "100BaseFX"
-};
-
int bcm_5201_init(struct net_device *dev, int phy_addr)
{
s16 data;
@@ -785,6 +778,7 @@ static struct mii_chip_info {
{"Broadcom BCM5201 10/100 BaseT PHY",0x0040,0x6212, &bcm_5201_ops,0},
{"Broadcom BCM5221 10/100 BaseT PHY",0x0040,0x61e4, &bcm_5201_ops,0},
{"Broadcom BCM5222 10/100 BaseT PHY",0x0040,0x6322, &bcm_5201_ops,1},
+ {"NS DP83847 PHY", 0x2000, 0x5c30, &bcm_5201_ops ,0},
{"AMD 79C901 HomePNA PHY",0x0000,0x35c8, &am79c901_ops,0},
{"AMD 79C874 10/100 BaseT PHY",0x0022,0x561b, &am79c874_ops,0},
{"LSI 80227 10/100 BaseT PHY",0x0016,0xf840, &lsi_80227_ops,0},
@@ -1045,7 +1039,7 @@ found:
#endif
if (aup->mii->chip_info == NULL) {
- printk(KERN_ERR "%s: Au1x No MII transceivers found!\n",
+ printk(KERN_ERR "%s: Au1x No known MII transceivers found!\n",
dev->name);
return -1;
}
@@ -1546,6 +1540,9 @@ au1000_probe(u32 ioaddr, int irq, int port_num)
printk(KERN_ERR "%s: out of memory\n", dev->name);
goto err_out;
}
+ aup->mii->next = NULL;
+ aup->mii->chip_info = NULL;
+ aup->mii->status = 0;
aup->mii->mii_control_reg = 0;
aup->mii->mii_data_reg = 0;
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 94939f570f78..282ebd15f011 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -106,6 +106,29 @@ static int b44_poll(struct net_device *dev, int *budget);
static void b44_poll_controller(struct net_device *dev);
#endif
+static int dma_desc_align_mask;
+static int dma_desc_sync_size;
+
+static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
+ dma_addr_t dma_base,
+ unsigned long offset,
+ enum dma_data_direction dir)
+{
+ dma_sync_single_range_for_device(&pdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
+}
+
+static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev,
+ dma_addr_t dma_base,
+ unsigned long offset,
+ enum dma_data_direction dir)
+{
+ dma_sync_single_range_for_cpu(&pdev->dev, dma_base,
+ offset & dma_desc_align_mask,
+ dma_desc_sync_size, dir);
+}
+
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
{
return readl(bp->regs + reg);
@@ -668,6 +691,11 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dp->ctrl = cpu_to_le32(ctrl);
dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset);
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+ b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
+ dest_idx * sizeof(dp),
+ DMA_BIDIRECTIONAL);
+
return RX_PKT_BUF_SZ;
}
@@ -692,6 +720,11 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
pci_unmap_addr_set(dest_map, mapping,
pci_unmap_addr(src_map, mapping));
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+ b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma,
+ src_idx * sizeof(src_desc),
+ DMA_BIDIRECTIONAL);
+
ctrl = src_desc->ctrl;
if (dest_idx == (B44_RX_RING_SIZE - 1))
ctrl |= cpu_to_le32(DESC_CTRL_EOT);
@@ -700,8 +733,14 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dest_desc->ctrl = ctrl;
dest_desc->addr = src_desc->addr;
+
src_map->skb = NULL;
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+ b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
+ dest_idx * sizeof(dest_desc),
+ DMA_BIDIRECTIONAL);
+
pci_dma_sync_single_for_device(bp->pdev, src_desc->addr,
RX_PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
@@ -959,6 +998,11 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl);
bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
+ if (bp->flags & B44_FLAG_TX_RING_HACK)
+ b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma,
+ entry * sizeof(bp->tx_ring[0]),
+ DMA_TO_DEVICE);
+
entry = NEXT_TX(entry);
bp->tx_prod = entry;
@@ -1064,6 +1108,16 @@ static void b44_init_rings(struct b44 *bp)
memset(bp->rx_ring, 0, B44_RX_RING_BYTES);
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
+ if (bp->flags & B44_FLAG_RX_RING_HACK)
+ dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ PCI_DMA_BIDIRECTIONAL);
+
+ if (bp->flags & B44_FLAG_TX_RING_HACK)
+ dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ PCI_DMA_TODEVICE);
+
for (i = 0; i < bp->rx_pending; i++) {
if (b44_alloc_rx_skb(bp, -1, i) < 0)
break;
@@ -1085,14 +1139,28 @@ static void b44_free_consistent(struct b44 *bp)
bp->tx_buffers = NULL;
}
if (bp->rx_ring) {
- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
- bp->rx_ring, bp->rx_ring_dma);
+ if (bp->flags & B44_FLAG_RX_RING_HACK) {
+ dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
+ kfree(bp->rx_ring);
+ } else
+ pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+ bp->rx_ring, bp->rx_ring_dma);
bp->rx_ring = NULL;
+ bp->flags &= ~B44_FLAG_RX_RING_HACK;
}
if (bp->tx_ring) {
- pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
- bp->tx_ring, bp->tx_ring_dma);
+ if (bp->flags & B44_FLAG_TX_RING_HACK) {
+ dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
+ kfree(bp->tx_ring);
+ } else
+ pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+ bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL;
+ bp->flags &= ~B44_FLAG_TX_RING_HACK;
}
}
@@ -1118,12 +1186,56 @@ static int b44_alloc_consistent(struct b44 *bp)
size = DMA_TABLE_BYTES;
bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
- if (!bp->rx_ring)
- goto out_err;
+ if (!bp->rx_ring) {
+ /* Allocation may have failed due to pci_alloc_consistent
+ insisting on use of GFP_DMA, which is more restrictive
+ than necessary... */
+ struct dma_desc *rx_ring;
+ dma_addr_t rx_ring_dma;
+
+ if (!(rx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+ goto out_err;
+
+ memset(rx_ring, 0, size);
+ rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
+
+ if (rx_ring_dma + size > B44_DMA_MASK) {
+ kfree(rx_ring);
+ goto out_err;
+ }
+
+ bp->rx_ring = rx_ring;
+ bp->rx_ring_dma = rx_ring_dma;
+ bp->flags |= B44_FLAG_RX_RING_HACK;
+ }
bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
- if (!bp->tx_ring)
- goto out_err;
+ if (!bp->tx_ring) {
+ /* Allocation may have failed due to pci_alloc_consistent
+ insisting on use of GFP_DMA, which is more restrictive
+ than necessary... */
+ struct dma_desc *tx_ring;
+ dma_addr_t tx_ring_dma;
+
+ if (!(tx_ring = (struct dma_desc *)kmalloc(size, GFP_KERNEL)))
+ goto out_err;
+
+ memset(tx_ring, 0, size);
+ tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
+
+ if (tx_ring_dma + size > B44_DMA_MASK) {
+ kfree(tx_ring);
+ goto out_err;
+ }
+
+ bp->tx_ring = tx_ring;
+ bp->tx_ring_dma = tx_ring_dma;
+ bp->flags |= B44_FLAG_TX_RING_HACK;
+ }
return 0;
@@ -1676,6 +1788,7 @@ static struct ethtool_ops b44_ethtool_ops = {
.set_pauseparam = b44_set_pauseparam,
.get_msglevel = b44_get_msglevel,
.set_msglevel = b44_set_msglevel,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -1718,6 +1831,7 @@ static int __devinit b44_get_invariants(struct b44 *bp)
bp->dev->dev_addr[3] = eeprom[80];
bp->dev->dev_addr[4] = eeprom[83];
bp->dev->dev_addr[5] = eeprom[82];
+ memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
bp->phy_addr = eeprom[90] & 0x1f;
@@ -1971,6 +2085,12 @@ static struct pci_driver b44_driver = {
static int __init b44_init(void)
{
+ unsigned int dma_desc_align_size = dma_get_cache_alignment();
+
+ /* Setup paramaters for syncing RX/TX DMA descriptors */
+ dma_desc_align_mask = ~(dma_desc_align_size - 1);
+ dma_desc_sync_size = max(dma_desc_align_size, sizeof(struct dma_desc));
+
return pci_module_init(&b44_driver);
}
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 11c40a2e71c7..593cb0ad4100 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -400,6 +400,8 @@ struct b44 {
#define B44_FLAG_ADV_100HALF 0x04000000
#define B44_FLAG_ADV_100FULL 0x08000000
#define B44_FLAG_INTERNAL_PHY 0x10000000
+#define B44_FLAG_RX_RING_HACK 0x20000000
+#define B44_FLAG_TX_RING_HACK 0x40000000
u32 rx_offset;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index f264ff162979..8032126fd589 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4241,6 +4241,43 @@ out:
return 0;
}
+static void bond_activebackup_xmit_copy(struct sk_buff *skb,
+ struct bonding *bond,
+ struct slave *slave)
+{
+ struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
+ struct ethhdr *eth_data;
+ u8 *hwaddr;
+ int res;
+
+ if (!skb2) {
+ printk(KERN_ERR DRV_NAME ": Error: "
+ "bond_activebackup_xmit_copy(): skb_copy() failed\n");
+ return;
+ }
+
+ skb2->mac.raw = (unsigned char *)skb2->data;
+ eth_data = eth_hdr(skb2);
+
+ /* Pick an appropriate source MAC address
+ * -- use slave's perm MAC addr, unless used by bond
+ * -- otherwise, borrow active slave's perm MAC addr
+ * since that will not be used
+ */
+ hwaddr = slave->perm_hwaddr;
+ if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN))
+ hwaddr = bond->curr_active_slave->perm_hwaddr;
+
+ /* Set source MAC address appropriately */
+ memcpy(eth_data->h_source, hwaddr, ETH_ALEN);
+
+ res = bond_dev_queue_xmit(bond, skb2, slave->dev);
+ if (res)
+ dev_kfree_skb(skb2);
+
+ return;
+}
+
/*
* in active-backup mode, we know that bond->curr_active_slave is always valid if
* the bond has a usable interface.
@@ -4257,10 +4294,26 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
goto out;
}
- if (bond->curr_active_slave) { /* one usable interface */
- res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
+ if (!bond->curr_active_slave)
+ goto out;
+
+ /* Xmit IGMP frames on all slaves to ensure rapid fail-over
+ for multicast traffic on snooping switches */
+ if (skb->protocol == __constant_htons(ETH_P_IP) &&
+ skb->nh.iph->protocol == IPPROTO_IGMP) {
+ struct slave *slave, *active_slave;
+ int i;
+
+ active_slave = bond->curr_active_slave;
+ bond_for_each_slave_from_to(bond, slave, i, active_slave->next,
+ active_slave->prev)
+ if (IS_UP(slave->dev) &&
+ (slave->link == BOND_LINK_UP))
+ bond_activebackup_xmit_copy(skb, bond, slave);
}
+ res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
+
out:
if (res) {
/* no suitable interface, frame not sent */
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 2e617424d3fb..50f43dbf31ae 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -489,7 +489,7 @@ static int cas_page_free(struct cas *cp, cas_page_t *page)
/* local page allocation routines for the receive buffers. jumbo pages
* require at least 8K contiguous and 8K aligned buffers.
*/
-static cas_page_t *cas_page_alloc(struct cas *cp, const int flags)
+static cas_page_t *cas_page_alloc(struct cas *cp, const gfp_t flags)
{
cas_page_t *page;
@@ -561,7 +561,7 @@ static void cas_spare_free(struct cas *cp)
}
/* replenish spares if needed */
-static void cas_spare_recover(struct cas *cp, const int flags)
+static void cas_spare_recover(struct cas *cp, const gfp_t flags)
{
struct list_head list, *elem, *tmp;
int needed, i;
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index a6078ad9b654..bfdae10036ed 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -182,6 +182,10 @@ static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
#define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
+#elif defined(CONFIG_MACH_MP1000)
+#include
+static unsigned int netcard_portlist[] __initdata = {MP1000_EIO_BASE+0x300, 0};
+static unsigned int cs8900_irq_map[] = {IRQ_EINT3,0,0,0};
#else
static unsigned int netcard_portlist[] __initdata =
{ 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
@@ -590,6 +594,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
cnt -= j;
}
} else
+#elif defined(CONFIG_MACH_MP1000)
+ if (1) {
+ memcpy(dev->dev_addr, get_eeprom_mac_address(), ETH_ALEN);
+ } else
#endif
if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
@@ -649,6 +657,10 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
if (1) {
printk(KERN_NOTICE "cs89x0: No EEPROM on HiCO.SH4\n");
} else
+#elif defined(CONFIG_MACH_MP1000)
+ if (1) {
+ lp->force |= FORCE_RJ45;
+ } else
#endif
if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0)
printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n");
@@ -1231,7 +1243,7 @@ net_open(struct net_device *dev)
else
#endif
{
-#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105)
+#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105) && !defined(CONFIG_MACH_MP1000)
if (((1 << dev->irq) & lp->irq_map) == 0) {
printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
dev->name, dev->irq, lp->irq_map);
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
index decea264f121..f19d1ebe0183 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/cs89x0.h
@@ -16,7 +16,7 @@
#include
-#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105) || defined (CONFIG_MACH_MP1000)
/* IXDP2401/IXDP2801 uses dword-aligned register addressing */
#define CS89x0_PORT(reg) ((reg) * 2)
#else
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 521c83137bf6..f130bdab3fd3 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -5,7 +5,7 @@
*
* adopted from sunlance.c by Richard van den Berg
*
- * Copyright (C) 2002, 2003 Maciej W. Rozycki
+ * Copyright (C) 2002, 2003, 2005 Maciej W. Rozycki
*
* additional sources:
* - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
@@ -57,13 +57,15 @@
#include
#include
+#include
+
#include
#include
#include
#include
#include
+#include
#include
-#include
static char version[] __devinitdata =
"declance.c: v0.009 by Linux MIPS DECstation task force\n";
@@ -79,10 +81,6 @@ MODULE_LICENSE("GPL");
#define PMAD_LANCE 2
#define PMAX_LANCE 3
-#ifndef CONFIG_TC
-unsigned long system_base;
-unsigned long dmaptr;
-#endif
#define LE_CSR0 0
#define LE_CSR1 1
@@ -237,7 +235,7 @@ struct lance_init_block {
/*
* This works *only* for the ring descriptors
*/
-#define LANCE_ADDR(x) (PHYSADDR(x) >> 1)
+#define LANCE_ADDR(x) (CPHYSADDR(x) >> 1)
struct lance_private {
struct net_device *next;
@@ -697,12 +695,13 @@ out:
spin_unlock(&lp->lock);
}
-static void lance_dma_merr_int(const int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
+ struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
printk("%s: DMA error\n", dev->name);
+ return IRQ_HANDLED;
}
static irqreturn_t
@@ -1026,10 +1025,6 @@ static int __init dec_lance_init(const int type, const int slot)
unsigned long esar_base;
unsigned char *esar;
-#ifndef CONFIG_TC
- system_base = KN01_LANCE_BASE;
-#endif
-
if (dec_lance_debug && version_printed++ == 0)
printk(version);
@@ -1062,16 +1057,16 @@ static int __init dec_lance_init(const int type, const int slot)
switch (type) {
#ifdef CONFIG_TC
case ASIC_LANCE:
- dev->base_addr = system_base + IOASIC_LANCE;
+ dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE);
/* buffer space for the on-board LANCE shared memory */
/*
* FIXME: ugly hack!
*/
- dev->mem_start = KSEG1ADDR(0x00020000);
+ dev->mem_start = CKSEG1ADDR(0x00020000);
dev->mem_end = dev->mem_start + 0x00020000;
dev->irq = dec_interrupt[DEC_IRQ_LANCE];
- esar_base = system_base + IOASIC_ESAR;
+ esar_base = CKSEG1ADDR(dec_kn_slot_base + IOASIC_ESAR);
/* Workaround crash with booting KN04 2.1k from Disk */
memset((void *)dev->mem_start, 0,
@@ -1101,14 +1096,14 @@ static int __init dec_lance_init(const int type, const int slot)
/* Setup I/O ASIC LANCE DMA. */
lp->dma_irq = dec_interrupt[DEC_IRQ_LANCE_MERR];
ioasic_write(IO_REG_LANCE_DMA_P,
- PHYSADDR(dev->mem_start) << 3);
+ CPHYSADDR(dev->mem_start) << 3);
break;
case PMAD_LANCE:
claim_tc_card(slot);
- dev->mem_start = get_tc_base_addr(slot);
+ dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot));
dev->base_addr = dev->mem_start + 0x100000;
dev->irq = get_tc_irq_nr(slot);
esar_base = dev->mem_start + 0x1c0002;
@@ -1137,9 +1132,9 @@ static int __init dec_lance_init(const int type, const int slot)
case PMAX_LANCE:
dev->irq = dec_interrupt[DEC_IRQ_LANCE];
- dev->base_addr = KN01_LANCE_BASE;
- dev->mem_start = KN01_LANCE_BASE + 0x01000000;
- esar_base = KN01_RTC_BASE + 1;
+ dev->base_addr = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE);
+ dev->mem_start = CKSEG1ADDR(KN01_SLOT_BASE + KN01_LANCE_MEM);
+ esar_base = CKSEG1ADDR(KN01_SLOT_BASE + KN01_ESAR + 1);
lp->dma_irq = -1;
/*
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 40887f09b681..eb169a8e8773 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2201,6 +2201,7 @@ static struct ethtool_ops e100_ethtool_ops = {
.phys_id = e100_phys_id,
.get_stats_count = e100_get_stats_count,
.get_ethtool_stats = e100_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
@@ -2351,7 +2352,8 @@ static int __devinit e100_probe(struct pci_dev *pdev,
e100_phy_init(nic);
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
- if(!is_valid_ether_addr(netdev->dev_addr)) {
+ memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
+ if(!is_valid_ether_addr(netdev->perm_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC address from "
"EEPROM, aborting.\n");
err = -EAGAIN;
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 092757bc721f..3f653a93e1bc 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -72,6 +72,10 @@
#include
#include
#include
+#ifdef CONFIG_E1000_MQ
+#include
+#include
+#endif
#define BAR_0 0
#define BAR_1 1
@@ -165,10 +169,33 @@ struct e1000_buffer {
uint16_t next_to_watch;
};
-struct e1000_ps_page { struct page *ps_page[MAX_PS_BUFFERS]; };
-struct e1000_ps_page_dma { uint64_t ps_page_dma[MAX_PS_BUFFERS]; };
+struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; };
+struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; };
-struct e1000_desc_ring {
+struct e1000_tx_ring {
+ /* pointer to the descriptor ring memory */
+ void *desc;
+ /* physical address of the descriptor ring */
+ dma_addr_t dma;
+ /* length of descriptor ring in bytes */
+ unsigned int size;
+ /* number of descriptors in the ring */
+ unsigned int count;
+ /* next descriptor to associate a buffer with */
+ unsigned int next_to_use;
+ /* next descriptor to check for DD status bit */
+ unsigned int next_to_clean;
+ /* array of buffer information structs */
+ struct e1000_buffer *buffer_info;
+
+ struct e1000_buffer previous_buffer_info;
+ spinlock_t tx_lock;
+ uint16_t tdh;
+ uint16_t tdt;
+ uint64_t pkt;
+};
+
+struct e1000_rx_ring {
/* pointer to the descriptor ring memory */
void *desc;
/* physical address of the descriptor ring */
@@ -186,6 +213,10 @@ struct e1000_desc_ring {
/* arrays of page information for packet split */
struct e1000_ps_page *ps_page;
struct e1000_ps_page_dma *ps_page_dma;
+
+ uint16_t rdh;
+ uint16_t rdt;
+ uint64_t pkt;
};
#define E1000_DESC_UNUSED(R) \
@@ -227,9 +258,10 @@ struct e1000_adapter {
unsigned long led_status;
/* TX */
- struct e1000_desc_ring tx_ring;
- struct e1000_buffer previous_buffer_info;
- spinlock_t tx_lock;
+ struct e1000_tx_ring *tx_ring; /* One per active queue */
+#ifdef CONFIG_E1000_MQ
+ struct e1000_tx_ring **cpu_tx_ring; /* per-cpu */
+#endif
uint32_t txd_cmd;
uint32_t tx_int_delay;
uint32_t tx_abs_int_delay;
@@ -246,19 +278,33 @@ struct e1000_adapter {
/* RX */
#ifdef CONFIG_E1000_NAPI
- boolean_t (*clean_rx) (struct e1000_adapter *adapter, int *work_done,
- int work_to_do);
+ boolean_t (*clean_rx) (struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do);
#else
- boolean_t (*clean_rx) (struct e1000_adapter *adapter);
+ boolean_t (*clean_rx) (struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
#endif
- void (*alloc_rx_buf) (struct e1000_adapter *adapter);
- struct e1000_desc_ring rx_ring;
+ void (*alloc_rx_buf) (struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
+ struct e1000_rx_ring *rx_ring; /* One per active queue */
+#ifdef CONFIG_E1000_NAPI
+ struct net_device *polling_netdev; /* One per active queue */
+#endif
+#ifdef CONFIG_E1000_MQ
+ struct net_device **cpu_netdev; /* per-cpu */
+ struct call_async_data_struct rx_sched_call_data;
+ int cpu_for_queue[4];
+#endif
+ int num_queues;
+
uint64_t hw_csum_err;
uint64_t hw_csum_good;
+ uint64_t rx_hdr_split;
uint32_t rx_int_delay;
uint32_t rx_abs_int_delay;
boolean_t rx_csum;
- boolean_t rx_ps;
+ unsigned int rx_ps_pages;
uint32_t gorcl;
uint64_t gorcl_old;
uint16_t rx_ps_bsize0;
@@ -278,8 +324,8 @@ struct e1000_adapter {
struct e1000_phy_stats phy_stats;
uint32_t test_icr;
- struct e1000_desc_ring test_tx_ring;
- struct e1000_desc_ring test_rx_ring;
+ struct e1000_tx_ring test_tx_ring;
+ struct e1000_rx_ring test_rx_ring;
int msg_enable;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index f133ff0b0b94..6b9acc7f94a3 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -39,10 +39,10 @@ extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
-extern int e1000_setup_rx_resources(struct e1000_adapter *adapter);
-extern int e1000_setup_tx_resources(struct e1000_adapter *adapter);
-extern void e1000_free_rx_resources(struct e1000_adapter *adapter);
-extern void e1000_free_tx_resources(struct e1000_adapter *adapter);
+extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
+extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_update_stats(struct e1000_adapter *adapter);
struct e1000_stats {
@@ -91,7 +91,8 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
{ "rx_long_byte_count", E1000_STAT(stats.gorcl) },
{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
- { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) }
+ { "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
+ { "rx_header_split", E1000_STAT(rx_hdr_split) },
};
#define E1000_STATS_LEN \
sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
@@ -546,8 +547,10 @@ e1000_set_eeprom(struct net_device *netdev,
ret_val = e1000_write_eeprom(hw, first_word,
last_word - first_word + 1, eeprom_buff);
- /* Update the checksum over the first part of the EEPROM if needed */
- if((ret_val == 0) && first_word <= EEPROM_CHECKSUM_REG)
+ /* Update the checksum over the first part of the EEPROM if needed
+ * and flush shadow RAM for 82573 conrollers */
+ if((ret_val == 0) && ((first_word <= EEPROM_CHECKSUM_REG) ||
+ (hw->mac_type == e1000_82573)))
e1000_update_eeprom_checksum(hw);
kfree(eeprom_buff);
@@ -576,8 +579,8 @@ e1000_get_ringparam(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_mac_type mac_type = adapter->hw.mac_type;
- struct e1000_desc_ring *txdr = &adapter->tx_ring;
- struct e1000_desc_ring *rxdr = &adapter->rx_ring;
+ struct e1000_tx_ring *txdr = adapter->tx_ring;
+ struct e1000_rx_ring *rxdr = adapter->rx_ring;
ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD :
E1000_MAX_82544_RXD;
@@ -597,20 +600,40 @@ e1000_set_ringparam(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_mac_type mac_type = adapter->hw.mac_type;
- struct e1000_desc_ring *txdr = &adapter->tx_ring;
- struct e1000_desc_ring *rxdr = &adapter->rx_ring;
- struct e1000_desc_ring tx_old, tx_new, rx_old, rx_new;
- int err;
+ struct e1000_tx_ring *txdr, *tx_old, *tx_new;
+ struct e1000_rx_ring *rxdr, *rx_old, *rx_new;
+ int i, err, tx_ring_size, rx_ring_size;
+
+ tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_queues;
+ rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_queues;
+
+ if (netif_running(adapter->netdev))
+ e1000_down(adapter);
tx_old = adapter->tx_ring;
rx_old = adapter->rx_ring;
+ adapter->tx_ring = kmalloc(tx_ring_size, GFP_KERNEL);
+ if (!adapter->tx_ring) {
+ err = -ENOMEM;
+ goto err_setup_rx;
+ }
+ memset(adapter->tx_ring, 0, tx_ring_size);
+
+ adapter->rx_ring = kmalloc(rx_ring_size, GFP_KERNEL);
+ if (!adapter->rx_ring) {
+ kfree(adapter->tx_ring);
+ err = -ENOMEM;
+ goto err_setup_rx;
+ }
+ memset(adapter->rx_ring, 0, rx_ring_size);
+
+ txdr = adapter->tx_ring;
+ rxdr = adapter->rx_ring;
+
if((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
- if(netif_running(adapter->netdev))
- e1000_down(adapter);
-
rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
E1000_MAX_RXD : E1000_MAX_82544_RXD));
@@ -621,11 +644,16 @@ e1000_set_ringparam(struct net_device *netdev,
E1000_MAX_TXD : E1000_MAX_82544_TXD));
E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+ for (i = 0; i < adapter->num_queues; i++) {
+ txdr[i].count = txdr->count;
+ rxdr[i].count = rxdr->count;
+ }
+
if(netif_running(adapter->netdev)) {
/* Try to get new resources before deleting old */
- if((err = e1000_setup_rx_resources(adapter)))
+ if ((err = e1000_setup_all_rx_resources(adapter)))
goto err_setup_rx;
- if((err = e1000_setup_tx_resources(adapter)))
+ if ((err = e1000_setup_all_tx_resources(adapter)))
goto err_setup_tx;
/* save the new, restore the old in order to free it,
@@ -635,8 +663,10 @@ e1000_set_ringparam(struct net_device *netdev,
tx_new = adapter->tx_ring;
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
- e1000_free_rx_resources(adapter);
- e1000_free_tx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
+ e1000_free_all_tx_resources(adapter);
+ kfree(tx_old);
+ kfree(rx_old);
adapter->rx_ring = rx_new;
adapter->tx_ring = tx_new;
if((err = e1000_up(adapter)))
@@ -645,7 +675,7 @@ e1000_set_ringparam(struct net_device *netdev,
return 0;
err_setup_tx:
- e1000_free_rx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
err_setup_rx:
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
@@ -696,6 +726,11 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
* Some bits that get toggled are ignored.
*/
switch (adapter->hw.mac_type) {
+ /* there are several bits on newer hardware that are r/w */
+ case e1000_82571:
+ case e1000_82572:
+ toggle = 0x7FFFF3FF;
+ break;
case e1000_82573:
toggle = 0x7FFFF033;
break;
@@ -898,8 +933,8 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
static void
e1000_free_desc_rings(struct e1000_adapter *adapter)
{
- struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
- struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct e1000_tx_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
int i;
@@ -941,8 +976,8 @@ e1000_free_desc_rings(struct e1000_adapter *adapter)
static int
e1000_setup_desc_rings(struct e1000_adapter *adapter)
{
- struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
- struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct e1000_tx_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
uint32_t rctl;
int size, i, ret_val;
@@ -1245,6 +1280,8 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter)
case e1000_82541_rev_2:
case e1000_82547:
case e1000_82547_rev_2:
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
return e1000_integrated_phy_loopback(adapter);
break;
@@ -1340,8 +1377,8 @@ e1000_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size)
static int
e1000_run_loopback_test(struct e1000_adapter *adapter)
{
- struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
- struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+ struct e1000_tx_ring *txdr = &adapter->test_tx_ring;
+ struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
int i, j, k, l, lc, good_cnt, ret_val=0;
unsigned long time;
@@ -1509,6 +1546,7 @@ e1000_diag_test(struct net_device *netdev,
data[2] = 0;
data[3] = 0;
}
+ msleep_interruptible(4 * 1000);
}
static void
@@ -1625,7 +1663,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
- if(adapter->hw.mac_type < e1000_82573) {
+ if(adapter->hw.mac_type < e1000_82571) {
if(!adapter->blink_timer.function) {
init_timer(&adapter->blink_timer);
adapter->blink_timer.function = e1000_led_blink_callback;
@@ -1739,6 +1777,7 @@ struct ethtool_ops e1000_ethtool_ops = {
.phys_id = e1000_phys_id,
.get_stats_count = e1000_get_stats_count,
.get_ethtool_stats = e1000_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 045f5426ab9a..8fc876da43b4 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -83,14 +83,14 @@ uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
static const
uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] =
- { 8, 13, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43,
- 22, 24, 27, 30, 32, 35, 37, 40, 42, 44, 47, 49, 51, 54, 56, 58,
- 32, 35, 38, 41, 44, 47, 50, 53, 55, 58, 61, 63, 66, 69, 71, 74,
- 43, 47, 51, 54, 58, 61, 64, 67, 71, 74, 77, 80, 82, 85, 88, 90,
- 57, 62, 66, 70, 74, 77, 81, 85, 88, 91, 94, 97, 100, 103, 106, 108,
- 73, 78, 82, 87, 91, 95, 98, 102, 105, 109, 112, 114, 117, 119, 122, 124,
- 91, 96, 101, 105, 109, 113, 116, 119, 122, 125, 127, 128, 128, 128, 128, 128,
- 108, 113, 117, 121, 124, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128};
+ { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21,
+ 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41,
+ 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61,
+ 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82,
+ 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104,
+ 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121,
+ 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
+ 104, 109, 114, 118, 121, 124};
/******************************************************************************
@@ -286,7 +286,6 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82546GB_FIBER:
case E1000_DEV_ID_82546GB_SERDES:
case E1000_DEV_ID_82546GB_PCIE:
- case E1000_DEV_ID_82546GB_QUAD_COPPER:
hw->mac_type = e1000_82546_rev_3;
break;
case E1000_DEV_ID_82541EI:
@@ -305,8 +304,19 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82547GI:
hw->mac_type = e1000_82547_rev_2;
break;
+ case E1000_DEV_ID_82571EB_COPPER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ case E1000_DEV_ID_82571EB_SERDES:
+ hw->mac_type = e1000_82571;
+ break;
+ case E1000_DEV_ID_82572EI_COPPER:
+ case E1000_DEV_ID_82572EI_FIBER:
+ case E1000_DEV_ID_82572EI_SERDES:
+ hw->mac_type = e1000_82572;
+ break;
case E1000_DEV_ID_82573E:
case E1000_DEV_ID_82573E_IAMT:
+ case E1000_DEV_ID_82573L:
hw->mac_type = e1000_82573;
break;
default:
@@ -315,6 +325,8 @@ e1000_set_mac_type(struct e1000_hw *hw)
}
switch(hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
hw->eeprom_semaphore_present = TRUE;
/* fall through */
@@ -351,6 +363,8 @@ e1000_set_media_type(struct e1000_hw *hw)
switch (hw->device_id) {
case E1000_DEV_ID_82545GM_SERDES:
case E1000_DEV_ID_82546GB_SERDES:
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82572EI_SERDES:
hw->media_type = e1000_media_type_internal_serdes;
break;
default:
@@ -523,6 +537,8 @@ e1000_reset_hw(struct e1000_hw *hw)
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
/* fall through */
+ case e1000_82571:
+ case e1000_82572:
ret_val = e1000_get_auto_rd_done(hw);
if(ret_val)
/* We don't want to continue accessing MAC registers. */
@@ -683,6 +699,9 @@ e1000_init_hw(struct e1000_hw *hw)
switch (hw->mac_type) {
default:
break;
+ case e1000_82571:
+ case e1000_82572:
+ ctrl |= (1 << 22);
case e1000_82573:
ctrl |= E1000_TXDCTL_COUNT_DESC;
break;
@@ -694,6 +713,26 @@ e1000_init_hw(struct e1000_hw *hw)
e1000_enable_tx_pkt_filtering(hw);
}
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ ctrl = E1000_READ_REG(hw, TXDCTL1);
+ ctrl &= ~E1000_TXDCTL_WTHRESH;
+ ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB;
+ ctrl |= (1 << 22);
+ E1000_WRITE_REG(hw, TXDCTL1, ctrl);
+ break;
+ }
+
+
+
+ if (hw->mac_type == e1000_82573) {
+ uint32_t gcr = E1000_READ_REG(hw, GCR);
+ gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+ E1000_WRITE_REG(hw, GCR, gcr);
+ }
/* Clear all of the statistics registers (clear on read). It is
* important that we do this after we have tried to establish link
@@ -878,6 +917,14 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
DEBUGFUNC("e1000_setup_fiber_serdes_link");
+ /* On 82571 and 82572 Fiber connections, SerDes loopback mode persists
+ * until explicitly turned off or a power cycle is performed. A read to
+ * the register does not indicate its status. Therefore, we ensure
+ * loopback mode is disabled during initialization.
+ */
+ if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572)
+ E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK);
+
/* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
* set when the optics detect a signal. On older adapters, it will be
* cleared when there is a signal. This applies to fiber media only.
@@ -2943,6 +2990,8 @@ e1000_phy_reset(struct e1000_hw *hw)
switch (hw->mac_type) {
case e1000_82541_rev_2:
+ case e1000_82571:
+ case e1000_82572:
ret_val = e1000_phy_hw_reset(hw);
if(ret_val)
return ret_val;
@@ -2981,6 +3030,16 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
DEBUGFUNC("e1000_detect_gig_phy");
+ /* The 82571 firmware may still be configuring the PHY. In this
+ * case, we cannot access the PHY until the configuration is done. So
+ * we explicitly set the PHY values. */
+ if(hw->mac_type == e1000_82571 ||
+ hw->mac_type == e1000_82572) {
+ hw->phy_id = IGP01E1000_I_PHY_ID;
+ hw->phy_type = e1000_phy_igp_2;
+ return E1000_SUCCESS;
+ }
+
/* Read the PHY ID Registers to identify which PHY is onboard. */
ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
if(ret_val)
@@ -3334,6 +3393,21 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->use_eerd = FALSE;
eeprom->use_eewr = FALSE;
break;
+ case e1000_82571:
+ case e1000_82572:
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->page_size = 32;
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->page_size = 8;
+ eeprom->address_bits = 8;
+ }
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ break;
case e1000_82573:
eeprom->type = e1000_eeprom_spi;
eeprom->opcode_bits = 8;
@@ -3543,25 +3617,26 @@ e1000_acquire_eeprom(struct e1000_hw *hw)
eecd = E1000_READ_REG(hw, EECD);
if (hw->mac_type != e1000_82573) {
- /* Request EEPROM Access */
- if(hw->mac_type > e1000_82544) {
- eecd |= E1000_EECD_REQ;
- E1000_WRITE_REG(hw, EECD, eecd);
- eecd = E1000_READ_REG(hw, EECD);
- while((!(eecd & E1000_EECD_GNT)) &&
- (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
- i++;
- udelay(5);
- eecd = E1000_READ_REG(hw, EECD);
- }
- if(!(eecd & E1000_EECD_GNT)) {
- eecd &= ~E1000_EECD_REQ;
+ /* Request EEPROM Access */
+ if(hw->mac_type > e1000_82544) {
+ eecd |= E1000_EECD_REQ;
E1000_WRITE_REG(hw, EECD, eecd);
- DEBUGOUT("Could not acquire EEPROM grant\n");
- return -E1000_ERR_EEPROM;
+ eecd = E1000_READ_REG(hw, EECD);
+ while((!(eecd & E1000_EECD_GNT)) &&
+ (i < E1000_EEPROM_GRANT_ATTEMPTS)) {
+ i++;
+ udelay(5);
+ eecd = E1000_READ_REG(hw, EECD);
+ }
+ if(!(eecd & E1000_EECD_GNT)) {
+ eecd &= ~E1000_EECD_REQ;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ DEBUGOUT("Could not acquire EEPROM grant\n");
+ e1000_put_hw_eeprom_semaphore(hw);
+ return -E1000_ERR_EEPROM;
+ }
}
}
- }
/* Setup EEPROM for Read/Write */
@@ -4064,7 +4139,7 @@ e1000_write_eeprom(struct e1000_hw *hw,
return -E1000_ERR_EEPROM;
}
- /* 82573 reads only through eerd */
+ /* 82573 writes only through eewr */
if(eeprom->use_eewr == TRUE)
return e1000_write_eeprom_eewr(hw, offset, words, data);
@@ -4353,9 +4428,16 @@ e1000_read_mac_addr(struct e1000_hw * hw)
hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
}
- if(((hw->mac_type == e1000_82546) || (hw->mac_type == e1000_82546_rev_3)) &&
- (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1))
+ switch (hw->mac_type) {
+ default:
+ break;
+ case e1000_82546:
+ case e1000_82546_rev_3:
+ case e1000_82571:
+ if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
hw->perm_mac_addr[5] ^= 0x01;
+ break;
+ }
for(i = 0; i < NODE_ADDRESS_SIZE; i++)
hw->mac_addr[i] = hw->perm_mac_addr[i];
@@ -4385,6 +4467,12 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
e1000_rar_set(hw, hw->mac_addr, 0);
rar_num = E1000_RAR_ENTRIES;
+
+ /* Reserve a spot for the Locally Administered Address to work around
+ * an 82571 issue in which a reset on one port will reload the MAC on
+ * the other port. */
+ if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
+ rar_num -= 1;
/* Zero out the other 15 receive addresses. */
DEBUGOUT("Clearing RAR[1-15]\n");
for(i = 1; i < rar_num; i++) {
@@ -4427,6 +4515,12 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
/* Clear RAR[1-15] */
DEBUGOUT(" Clearing RAR[1-15]\n");
num_rar_entry = E1000_RAR_ENTRIES;
+ /* Reserve a spot for the Locally Administered Address to work around
+ * an 82571 issue in which a reset on one port will reload the MAC on
+ * the other port. */
+ if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
+ num_rar_entry -= 1;
+
for(i = rar_used_count; i < num_rar_entry; i++) {
E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
@@ -4984,7 +5078,6 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = E1000_READ_REG(hw, ICTXQEC);
temp = E1000_READ_REG(hw, ICTXQMTC);
temp = E1000_READ_REG(hw, ICRXDMTC);
-
}
/******************************************************************************
@@ -5151,6 +5244,8 @@ e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_speed = e1000_bus_speed_unknown;
hw->bus_width = e1000_bus_width_unknown;
break;
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
@@ -5250,6 +5345,7 @@ e1000_get_cable_length(struct e1000_hw *hw,
int32_t ret_val;
uint16_t agc_value = 0;
uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+ uint16_t max_agc = 0;
uint16_t i, phy_data;
uint16_t cable_length;
@@ -5338,6 +5434,40 @@ e1000_get_cable_length(struct e1000_hw *hw,
IGP01E1000_AGC_RANGE) : 0;
*max_length = e1000_igp_cable_length_table[agc_value] +
IGP01E1000_AGC_RANGE;
+ } else if (hw->phy_type == e1000_phy_igp_2) {
+ uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+ {IGP02E1000_PHY_AGC_A,
+ IGP02E1000_PHY_AGC_B,
+ IGP02E1000_PHY_AGC_C,
+ IGP02E1000_PHY_AGC_D};
+ /* Read the AGC registers for all channels */
+ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+ ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* Getting bits 15:9, which represent the combination of course and
+ * fine gain values. The result is a number that can be put into
+ * the lookup table to obtain the approximate cable length. */
+ cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK;
+
+ /* Remove min & max AGC values from calculation. */
+ if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc])
+ min_agc = cur_agc;
+ if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc])
+ max_agc = cur_agc;
+
+ agc_value += e1000_igp_2_cable_length_table[cur_agc];
+ }
+
+ agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]);
+ agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+ /* Calculate cable length with the error range of +/- 10 meters. */
+ *min_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+ (agc_value - IGP02E1000_AGC_RANGE) : 0;
+ *max_length = agc_value + IGP02E1000_AGC_RANGE;
}
return E1000_SUCCESS;
@@ -6465,6 +6595,8 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
default:
msec_delay(5);
break;
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
while(timeout) {
if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
@@ -6494,10 +6626,31 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
int32_t
e1000_get_phy_cfg_done(struct e1000_hw *hw)
{
+ int32_t timeout = PHY_CFG_TIMEOUT;
+ uint32_t cfg_mask = E1000_EEPROM_CFG_DONE;
+
DEBUGFUNC("e1000_get_phy_cfg_done");
- /* Simply wait for 10ms */
- msec_delay(10);
+ switch (hw->mac_type) {
+ default:
+ msec_delay(10);
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ while (timeout) {
+ if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
+ break;
+ else
+ msec_delay(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("MNG configuration cycle has not completed.\n");
+ return -E1000_ERR_RESET;
+ }
+ break;
+ }
return E1000_SUCCESS;
}
@@ -6569,8 +6722,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
return;
swsm = E1000_READ_REG(hw, SWSM);
- /* Release both semaphores. */
- swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+ swsm &= ~(E1000_SWSM_SWESMBI);
E1000_WRITE_REG(hw, SWSM, swsm);
}
@@ -6606,6 +6758,8 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw)
* if this is the case. We read FWSM to determine the manageability mode.
*/
switch (hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
case e1000_82573:
fwsm = E1000_READ_REG(hw, FWSM);
if((fwsm & E1000_FWSM_MODE_MASK) != 0)
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 51c2b3a18b6f..4f2c196dc314 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -57,6 +57,8 @@ typedef enum {
e1000_82541_rev_2,
e1000_82547,
e1000_82547_rev_2,
+ e1000_82571,
+ e1000_82572,
e1000_82573,
e1000_num_macs
} e1000_mac_type;
@@ -478,10 +480,16 @@ uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw);
#define E1000_DEV_ID_82546GB_SERDES 0x107B
#define E1000_DEV_ID_82546GB_PCIE 0x108A
#define E1000_DEV_ID_82547EI 0x1019
+#define E1000_DEV_ID_82571EB_COPPER 0x105E
+#define E1000_DEV_ID_82571EB_FIBER 0x105F
+#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82572EI_COPPER 0x107D
+#define E1000_DEV_ID_82572EI_FIBER 0x107E
+#define E1000_DEV_ID_82572EI_SERDES 0x107F
#define E1000_DEV_ID_82573E 0x108B
#define E1000_DEV_ID_82573E_IAMT 0x108C
+#define E1000_DEV_ID_82573L 0x109A
-#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
#define NODE_ADDRESS_SIZE 6
#define ETH_LENGTH_OF_ADDRESS 6
@@ -833,6 +841,8 @@ struct e1000_ffvt_entry {
#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_DISABLE_SERDES_LOOPBACK 0x0400
+
/* Register Set. (82543, 82544)
*
* Registers are defined to be 32 bits and should be accessed as 32 bit values.
@@ -853,6 +863,7 @@ struct e1000_ffvt_entry {
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
+#define E1000_SCTL 0x00024 /* SerDes Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
@@ -864,6 +875,12 @@ struct e1000_ffvt_entry {
#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */
#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */
#define E1000_RCTL 0x00100 /* RX Control - RW */
+#define E1000_RDTR1 0x02820 /* RX Delay Timer (1) - RW */
+#define E1000_RDBAL1 0x02900 /* RX Descriptor Base Address Low (1) - RW */
+#define E1000_RDBAH1 0x02904 /* RX Descriptor Base Address High (1) - RW */
+#define E1000_RDLEN1 0x02908 /* RX Descriptor Length (1) - RW */
+#define E1000_RDH1 0x02910 /* RX Descriptor Head (1) - RW */
+#define E1000_RDT1 0x02918 /* RX Descriptor Tail (1) - RW */
#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */
#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */
#define E1000_RXCW 0x00180 /* RX Configuration Word - RO */
@@ -895,6 +912,12 @@ struct e1000_ffvt_entry {
#define E1000_RDH 0x02810 /* RX Descriptor Head - RW */
#define E1000_RDT 0x02818 /* RX Descriptor Tail - RW */
#define E1000_RDTR 0x02820 /* RX Delay Timer - RW */
+#define E1000_RDBAL0 E1000_RDBAL /* RX Desc Base Address Low (0) - RW */
+#define E1000_RDBAH0 E1000_RDBAH /* RX Desc Base Address High (0) - RW */
+#define E1000_RDLEN0 E1000_RDLEN /* RX Desc Length (0) - RW */
+#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */
+#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */
+#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */
#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */
#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
@@ -980,15 +1003,15 @@ struct e1000_ffvt_entry {
#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */
#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */
#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */
-#define E1000_IAC 0x4100 /* Interrupt Assertion Count */
-#define E1000_ICRXPTC 0x4104 /* Interrupt Cause Rx Packet Timer Expire Count */
-#define E1000_ICRXATC 0x4108 /* Interrupt Cause Rx Absolute Timer Expire Count */
-#define E1000_ICTXPTC 0x410C /* Interrupt Cause Tx Packet Timer Expire Count */
-#define E1000_ICTXATC 0x4110 /* Interrupt Cause Tx Absolute Timer Expire Count */
-#define E1000_ICTXQEC 0x4118 /* Interrupt Cause Tx Queue Empty Count */
-#define E1000_ICTXQMTC 0x411C /* Interrupt Cause Tx Queue Minimum Threshold Count */
-#define E1000_ICRXDMTC 0x4120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
-#define E1000_ICRXOC 0x4124 /* Interrupt Cause Receiver Overrun Count */
+#define E1000_IAC 0x04100 /* Interrupt Assertion Count */
+#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Packet Timer Expire Count */
+#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Absolute Timer Expire Count */
+#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Packet Timer Expire Count */
+#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Absolute Timer Expire Count */
+#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */
+#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Minimum Threshold Count */
+#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Descriptor Minimum Threshold Count */
+#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */
#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */
#define E1000_RFCTL 0x05008 /* Receive Filter Control*/
#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */
@@ -1018,6 +1041,14 @@ struct e1000_ffvt_entry {
#define E1000_FWSM 0x05B54 /* FW Semaphore */
#define E1000_FFLT_DBG 0x05F04 /* Debug Register */
#define E1000_HICR 0x08F00 /* Host Inteface Control */
+
+/* RSS registers */
+#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */
+#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */
+#define E1000_RETA 0x05C00 /* Redirection Table - RW Array */
+#define E1000_RSSRK 0x05C80 /* RSS Random Key - RW Array */
+#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */
+#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */
/* Register Set (82542)
*
* Some of the 82542 registers are located at different offsets than they are
@@ -1032,6 +1063,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
#define E1000_82542_FLA E1000_FLA
#define E1000_82542_MDIC E1000_MDIC
+#define E1000_82542_SCTL E1000_SCTL
#define E1000_82542_FCAL E1000_FCAL
#define E1000_82542_FCAH E1000_FCAH
#define E1000_82542_FCT E1000_FCT
@@ -1049,6 +1081,18 @@ struct e1000_ffvt_entry {
#define E1000_82542_RDLEN 0x00118
#define E1000_82542_RDH 0x00120
#define E1000_82542_RDT 0x00128
+#define E1000_82542_RDTR0 E1000_82542_RDTR
+#define E1000_82542_RDBAL0 E1000_82542_RDBAL
+#define E1000_82542_RDBAH0 E1000_82542_RDBAH
+#define E1000_82542_RDLEN0 E1000_82542_RDLEN
+#define E1000_82542_RDH0 E1000_82542_RDH
+#define E1000_82542_RDT0 E1000_82542_RDT
+#define E1000_82542_RDTR1 0x00130
+#define E1000_82542_RDBAL1 0x00138
+#define E1000_82542_RDBAH1 0x0013C
+#define E1000_82542_RDLEN1 0x00140
+#define E1000_82542_RDH1 0x00148
+#define E1000_82542_RDT1 0x00150
#define E1000_82542_FCRTH 0x00160
#define E1000_82542_FCRTL 0x00168
#define E1000_82542_FCTTV E1000_FCTTV
@@ -1197,6 +1241,13 @@ struct e1000_ffvt_entry {
#define E1000_82542_ICRXOC E1000_ICRXOC
#define E1000_82542_HICR E1000_HICR
+#define E1000_82542_CPUVEC E1000_CPUVEC
+#define E1000_82542_MRQC E1000_MRQC
+#define E1000_82542_RETA E1000_RETA
+#define E1000_82542_RSSRK E1000_RSSRK
+#define E1000_82542_RSSIM E1000_RSSIM
+#define E1000_82542_RSSIR E1000_RSSIR
+
/* Statistics counters collected by the MAC */
struct e1000_hw_stats {
uint64_t crcerrs;
@@ -1336,6 +1387,7 @@ struct e1000_hw {
boolean_t serdes_link_down;
boolean_t tbi_compatibility_en;
boolean_t tbi_compatibility_on;
+ boolean_t laa_is_present;
boolean_t phy_reset_disable;
boolean_t fc_send_xon;
boolean_t fc_strict_ieee;
@@ -1374,6 +1426,7 @@ struct e1000_hw {
#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */
#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */
#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */
+#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */
#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */
#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */
#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */
@@ -1491,6 +1544,8 @@ struct e1000_hw {
#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
+#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */
+#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
@@ -1524,6 +1579,7 @@ struct e1000_hw {
#define E1000_LEDCTL_LED2_BLINK 0x00800000
#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000
#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000
#define E1000_LEDCTL_LED3_IVRT 0x40000000
#define E1000_LEDCTL_LED3_BLINK 0x80000000
@@ -1784,6 +1840,16 @@ struct e1000_hw {
#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */
+/* Multiple Receive Queue Control */
+#define E1000_MRQC_ENABLE_MASK 0x00000003
+#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001
+#define E1000_MRQC_ENABLE_RSS_INT 0x00000004
+#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000
+#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
+#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000
+#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000
/* Definitions for power management and wakeup registers */
/* Wake Up Control */
@@ -1928,6 +1994,7 @@ struct e1000_host_command_info {
#define E1000_MDALIGN 4096
#define E1000_GCR_BEM32 0x00400000
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
/* Function Active and Power State to MNG */
#define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003
#define E1000_FACTPS_LAN0_VALID 0x00000004
@@ -1980,6 +2047,7 @@ struct e1000_host_command_info {
/* EEPROM Word Offsets */
#define EEPROM_COMPAT 0x0003
#define EEPROM_ID_LED_SETTINGS 0x0004
+#define EEPROM_VERSION 0x0005
#define EEPROM_SERDES_AMPLITUDE 0x0006 /* For SERDES output amplitude adjustment. */
#define EEPROM_PHY_CLASS_WORD 0x0007
#define EEPROM_INIT_CONTROL1_REG 0x000A
@@ -1990,6 +2058,8 @@ struct e1000_host_command_info {
#define EEPROM_FLASH_VERSION 0x0032
#define EEPROM_CHECKSUM_REG 0x003F
+#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
+
/* Word definitions for ID LED Settings */
#define ID_LED_RESERVED_0000 0x0000
#define ID_LED_RESERVED_FFFF 0xFFFF
@@ -2108,6 +2178,8 @@ struct e1000_host_command_info {
#define E1000_PBA_22K 0x0016
#define E1000_PBA_24K 0x0018
#define E1000_PBA_30K 0x001E
+#define E1000_PBA_32K 0x0020
+#define E1000_PBA_38K 0x0026
#define E1000_PBA_40K 0x0028
#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */
@@ -2592,11 +2664,11 @@ struct e1000_host_command_info {
/* 7 bits (3 Coarse + 4 Fine) --> 128 optional values */
#define IGP01E1000_AGC_LENGTH_TABLE_SIZE 128
-#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 128
+#define IGP02E1000_AGC_LENGTH_TABLE_SIZE 113
/* The precision error of the cable length is +/- 10 meters */
#define IGP01E1000_AGC_RANGE 10
-#define IGP02E1000_AGC_RANGE 10
+#define IGP02E1000_AGC_RANGE 15
/* IGP01E1000 PCS Initialization register */
/* bits 3:6 in the PCS registers stores the channels polarity */
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index ee687c902a20..6b72f6acdd54 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -43,7 +43,7 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "6.0.60-k2"DRIVERNAPI
+#define DRV_VERSION "6.1.16-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
@@ -80,6 +80,9 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x1026),
INTEL_E1000_ETHERNET_DEVICE(0x1027),
INTEL_E1000_ETHERNET_DEVICE(0x1028),
+ INTEL_E1000_ETHERNET_DEVICE(0x105E),
+ INTEL_E1000_ETHERNET_DEVICE(0x105F),
+ INTEL_E1000_ETHERNET_DEVICE(0x1060),
INTEL_E1000_ETHERNET_DEVICE(0x1075),
INTEL_E1000_ETHERNET_DEVICE(0x1076),
INTEL_E1000_ETHERNET_DEVICE(0x1077),
@@ -88,10 +91,13 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x107A),
INTEL_E1000_ETHERNET_DEVICE(0x107B),
INTEL_E1000_ETHERNET_DEVICE(0x107C),
+ INTEL_E1000_ETHERNET_DEVICE(0x107D),
+ INTEL_E1000_ETHERNET_DEVICE(0x107E),
+ INTEL_E1000_ETHERNET_DEVICE(0x107F),
INTEL_E1000_ETHERNET_DEVICE(0x108A),
INTEL_E1000_ETHERNET_DEVICE(0x108B),
INTEL_E1000_ETHERNET_DEVICE(0x108C),
- INTEL_E1000_ETHERNET_DEVICE(0x1099),
+ INTEL_E1000_ETHERNET_DEVICE(0x109A),
/* required last entry */
{0,}
};
@@ -102,10 +108,18 @@ int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
void e1000_reset(struct e1000_adapter *adapter);
int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
-int e1000_setup_tx_resources(struct e1000_adapter *adapter);
-int e1000_setup_rx_resources(struct e1000_adapter *adapter);
-void e1000_free_tx_resources(struct e1000_adapter *adapter);
-void e1000_free_rx_resources(struct e1000_adapter *adapter);
+int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
+int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
+void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
+void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
+int e1000_setup_tx_resources(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *txdr);
+int e1000_setup_rx_resources(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rxdr);
+void e1000_free_tx_resources(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring);
+void e1000_free_rx_resources(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
void e1000_update_stats(struct e1000_adapter *adapter);
/* Local Function Prototypes */
@@ -114,14 +128,22 @@ static int e1000_init_module(void);
static void e1000_exit_module(void);
static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void __devexit e1000_remove(struct pci_dev *pdev);
+static int e1000_alloc_queues(struct e1000_adapter *adapter);
+#ifdef CONFIG_E1000_MQ
+static void e1000_setup_queue_mapping(struct e1000_adapter *adapter);
+#endif
static int e1000_sw_init(struct e1000_adapter *adapter);
static int e1000_open(struct net_device *netdev);
static int e1000_close(struct net_device *netdev);
static void e1000_configure_tx(struct e1000_adapter *adapter);
static void e1000_configure_rx(struct e1000_adapter *adapter);
static void e1000_setup_rctl(struct e1000_adapter *adapter);
-static void e1000_clean_tx_ring(struct e1000_adapter *adapter);
-static void e1000_clean_rx_ring(struct e1000_adapter *adapter);
+static void e1000_clean_all_tx_rings(struct e1000_adapter *adapter);
+static void e1000_clean_all_rx_rings(struct e1000_adapter *adapter);
+static void e1000_clean_tx_ring(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring);
+static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
static void e1000_set_multi(struct net_device *netdev);
static void e1000_update_phy_info(unsigned long data);
static void e1000_watchdog(unsigned long data);
@@ -132,19 +154,26 @@ static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
static int e1000_set_mac(struct net_device *netdev, void *p);
static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
-static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter);
+static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring);
#ifdef CONFIG_E1000_NAPI
-static int e1000_clean(struct net_device *netdev, int *budget);
+static int e1000_clean(struct net_device *poll_dev, int *budget);
static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
#else
-static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter);
-static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter);
+static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
+static boolean_t e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
#endif
-static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
-static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter);
+static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
+static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring);
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
int cmd);
@@ -172,6 +201,11 @@ static int e1000_resume(struct pci_dev *pdev);
static void e1000_netpoll (struct net_device *netdev);
#endif
+#ifdef CONFIG_E1000_MQ
+/* for multiple Rx queues */
+void e1000_rx_schedule(void *data);
+#endif
+
/* Exported from other modules */
extern void e1000_check_options(struct e1000_adapter *adapter);
@@ -289,7 +323,7 @@ int
e1000_up(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- int err;
+ int i, err;
/* hardware has been reset, we need to reload some things */
@@ -308,7 +342,8 @@ e1000_up(struct e1000_adapter *adapter)
e1000_configure_tx(adapter);
e1000_setup_rctl(adapter);
e1000_configure_rx(adapter);
- adapter->alloc_rx_buf(adapter);
+ for (i = 0; i < adapter->num_queues; i++)
+ adapter->alloc_rx_buf(adapter, &adapter->rx_ring[i]);
#ifdef CONFIG_PCI_MSI
if(adapter->hw.mac_type > e1000_82547_rev_2) {
@@ -344,6 +379,9 @@ e1000_down(struct e1000_adapter *adapter)
struct net_device *netdev = adapter->netdev;
e1000_irq_disable(adapter);
+#ifdef CONFIG_E1000_MQ
+ while (atomic_read(&adapter->rx_sched_call_data.count) != 0);
+#endif
free_irq(adapter->pdev->irq, netdev);
#ifdef CONFIG_PCI_MSI
if(adapter->hw.mac_type > e1000_82547_rev_2 &&
@@ -363,11 +401,10 @@ e1000_down(struct e1000_adapter *adapter)
netif_stop_queue(netdev);
e1000_reset(adapter);
- e1000_clean_tx_ring(adapter);
- e1000_clean_rx_ring(adapter);
+ e1000_clean_all_tx_rings(adapter);
+ e1000_clean_all_rx_rings(adapter);
- /* If WoL is not enabled
- * and management mode is not IAMT
+ /* If WoL is not enabled and management mode is not IAMT
* Power down the PHY so no link is implied when interface is down */
if(!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
adapter->hw.media_type == e1000_media_type_copper &&
@@ -398,6 +435,10 @@ e1000_reset(struct e1000_adapter *adapter)
case e1000_82547_rev_2:
pba = E1000_PBA_30K;
break;
+ case e1000_82571:
+ case e1000_82572:
+ pba = E1000_PBA_38K;
+ break;
case e1000_82573:
pba = E1000_PBA_12K;
break;
@@ -475,6 +516,7 @@ e1000_probe(struct pci_dev *pdev,
struct net_device *netdev;
struct e1000_adapter *adapter;
unsigned long mmio_start, mmio_len;
+ uint32_t ctrl_ext;
uint32_t swsm;
static int cards_found = 0;
@@ -614,8 +656,9 @@ e1000_probe(struct pci_dev *pdev,
if(e1000_read_mac_addr(&adapter->hw))
DPRINTK(PROBE, ERR, "EEPROM Read Error\n");
memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+ memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
- if(!is_valid_ether_addr(netdev->dev_addr)) {
+ if(!is_valid_ether_addr(netdev->perm_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
err = -EIO;
goto err_eeprom;
@@ -687,6 +730,12 @@ e1000_probe(struct pci_dev *pdev,
/* Let firmware know the driver has taken over */
switch(adapter->hw.mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+ break;
case e1000_82573:
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
@@ -731,7 +780,11 @@ e1000_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
+ uint32_t ctrl_ext;
uint32_t manc, swsm;
+#ifdef CONFIG_E1000_NAPI
+ int i;
+#endif
flush_scheduled_work();
@@ -745,6 +798,12 @@ e1000_remove(struct pci_dev *pdev)
}
switch(adapter->hw.mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+ break;
case e1000_82573:
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
@@ -756,13 +815,27 @@ e1000_remove(struct pci_dev *pdev)
}
unregister_netdev(netdev);
+#ifdef CONFIG_E1000_NAPI
+ for (i = 0; i < adapter->num_queues; i++)
+ __dev_put(&adapter->polling_netdev[i]);
+#endif
if(!e1000_check_phy_reset_block(&adapter->hw))
e1000_phy_hw_reset(&adapter->hw);
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+#ifdef CONFIG_E1000_NAPI
+ kfree(adapter->polling_netdev);
+#endif
+
iounmap(adapter->hw.hw_addr);
pci_release_regions(pdev);
+#ifdef CONFIG_E1000_MQ
+ free_percpu(adapter->cpu_netdev);
+ free_percpu(adapter->cpu_tx_ring);
+#endif
free_netdev(netdev);
pci_disable_device(pdev);
@@ -783,6 +856,9 @@ e1000_sw_init(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
+#ifdef CONFIG_E1000_NAPI
+ int i;
+#endif
/* PCI config space info */
@@ -840,13 +916,122 @@ e1000_sw_init(struct e1000_adapter *adapter)
hw->master_slave = E1000_MASTER_SLAVE;
}
+#ifdef CONFIG_E1000_MQ
+ /* Number of supported queues */
+ switch (hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ adapter->num_queues = 2;
+ break;
+ default:
+ adapter->num_queues = 1;
+ break;
+ }
+ adapter->num_queues = min(adapter->num_queues, num_online_cpus());
+#else
+ adapter->num_queues = 1;
+#endif
+
+ if (e1000_alloc_queues(adapter)) {
+ DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n");
+ return -ENOMEM;
+ }
+
+#ifdef CONFIG_E1000_NAPI
+ for (i = 0; i < adapter->num_queues; i++) {
+ adapter->polling_netdev[i].priv = adapter;
+ adapter->polling_netdev[i].poll = &e1000_clean;
+ adapter->polling_netdev[i].weight = 64;
+ dev_hold(&adapter->polling_netdev[i]);
+ set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state);
+ }
+#endif
+
+#ifdef CONFIG_E1000_MQ
+ e1000_setup_queue_mapping(adapter);
+#endif
+
atomic_set(&adapter->irq_sem, 1);
spin_lock_init(&adapter->stats_lock);
- spin_lock_init(&adapter->tx_lock);
return 0;
}
+/**
+ * e1000_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time. The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
+ **/
+
+static int __devinit
+e1000_alloc_queues(struct e1000_adapter *adapter)
+{
+ int size;
+
+ size = sizeof(struct e1000_tx_ring) * adapter->num_queues;
+ adapter->tx_ring = kmalloc(size, GFP_KERNEL);
+ if (!adapter->tx_ring)
+ return -ENOMEM;
+ memset(adapter->tx_ring, 0, size);
+
+ size = sizeof(struct e1000_rx_ring) * adapter->num_queues;
+ adapter->rx_ring = kmalloc(size, GFP_KERNEL);
+ if (!adapter->rx_ring) {
+ kfree(adapter->tx_ring);
+ return -ENOMEM;
+ }
+ memset(adapter->rx_ring, 0, size);
+
+#ifdef CONFIG_E1000_NAPI
+ size = sizeof(struct net_device) * adapter->num_queues;
+ adapter->polling_netdev = kmalloc(size, GFP_KERNEL);
+ if (!adapter->polling_netdev) {
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+ return -ENOMEM;
+ }
+ memset(adapter->polling_netdev, 0, size);
+#endif
+
+ return E1000_SUCCESS;
+}
+
+#ifdef CONFIG_E1000_MQ
+static void __devinit
+e1000_setup_queue_mapping(struct e1000_adapter *adapter)
+{
+ int i, cpu;
+
+ adapter->rx_sched_call_data.func = e1000_rx_schedule;
+ adapter->rx_sched_call_data.info = adapter->netdev;
+ cpus_clear(adapter->rx_sched_call_data.cpumask);
+
+ adapter->cpu_netdev = alloc_percpu(struct net_device *);
+ adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *);
+
+ lock_cpu_hotplug();
+ i = 0;
+ for_each_online_cpu(cpu) {
+ *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = &adapter->tx_ring[i % adapter->num_queues];
+ /* This is incomplete because we'd like to assign separate
+ * physical cpus to these netdev polling structures and
+ * avoid saturating a subset of cpus.
+ */
+ if (i < adapter->num_queues) {
+ *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i];
+ adapter->cpu_for_queue[i] = cpu;
+ } else
+ *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL;
+
+ i++;
+ }
+ unlock_cpu_hotplug();
+}
+#endif
+
/**
* e1000_open - Called when a network interface is made active
* @netdev: network interface device structure
@@ -868,12 +1053,12 @@ e1000_open(struct net_device *netdev)
/* allocate transmit descriptors */
- if((err = e1000_setup_tx_resources(adapter)))
+ if ((err = e1000_setup_all_tx_resources(adapter)))
goto err_setup_tx;
/* allocate receive descriptors */
- if((err = e1000_setup_rx_resources(adapter)))
+ if ((err = e1000_setup_all_rx_resources(adapter)))
goto err_setup_rx;
if((err = e1000_up(adapter)))
@@ -887,9 +1072,9 @@ e1000_open(struct net_device *netdev)
return E1000_SUCCESS;
err_up:
- e1000_free_rx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
err_setup_rx:
- e1000_free_tx_resources(adapter);
+ e1000_free_all_tx_resources(adapter);
err_setup_tx:
e1000_reset(adapter);
@@ -915,8 +1100,8 @@ e1000_close(struct net_device *netdev)
e1000_down(adapter);
- e1000_free_tx_resources(adapter);
- e1000_free_rx_resources(adapter);
+ e1000_free_all_tx_resources(adapter);
+ e1000_free_all_rx_resources(adapter);
if((adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) {
@@ -951,14 +1136,15 @@ e1000_check_64k_bound(struct e1000_adapter *adapter,
/**
* e1000_setup_tx_resources - allocate Tx resources (Descriptors)
* @adapter: board private structure
+ * @txdr: tx descriptor ring (for a specific queue) to setup
*
* Return 0 on success, negative on failure
**/
int
-e1000_setup_tx_resources(struct e1000_adapter *adapter)
+e1000_setup_tx_resources(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *txdr)
{
- struct e1000_desc_ring *txdr = &adapter->tx_ring;
struct pci_dev *pdev = adapter->pdev;
int size;
@@ -970,6 +1156,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter)
return -ENOMEM;
}
memset(txdr->buffer_info, 0, size);
+ memset(&txdr->previous_buffer_info, 0, sizeof(struct e1000_buffer));
/* round up to nearest 4K */
@@ -1018,10 +1205,40 @@ setup_tx_desc_die:
txdr->next_to_use = 0;
txdr->next_to_clean = 0;
+ spin_lock_init(&txdr->tx_lock);
return 0;
}
+/**
+ * e1000_setup_all_tx_resources - wrapper to allocate Tx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+int
+e1000_setup_all_tx_resources(struct e1000_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_queues; i++) {
+ err = e1000_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Tx Queue %u failed\n", i);
+ break;
+ }
+ }
+
+ return err;
+}
+
/**
* e1000_configure_tx - Configure 8254x Transmit Unit after Reset
* @adapter: board private structure
@@ -1032,23 +1249,43 @@ setup_tx_desc_die:
static void
e1000_configure_tx(struct e1000_adapter *adapter)
{
- uint64_t tdba = adapter->tx_ring.dma;
- uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc);
- uint32_t tctl, tipg;
-
- E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000ffffffffULL));
- E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32));
-
- E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen);
+ uint64_t tdba;
+ struct e1000_hw *hw = &adapter->hw;
+ uint32_t tdlen, tctl, tipg, tarc;
/* Setup the HW Tx Head and Tail descriptor pointers */
- E1000_WRITE_REG(&adapter->hw, TDH, 0);
- E1000_WRITE_REG(&adapter->hw, TDT, 0);
+ switch (adapter->num_queues) {
+ case 2:
+ tdba = adapter->tx_ring[1].dma;
+ tdlen = adapter->tx_ring[1].count *
+ sizeof(struct e1000_tx_desc);
+ E1000_WRITE_REG(hw, TDBAL1, (tdba & 0x00000000ffffffffULL));
+ E1000_WRITE_REG(hw, TDBAH1, (tdba >> 32));
+ E1000_WRITE_REG(hw, TDLEN1, tdlen);
+ E1000_WRITE_REG(hw, TDH1, 0);
+ E1000_WRITE_REG(hw, TDT1, 0);
+ adapter->tx_ring[1].tdh = E1000_TDH1;
+ adapter->tx_ring[1].tdt = E1000_TDT1;
+ /* Fall Through */
+ case 1:
+ default:
+ tdba = adapter->tx_ring[0].dma;
+ tdlen = adapter->tx_ring[0].count *
+ sizeof(struct e1000_tx_desc);
+ E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
+ E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
+ E1000_WRITE_REG(hw, TDLEN, tdlen);
+ E1000_WRITE_REG(hw, TDH, 0);
+ E1000_WRITE_REG(hw, TDT, 0);
+ adapter->tx_ring[0].tdh = E1000_TDH;
+ adapter->tx_ring[0].tdt = E1000_TDT;
+ break;
+ }
/* Set the default values for the Tx Inter Packet Gap timer */
- switch (adapter->hw.mac_type) {
+ switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
tipg = DEFAULT_82542_TIPG_IPGT;
@@ -1056,67 +1293,81 @@ e1000_configure_tx(struct e1000_adapter *adapter)
tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
break;
default:
- if(adapter->hw.media_type == e1000_media_type_fiber ||
- adapter->hw.media_type == e1000_media_type_internal_serdes)
+ if (hw->media_type == e1000_media_type_fiber ||
+ hw->media_type == e1000_media_type_internal_serdes)
tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
else
tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
}
- E1000_WRITE_REG(&adapter->hw, TIPG, tipg);
+ E1000_WRITE_REG(hw, TIPG, tipg);
/* Set the Tx Interrupt Delay register */
- E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay);
- if(adapter->hw.mac_type >= e1000_82540)
- E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay);
+ E1000_WRITE_REG(hw, TIDV, adapter->tx_int_delay);
+ if (hw->mac_type >= e1000_82540)
+ E1000_WRITE_REG(hw, TADV, adapter->tx_abs_int_delay);
/* Program the Transmit Control Register */
- tctl = E1000_READ_REG(&adapter->hw, TCTL);
+ tctl = E1000_READ_REG(hw, TCTL);
tctl &= ~E1000_TCTL_CT;
- tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
+ tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_RTLC |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
- E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+ E1000_WRITE_REG(hw, TCTL, tctl);
- e1000_config_collision_dist(&adapter->hw);
+ if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) {
+ tarc = E1000_READ_REG(hw, TARC0);
+ tarc |= ((1 << 25) | (1 << 21));
+ E1000_WRITE_REG(hw, TARC0, tarc);
+ tarc = E1000_READ_REG(hw, TARC1);
+ tarc |= (1 << 25);
+ if (tctl & E1000_TCTL_MULR)
+ tarc &= ~(1 << 28);
+ else
+ tarc |= (1 << 28);
+ E1000_WRITE_REG(hw, TARC1, tarc);
+ }
+
+ e1000_config_collision_dist(hw);
/* Setup Transmit Descriptor Settings for eop descriptor */
adapter->txd_cmd = E1000_TXD_CMD_IDE | E1000_TXD_CMD_EOP |
E1000_TXD_CMD_IFCS;
- if(adapter->hw.mac_type < e1000_82543)
+ if (hw->mac_type < e1000_82543)
adapter->txd_cmd |= E1000_TXD_CMD_RPS;
else
adapter->txd_cmd |= E1000_TXD_CMD_RS;
/* Cache if we're 82544 running in PCI-X because we'll
* need this to apply a workaround later in the send path. */
- if(adapter->hw.mac_type == e1000_82544 &&
- adapter->hw.bus_type == e1000_bus_type_pcix)
+ if (hw->mac_type == e1000_82544 &&
+ hw->bus_type == e1000_bus_type_pcix)
adapter->pcix_82544 = 1;
}
/**
* e1000_setup_rx_resources - allocate Rx resources (Descriptors)
* @adapter: board private structure
+ * @rxdr: rx descriptor ring (for a specific queue) to setup
*
* Returns 0 on success, negative on failure
**/
int
-e1000_setup_rx_resources(struct e1000_adapter *adapter)
+e1000_setup_rx_resources(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rxdr)
{
- struct e1000_desc_ring *rxdr = &adapter->rx_ring;
struct pci_dev *pdev = adapter->pdev;
int size, desc_len;
size = sizeof(struct e1000_buffer) * rxdr->count;
rxdr->buffer_info = vmalloc(size);
- if(!rxdr->buffer_info) {
+ if (!rxdr->buffer_info) {
DPRINTK(PROBE, ERR,
"Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
@@ -1156,13 +1407,13 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter)
rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
- if(!rxdr->desc) {
+ if (!rxdr->desc) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate memory for the receive descriptor ring\n");
setup_rx_desc_die:
vfree(rxdr->buffer_info);
kfree(rxdr->ps_page);
kfree(rxdr->ps_page_dma);
- DPRINTK(PROBE, ERR,
- "Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
}
@@ -1174,9 +1425,12 @@ setup_rx_desc_die:
"at %p\n", rxdr->size, rxdr->desc);
/* Try again, without freeing the previous */
rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
- if(!rxdr->desc) {
/* Failed allocation, critical failure */
+ if (!rxdr->desc) {
pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate memory "
+ "for the receive descriptor ring\n");
goto setup_rx_desc_die;
}
@@ -1188,10 +1442,7 @@ setup_rx_desc_die:
DPRINTK(PROBE, ERR,
"Unable to allocate aligned memory "
"for the receive descriptor ring\n");
- vfree(rxdr->buffer_info);
- kfree(rxdr->ps_page);
- kfree(rxdr->ps_page_dma);
- return -ENOMEM;
+ goto setup_rx_desc_die;
} else {
/* Free old allocation, new allocation was successful */
pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
@@ -1205,16 +1456,49 @@ setup_rx_desc_die:
return 0;
}
+/**
+ * e1000_setup_all_rx_resources - wrapper to allocate Rx resources
+ * (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not). It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+int
+e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
+{
+ int i, err = 0;
+
+ for (i = 0; i < adapter->num_queues; i++) {
+ err = e1000_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+ if (err) {
+ DPRINTK(PROBE, ERR,
+ "Allocation for Rx Queue %u failed\n", i);
+ break;
+ }
+ }
+
+ return err;
+}
+
/**
* e1000_setup_rctl - configure the receive control registers
* @adapter: Board private structure
**/
-
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+ (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
static void
e1000_setup_rctl(struct e1000_adapter *adapter)
{
uint32_t rctl, rfctl;
uint32_t psrctl = 0;
+#ifdef CONFIG_E1000_PACKET_SPLIT
+ uint32_t pages = 0;
+#endif
rctl = E1000_READ_REG(&adapter->hw, RCTL);
@@ -1235,7 +1519,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
rctl |= E1000_RCTL_LPE;
/* Setup buffer sizes */
- if(adapter->hw.mac_type == e1000_82573) {
+ if(adapter->hw.mac_type >= e1000_82571) {
/* We can now specify buffers in 1K increments.
* BSIZE and BSEX are ignored in this case. */
rctl |= adapter->rx_buffer_len << 0x11;
@@ -1268,11 +1552,14 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
* followed by the page buffers. Therefore, skb->data is
* sized to hold the largest protocol header.
*/
- adapter->rx_ps = (adapter->hw.mac_type > e1000_82547_rev_2)
- && (adapter->netdev->mtu
- < ((3 * PAGE_SIZE) + adapter->rx_ps_bsize0));
+ pages = PAGE_USE_COUNT(adapter->netdev->mtu);
+ if ((adapter->hw.mac_type > e1000_82547_rev_2) && (pages <= 3) &&
+ PAGE_SIZE <= 16384)
+ adapter->rx_ps_pages = pages;
+ else
+ adapter->rx_ps_pages = 0;
#endif
- if(adapter->rx_ps) {
+ if (adapter->rx_ps_pages) {
/* Configure extra packet-split registers */
rfctl = E1000_READ_REG(&adapter->hw, RFCTL);
rfctl |= E1000_RFCTL_EXTEN;
@@ -1284,12 +1571,19 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
psrctl |= adapter->rx_ps_bsize0 >>
E1000_PSRCTL_BSIZE0_SHIFT;
- psrctl |= PAGE_SIZE >>
- E1000_PSRCTL_BSIZE1_SHIFT;
- psrctl |= PAGE_SIZE <<
- E1000_PSRCTL_BSIZE2_SHIFT;
- psrctl |= PAGE_SIZE <<
- E1000_PSRCTL_BSIZE3_SHIFT;
+
+ switch (adapter->rx_ps_pages) {
+ case 3:
+ psrctl |= PAGE_SIZE <<
+ E1000_PSRCTL_BSIZE3_SHIFT;
+ case 2:
+ psrctl |= PAGE_SIZE <<
+ E1000_PSRCTL_BSIZE2_SHIFT;
+ case 1:
+ psrctl |= PAGE_SIZE >>
+ E1000_PSRCTL_BSIZE1_SHIFT;
+ break;
+ }
E1000_WRITE_REG(&adapter->hw, PSRCTL, psrctl);
}
@@ -1307,91 +1601,181 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
static void
e1000_configure_rx(struct e1000_adapter *adapter)
{
- uint64_t rdba = adapter->rx_ring.dma;
- uint32_t rdlen, rctl, rxcsum;
+ uint64_t rdba;
+ struct e1000_hw *hw = &adapter->hw;
+ uint32_t rdlen, rctl, rxcsum, ctrl_ext;
+#ifdef CONFIG_E1000_MQ
+ uint32_t reta, mrqc;
+ int i;
+#endif
- if(adapter->rx_ps) {
- rdlen = adapter->rx_ring.count *
+ if (adapter->rx_ps_pages) {
+ rdlen = adapter->rx_ring[0].count *
sizeof(union e1000_rx_desc_packet_split);
adapter->clean_rx = e1000_clean_rx_irq_ps;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
} else {
- rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc);
+ rdlen = adapter->rx_ring[0].count *
+ sizeof(struct e1000_rx_desc);
adapter->clean_rx = e1000_clean_rx_irq;
adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
}
/* disable receives while setting up the descriptors */
- rctl = E1000_READ_REG(&adapter->hw, RCTL);
- E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
+ rctl = E1000_READ_REG(hw, RCTL);
+ E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
/* set the Receive Delay Timer Register */
- E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+ E1000_WRITE_REG(hw, RDTR, adapter->rx_int_delay);
- if(adapter->hw.mac_type >= e1000_82540) {
- E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay);
+ if (hw->mac_type >= e1000_82540) {
+ E1000_WRITE_REG(hw, RADV, adapter->rx_abs_int_delay);
if(adapter->itr > 1)
- E1000_WRITE_REG(&adapter->hw, ITR,
+ E1000_WRITE_REG(hw, ITR,
1000000000 / (adapter->itr * 256));
}
- /* Setup the Base and Length of the Rx Descriptor Ring */
- E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL));
- E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
+ if (hw->mac_type >= e1000_82571) {
+ /* Reset delay timers after every interrupt */
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_CANC;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ E1000_WRITE_FLUSH(hw);
+ }
- E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen);
+ /* Setup the HW Rx Head and Tail Descriptor Pointers and
+ * the Base and Length of the Rx Descriptor Ring */
+ switch (adapter->num_queues) {
+#ifdef CONFIG_E1000_MQ
+ case 2:
+ rdba = adapter->rx_ring[1].dma;
+ E1000_WRITE_REG(hw, RDBAL1, (rdba & 0x00000000ffffffffULL));
+ E1000_WRITE_REG(hw, RDBAH1, (rdba >> 32));
+ E1000_WRITE_REG(hw, RDLEN1, rdlen);
+ E1000_WRITE_REG(hw, RDH1, 0);
+ E1000_WRITE_REG(hw, RDT1, 0);
+ adapter->rx_ring[1].rdh = E1000_RDH1;
+ adapter->rx_ring[1].rdt = E1000_RDT1;
+ /* Fall Through */
+#endif
+ case 1:
+ default:
+ rdba = adapter->rx_ring[0].dma;
+ E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
+ E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
+ E1000_WRITE_REG(hw, RDLEN, rdlen);
+ E1000_WRITE_REG(hw, RDH, 0);
+ E1000_WRITE_REG(hw, RDT, 0);
+ adapter->rx_ring[0].rdh = E1000_RDH;
+ adapter->rx_ring[0].rdt = E1000_RDT;
+ break;
+ }
- /* Setup the HW Rx Head and Tail Descriptor Pointers */
- E1000_WRITE_REG(&adapter->hw, RDH, 0);
- E1000_WRITE_REG(&adapter->hw, RDT, 0);
+#ifdef CONFIG_E1000_MQ
+ if (adapter->num_queues > 1) {
+ uint32_t random[10];
+
+ get_random_bytes(&random[0], 40);
+
+ if (hw->mac_type <= e1000_82572) {
+ E1000_WRITE_REG(hw, RSSIR, 0);
+ E1000_WRITE_REG(hw, RSSIM, 0);
+ }
+
+ switch (adapter->num_queues) {
+ case 2:
+ default:
+ reta = 0x00800080;
+ mrqc = E1000_MRQC_ENABLE_RSS_2Q;
+ break;
+ }
+
+ /* Fill out redirection table */
+ for (i = 0; i < 32; i++)
+ E1000_WRITE_REG_ARRAY(hw, RETA, i, reta);
+ /* Fill out hash function seeds */
+ for (i = 0; i < 10; i++)
+ E1000_WRITE_REG_ARRAY(hw, RSSRK, i, random[i]);
+
+ mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 |
+ E1000_MRQC_RSS_FIELD_IPV4_TCP);
+ E1000_WRITE_REG(hw, MRQC, mrqc);
+ }
+
+ /* Multiqueue and packet checksumming are mutually exclusive. */
+ if (hw->mac_type >= e1000_82571) {
+ rxcsum = E1000_READ_REG(hw, RXCSUM);
+ rxcsum |= E1000_RXCSUM_PCSD;
+ E1000_WRITE_REG(hw, RXCSUM, rxcsum);
+ }
+
+#else
/* Enable 82543 Receive Checksum Offload for TCP and UDP */
- if(adapter->hw.mac_type >= e1000_82543) {
- rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
+ if (hw->mac_type >= e1000_82543) {
+ rxcsum = E1000_READ_REG(hw, RXCSUM);
if(adapter->rx_csum == TRUE) {
rxcsum |= E1000_RXCSUM_TUOFL;
- /* Enable 82573 IPv4 payload checksum for UDP fragments
+ /* Enable 82571 IPv4 payload checksum for UDP fragments
* Must be used in conjunction with packet-split. */
- if((adapter->hw.mac_type > e1000_82547_rev_2) &&
- (adapter->rx_ps)) {
+ if ((hw->mac_type >= e1000_82571) &&
+ (adapter->rx_ps_pages)) {
rxcsum |= E1000_RXCSUM_IPPCSE;
}
} else {
rxcsum &= ~E1000_RXCSUM_TUOFL;
/* don't need to clear IPPCSE as it defaults to 0 */
}
- E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum);
+ E1000_WRITE_REG(hw, RXCSUM, rxcsum);
}
+#endif /* CONFIG_E1000_MQ */
- if (adapter->hw.mac_type == e1000_82573)
- E1000_WRITE_REG(&adapter->hw, ERT, 0x0100);
+ if (hw->mac_type == e1000_82573)
+ E1000_WRITE_REG(hw, ERT, 0x0100);
/* Enable Receives */
- E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+ E1000_WRITE_REG(hw, RCTL, rctl);
}
/**
- * e1000_free_tx_resources - Free Tx Resources
+ * e1000_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+
+void
+e1000_free_tx_resources(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ e1000_clean_tx_ring(adapter, tx_ring);
+
+ vfree(tx_ring->buffer_info);
+ tx_ring->buffer_info = NULL;
+
+ pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+ tx_ring->desc = NULL;
+}
+
+/**
+ * e1000_free_all_tx_resources - Free Tx Resources for All Queues
* @adapter: board private structure
*
* Free all transmit software resources
**/
void
-e1000_free_tx_resources(struct e1000_adapter *adapter)
+e1000_free_all_tx_resources(struct e1000_adapter *adapter)
{
- struct pci_dev *pdev = adapter->pdev;
+ int i;
- e1000_clean_tx_ring(adapter);
-
- vfree(adapter->tx_ring.buffer_info);
- adapter->tx_ring.buffer_info = NULL;
-
- pci_free_consistent(pdev, adapter->tx_ring.size,
- adapter->tx_ring.desc, adapter->tx_ring.dma);
-
- adapter->tx_ring.desc = NULL;
+ for (i = 0; i < adapter->num_queues; i++)
+ e1000_free_tx_resources(adapter, &adapter->tx_ring[i]);
}
static inline void
@@ -1414,21 +1798,22 @@ e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
/**
* e1000_clean_tx_ring - Free Tx Buffers
* @adapter: board private structure
+ * @tx_ring: ring to be cleaned
**/
static void
-e1000_clean_tx_ring(struct e1000_adapter *adapter)
+e1000_clean_tx_ring(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring)
{
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct e1000_buffer *buffer_info;
unsigned long size;
unsigned int i;
/* Free all the Tx ring sk_buffs */
- if (likely(adapter->previous_buffer_info.skb != NULL)) {
+ if (likely(tx_ring->previous_buffer_info.skb != NULL)) {
e1000_unmap_and_free_tx_resource(adapter,
- &adapter->previous_buffer_info);
+ &tx_ring->previous_buffer_info);
}
for(i = 0; i < tx_ring->count; i++) {
@@ -1446,24 +1831,39 @@ e1000_clean_tx_ring(struct e1000_adapter *adapter)
tx_ring->next_to_use = 0;
tx_ring->next_to_clean = 0;
- E1000_WRITE_REG(&adapter->hw, TDH, 0);
- E1000_WRITE_REG(&adapter->hw, TDT, 0);
+ writel(0, adapter->hw.hw_addr + tx_ring->tdh);
+ writel(0, adapter->hw.hw_addr + tx_ring->tdt);
+}
+
+/**
+ * e1000_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_all_tx_rings(struct e1000_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_queues; i++)
+ e1000_clean_tx_ring(adapter, &adapter->tx_ring[i]);
}
/**
* e1000_free_rx_resources - Free Rx Resources
* @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
*
* Free all receive software resources
**/
void
-e1000_free_rx_resources(struct e1000_adapter *adapter)
+e1000_free_rx_resources(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct pci_dev *pdev = adapter->pdev;
- e1000_clean_rx_ring(adapter);
+ e1000_clean_rx_ring(adapter, rx_ring);
vfree(rx_ring->buffer_info);
rx_ring->buffer_info = NULL;
@@ -1478,14 +1878,31 @@ e1000_free_rx_resources(struct e1000_adapter *adapter)
}
/**
- * e1000_clean_rx_ring - Free Rx Buffers
+ * e1000_free_all_rx_resources - Free Rx Resources for All Queues
* @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+
+void
+e1000_free_all_rx_resources(struct e1000_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_queues; i++)
+ e1000_free_rx_resources(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * e1000_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ * @rx_ring: ring to free buffers from
**/
static void
-e1000_clean_rx_ring(struct e1000_adapter *adapter)
+e1000_clean_rx_ring(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct e1000_buffer *buffer_info;
struct e1000_ps_page *ps_page;
struct e1000_ps_page_dma *ps_page_dma;
@@ -1508,7 +1925,7 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter)
dev_kfree_skb(buffer_info->skb);
buffer_info->skb = NULL;
- for(j = 0; j < PS_PAGE_BUFFERS; j++) {
+ for(j = 0; j < adapter->rx_ps_pages; j++) {
if(!ps_page->ps_page[j]) break;
pci_unmap_single(pdev,
ps_page_dma->ps_page_dma[j],
@@ -1534,8 +1951,22 @@ e1000_clean_rx_ring(struct e1000_adapter *adapter)
rx_ring->next_to_clean = 0;
rx_ring->next_to_use = 0;
- E1000_WRITE_REG(&adapter->hw, RDH, 0);
- E1000_WRITE_REG(&adapter->hw, RDT, 0);
+ writel(0, adapter->hw.hw_addr + rx_ring->rdh);
+ writel(0, adapter->hw.hw_addr + rx_ring->rdt);
+}
+
+/**
+ * e1000_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_all_rx_rings(struct e1000_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_queues; i++)
+ e1000_clean_rx_ring(adapter, &adapter->rx_ring[i]);
}
/* The 82542 2.0 (revision 2) needs to have the receive unit in reset
@@ -1556,7 +1987,7 @@ e1000_enter_82542_rst(struct e1000_adapter *adapter)
mdelay(5);
if(netif_running(netdev))
- e1000_clean_rx_ring(adapter);
+ e1000_clean_all_rx_rings(adapter);
}
static void
@@ -1576,7 +2007,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
if(netif_running(netdev)) {
e1000_configure_rx(adapter);
- e1000_alloc_rx_buffers(adapter);
+ e1000_alloc_rx_buffers(adapter, &adapter->rx_ring[0]);
}
}
@@ -1607,6 +2038,22 @@ e1000_set_mac(struct net_device *netdev, void *p)
e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
+ /* With 82571 controllers, LAA may be overwritten (with the default)
+ * due to controller reset from the other port. */
+ if (adapter->hw.mac_type == e1000_82571) {
+ /* activate the work around */
+ adapter->hw.laa_is_present = 1;
+
+ /* Hold a copy of the LAA in RAR[14] This is done so that
+ * between the time RAR[0] gets clobbered and the time it
+ * gets fixed (in e1000_watchdog), the actual LAA is in one
+ * of the RARs and no incoming packets directed to this port
+ * are dropped. Eventaully the LAA will be in RAR[0] and
+ * RAR[14] */
+ e1000_rar_set(&adapter->hw, adapter->hw.mac_addr,
+ E1000_RAR_ENTRIES - 1);
+ }
+
if(adapter->hw.mac_type == e1000_82542_rev2_0)
e1000_leave_82542_rst(adapter);
@@ -1629,12 +2076,13 @@ e1000_set_multi(struct net_device *netdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr;
- unsigned long flags;
uint32_t rctl;
uint32_t hash_value;
- int i;
+ int i, rar_entries = E1000_RAR_ENTRIES;
- spin_lock_irqsave(&adapter->tx_lock, flags);
+ /* reserve RAR[14] for LAA over-write work-around */
+ if (adapter->hw.mac_type == e1000_82571)
+ rar_entries--;
/* Check for Promiscuous and All Multicast modes */
@@ -1659,11 +2107,12 @@ e1000_set_multi(struct net_device *netdev)
/* load the first 14 multicast address into the exact filters 1-14
* RAR 0 is used for the station MAC adddress
* if there are not 14 addresses, go ahead and clear the filters
+ * -- with 82571 controllers only 0-13 entries are filled here
*/
mc_ptr = netdev->mc_list;
- for(i = 1; i < E1000_RAR_ENTRIES; i++) {
- if(mc_ptr) {
+ for(i = 1; i < rar_entries; i++) {
+ if (mc_ptr) {
e1000_rar_set(hw, mc_ptr->dmi_addr, i);
mc_ptr = mc_ptr->next;
} else {
@@ -1686,8 +2135,6 @@ e1000_set_multi(struct net_device *netdev)
if(hw->mac_type == e1000_82542_rev2_0)
e1000_leave_82542_rst(adapter);
-
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
}
/* Need to wait a few seconds after link up to get diagnostic information from
@@ -1759,7 +2206,7 @@ static void
e1000_watchdog_task(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- struct e1000_desc_ring *txdr = &adapter->tx_ring;
+ struct e1000_tx_ring *txdr = &adapter->tx_ring[0];
uint32_t link;
e1000_check_for_link(&adapter->hw);
@@ -1818,8 +2265,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
e1000_update_adaptive(&adapter->hw);
- if(!netif_carrier_ok(netdev)) {
- if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) {
+ if (adapter->num_queues == 1 && !netif_carrier_ok(netdev)) {
+ if (E1000_DESC_UNUSED(txdr) + 1 < txdr->count) {
/* We've lost link, so the controller stops DMA,
* but we've got queued Tx work that's never going
* to get done, so reset controller to flush Tx.
@@ -1847,6 +2294,11 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
/* Force detection of hung controller every watchdog period */
adapter->detect_tx_hung = TRUE;
+ /* With 82571 controllers, LAA may be overwritten due to controller
+ * reset from the other port. Set the appropriate LAA in RAR[0] */
+ if (adapter->hw.mac_type == e1000_82571 && adapter->hw.laa_is_present)
+ e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
+
/* Reset the timer */
mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
}
@@ -1859,7 +2311,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
#define E1000_TX_FLAGS_VLAN_SHIFT 16
static inline int
-e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
+e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
+ struct sk_buff *skb)
{
#ifdef NETIF_F_TSO
struct e1000_context_desc *context_desc;
@@ -1910,8 +2363,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
- i = adapter->tx_ring.next_to_use;
- context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
+ i = tx_ring->next_to_use;
+ context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
context_desc->lower_setup.ip_fields.ipcss = ipcss;
context_desc->lower_setup.ip_fields.ipcso = ipcso;
@@ -1923,8 +2376,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
context_desc->cmd_and_length = cpu_to_le32(cmd_length);
- if(++i == adapter->tx_ring.count) i = 0;
- adapter->tx_ring.next_to_use = i;
+ if (++i == tx_ring->count) i = 0;
+ tx_ring->next_to_use = i;
return 1;
}
@@ -1934,7 +2387,8 @@ e1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb)
}
static inline boolean_t
-e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
+ struct sk_buff *skb)
{
struct e1000_context_desc *context_desc;
unsigned int i;
@@ -1943,8 +2397,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
if(likely(skb->ip_summed == CHECKSUM_HW)) {
css = skb->h.raw - skb->data;
- i = adapter->tx_ring.next_to_use;
- context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
+ i = tx_ring->next_to_use;
+ context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
context_desc->upper_setup.tcp_fields.tucss = css;
context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
@@ -1952,8 +2406,8 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
context_desc->tcp_seg_setup.data = 0;
context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
- if(unlikely(++i == adapter->tx_ring.count)) i = 0;
- adapter->tx_ring.next_to_use = i;
+ if (unlikely(++i == tx_ring->count)) i = 0;
+ tx_ring->next_to_use = i;
return TRUE;
}
@@ -1965,11 +2419,10 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
#define E1000_MAX_DATA_PER_TXD (1<tx_ring;
struct e1000_buffer *buffer_info;
unsigned int len = skb->len;
unsigned int offset = 0, size, count = 0, i;
@@ -2065,9 +2518,9 @@ e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb,
}
static inline void
-e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
+e1000_tx_queue(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
+ int tx_flags, int count)
{
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct e1000_tx_desc *tx_desc = NULL;
struct e1000_buffer *buffer_info;
uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
@@ -2113,7 +2566,7 @@ e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
wmb();
tx_ring->next_to_use = i;
- E1000_WRITE_REG(&adapter->hw, TDT, i);
+ writel(i, adapter->hw.hw_addr + tx_ring->tdt);
}
/**
@@ -2206,6 +2659,7 @@ static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_tx_ring *tx_ring;
unsigned int first, max_per_txd = E1000_MAX_DATA_PER_TXD;
unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
unsigned int tx_flags = 0;
@@ -2218,7 +2672,13 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
unsigned int f;
len -= skb->data_len;
- if(unlikely(skb->len <= 0)) {
+#ifdef CONFIG_E1000_MQ
+ tx_ring = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id());
+#else
+ tx_ring = adapter->tx_ring;
+#endif
+
+ if (unlikely(skb->len <= 0)) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -2262,21 +2722,42 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if(adapter->pcix_82544)
count += nr_frags;
- local_irq_save(flags);
- if (!spin_trylock(&adapter->tx_lock)) {
- /* Collision - tell upper layer to requeue */
- local_irq_restore(flags);
- return NETDEV_TX_LOCKED;
- }
+#ifdef NETIF_F_TSO
+ /* TSO Workaround for 82571/2 Controllers -- if skb->data
+ * points to just header, pull a few bytes of payload from
+ * frags into skb->data */
+ if (skb_shinfo(skb)->tso_size) {
+ uint8_t hdr_len;
+ hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
+ if (skb->data_len && (hdr_len < (skb->len - skb->data_len)) &&
+ (adapter->hw.mac_type == e1000_82571 ||
+ adapter->hw.mac_type == e1000_82572)) {
+ unsigned int pull_size;
+ pull_size = min((unsigned int)4, skb->data_len);
+ if (!__pskb_pull_tail(skb, pull_size)) {
+ printk(KERN_ERR "__pskb_pull_tail failed.\n");
+ dev_kfree_skb_any(skb);
+ return -EFAULT;
+ }
+ }
+ }
+#endif
+
if(adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) )
e1000_transfer_dhcp_info(adapter, skb);
+ local_irq_save(flags);
+ if (!spin_trylock(&tx_ring->tx_lock)) {
+ /* Collision - tell upper layer to requeue */
+ local_irq_restore(flags);
+ return NETDEV_TX_LOCKED;
+ }
/* need: count + 2 desc gap to keep tail from touching
* head, otherwise try next time */
- if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < count + 2)) {
+ if (unlikely(E1000_DESC_UNUSED(tx_ring) < count + 2)) {
netif_stop_queue(netdev);
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_BUSY;
}
@@ -2284,7 +2765,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if(unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
netif_stop_queue(netdev);
mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_BUSY;
}
}
@@ -2294,37 +2775,37 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
}
- first = adapter->tx_ring.next_to_use;
+ first = tx_ring->next_to_use;
- tso = e1000_tso(adapter, skb);
+ tso = e1000_tso(adapter, tx_ring, skb);
if (tso < 0) {
dev_kfree_skb_any(skb);
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_OK;
}
if (likely(tso))
tx_flags |= E1000_TX_FLAGS_TSO;
- else if(likely(e1000_tx_csum(adapter, skb)))
+ else if (likely(e1000_tx_csum(adapter, tx_ring, skb)))
tx_flags |= E1000_TX_FLAGS_CSUM;
/* Old method was to assume IPv4 packet by default if TSO was enabled.
- * 82573 hardware supports TSO capabilities for IPv6 as well...
+ * 82571 hardware supports TSO capabilities for IPv6 as well...
* no longer assume, we must. */
- if(likely(skb->protocol == ntohs(ETH_P_IP)))
+ if (likely(skb->protocol == ntohs(ETH_P_IP)))
tx_flags |= E1000_TX_FLAGS_IPV4;
- e1000_tx_queue(adapter,
- e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss),
- tx_flags);
+ e1000_tx_queue(adapter, tx_ring, tx_flags,
+ e1000_tx_map(adapter, tx_ring, skb, first,
+ max_per_txd, nr_frags, mss));
netdev->trans_start = jiffies;
/* Make sure there is space in the ring for the next send. */
- if(unlikely(E1000_DESC_UNUSED(&adapter->tx_ring) < MAX_SKB_FRAGS + 2))
+ if (unlikely(E1000_DESC_UNUSED(tx_ring) < MAX_SKB_FRAGS + 2))
netif_stop_queue(netdev);
- spin_unlock_irqrestore(&adapter->tx_lock, flags);
+ spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_OK;
}
@@ -2388,9 +2869,18 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
return -EINVAL;
}
-#define MAX_STD_JUMBO_FRAME_SIZE 9216
+#define MAX_STD_JUMBO_FRAME_SIZE 9234
/* might want this to be bigger enum check... */
- if (adapter->hw.mac_type == e1000_82573 &&
+ /* 82571 controllers limit jumbo frame size to 10500 bytes */
+ if ((adapter->hw.mac_type == e1000_82571 ||
+ adapter->hw.mac_type == e1000_82572) &&
+ max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
+ DPRINTK(PROBE, ERR, "MTU > 9216 bytes not supported "
+ "on 82571 and 82572 controllers.\n");
+ return -EINVAL;
+ }
+
+ if(adapter->hw.mac_type == e1000_82573 &&
max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
DPRINTK(PROBE, ERR, "Jumbo Frames not supported "
"on 82573\n");
@@ -2578,6 +3068,29 @@ e1000_update_stats(struct e1000_adapter *adapter)
spin_unlock_irqrestore(&adapter->stats_lock, flags);
}
+#ifdef CONFIG_E1000_MQ
+void
+e1000_rx_schedule(void *data)
+{
+ struct net_device *poll_dev, *netdev = data;
+ struct e1000_adapter *adapter = netdev->priv;
+ int this_cpu = get_cpu();
+
+ poll_dev = *per_cpu_ptr(adapter->cpu_netdev, this_cpu);
+ if (poll_dev == NULL) {
+ put_cpu();
+ return;
+ }
+
+ if (likely(netif_rx_schedule_prep(poll_dev)))
+ __netif_rx_schedule(poll_dev);
+ else
+ e1000_irq_enable(adapter);
+
+ put_cpu();
+}
+#endif
+
/**
* e1000_intr - Interrupt Handler
* @irq: interrupt number
@@ -2592,8 +3105,8 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint32_t icr = E1000_READ_REG(hw, ICR);
-#ifndef CONFIG_E1000_NAPI
- unsigned int i;
+#if defined(CONFIG_E1000_NAPI) && defined(CONFIG_E1000_MQ) || !defined(CONFIG_E1000_NAPI)
+ int i;
#endif
if(unlikely(!icr))
@@ -2605,17 +3118,31 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
}
#ifdef CONFIG_E1000_NAPI
- if(likely(netif_rx_schedule_prep(netdev))) {
-
- /* Disable interrupts and register for poll. The flush
- of the posted write is intentionally left out.
- */
-
- atomic_inc(&adapter->irq_sem);
- E1000_WRITE_REG(hw, IMC, ~0);
- __netif_rx_schedule(netdev);
+ atomic_inc(&adapter->irq_sem);
+ E1000_WRITE_REG(hw, IMC, ~0);
+ E1000_WRITE_FLUSH(hw);
+#ifdef CONFIG_E1000_MQ
+ if (atomic_read(&adapter->rx_sched_call_data.count) == 0) {
+ cpu_set(adapter->cpu_for_queue[0],
+ adapter->rx_sched_call_data.cpumask);
+ for (i = 1; i < adapter->num_queues; i++) {
+ cpu_set(adapter->cpu_for_queue[i],
+ adapter->rx_sched_call_data.cpumask);
+ atomic_inc(&adapter->irq_sem);
+ }
+ atomic_set(&adapter->rx_sched_call_data.count, i);
+ smp_call_async_mask(&adapter->rx_sched_call_data);
+ } else {
+ printk("call_data.count == %u\n", atomic_read(&adapter->rx_sched_call_data.count));
}
-#else
+#else /* if !CONFIG_E1000_MQ */
+ if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0])))
+ __netif_rx_schedule(&adapter->polling_netdev[0]);
+ else
+ e1000_irq_enable(adapter);
+#endif /* CONFIG_E1000_MQ */
+
+#else /* if !CONFIG_E1000_NAPI */
/* Writing IMC and IMS is needed for 82547.
Due to Hub Link bus being occupied, an interrupt
de-assertion message is not able to be sent.
@@ -2632,13 +3159,14 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
}
for(i = 0; i < E1000_MAX_INTR; i++)
- if(unlikely(!adapter->clean_rx(adapter) &
- !e1000_clean_tx_irq(adapter)))
+ if(unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
+ !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
break;
if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
e1000_irq_enable(adapter);
-#endif
+
+#endif /* CONFIG_E1000_NAPI */
return IRQ_HANDLED;
}
@@ -2650,22 +3178,37 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
**/
static int
-e1000_clean(struct net_device *netdev, int *budget)
+e1000_clean(struct net_device *poll_dev, int *budget)
{
- struct e1000_adapter *adapter = netdev_priv(netdev);
- int work_to_do = min(*budget, netdev->quota);
- int tx_cleaned;
- int work_done = 0;
+ struct e1000_adapter *adapter;
+ int work_to_do = min(*budget, poll_dev->quota);
+ int tx_cleaned, i = 0, work_done = 0;
- tx_cleaned = e1000_clean_tx_irq(adapter);
- adapter->clean_rx(adapter, &work_done, work_to_do);
+ /* Must NOT use netdev_priv macro here. */
+ adapter = poll_dev->priv;
+
+ /* Keep link state information with original netdev */
+ if (!netif_carrier_ok(adapter->netdev))
+ goto quit_polling;
+
+ while (poll_dev != &adapter->polling_netdev[i]) {
+ i++;
+ if (unlikely(i == adapter->num_queues))
+ BUG();
+ }
+
+ tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]);
+ adapter->clean_rx(adapter, &adapter->rx_ring[i],
+ &work_done, work_to_do);
*budget -= work_done;
- netdev->quota -= work_done;
+ poll_dev->quota -= work_done;
- if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
/* If no Tx and not enough Rx work done, exit the polling mode */
- netif_rx_complete(netdev);
+ if((!tx_cleaned && (work_done == 0)) ||
+ !netif_running(adapter->netdev)) {
+quit_polling:
+ netif_rx_complete(poll_dev);
e1000_irq_enable(adapter);
return 0;
}
@@ -2680,9 +3223,9 @@ e1000_clean(struct net_device *netdev, int *budget)
**/
static boolean_t
-e1000_clean_tx_irq(struct e1000_adapter *adapter)
+e1000_clean_tx_irq(struct e1000_adapter *adapter,
+ struct e1000_tx_ring *tx_ring)
{
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
struct net_device *netdev = adapter->netdev;
struct e1000_tx_desc *tx_desc, *eop_desc;
struct e1000_buffer *buffer_info;
@@ -2693,12 +3236,12 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
- while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+ while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
/* Premature writeback of Tx descriptors clear (free buffers
* and unmap pci_mapping) previous_buffer_info */
- if (likely(adapter->previous_buffer_info.skb != NULL)) {
+ if (likely(tx_ring->previous_buffer_info.skb != NULL)) {
e1000_unmap_and_free_tx_resource(adapter,
- &adapter->previous_buffer_info);
+ &tx_ring->previous_buffer_info);
}
for(cleaned = FALSE; !cleaned; ) {
@@ -2714,7 +3257,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
#ifdef NETIF_F_TSO
} else {
if (cleaned) {
- memcpy(&adapter->previous_buffer_info,
+ memcpy(&tx_ring->previous_buffer_info,
buffer_info,
sizeof(struct e1000_buffer));
memset(buffer_info, 0,
@@ -2732,6 +3275,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
if(unlikely(++i == tx_ring->count)) i = 0;
}
+
+ tx_ring->pkt++;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
@@ -2739,15 +3284,15 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
tx_ring->next_to_clean = i;
- spin_lock(&adapter->tx_lock);
+ spin_lock(&tx_ring->tx_lock);
if(unlikely(cleaned && netif_queue_stopped(netdev) &&
netif_carrier_ok(netdev)))
netif_wake_queue(netdev);
- spin_unlock(&adapter->tx_lock);
- if(adapter->detect_tx_hung) {
+ spin_unlock(&tx_ring->tx_lock);
+ if (adapter->detect_tx_hung) {
/* Detect a transmit hang in hardware, this serializes the
* check with the clearing of time_stamp and movement of i */
adapter->detect_tx_hung = FALSE;
@@ -2771,8 +3316,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
" next_to_watch <%x>\n"
" jiffies <%lx>\n"
" next_to_watch.status <%x>\n",
- E1000_READ_REG(&adapter->hw, TDH),
- E1000_READ_REG(&adapter->hw, TDT),
+ readl(adapter->hw.hw_addr + tx_ring->tdh),
+ readl(adapter->hw.hw_addr + tx_ring->tdt),
tx_ring->next_to_use,
i,
(unsigned long long)tx_ring->buffer_info[i].dma,
@@ -2784,12 +3329,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
}
}
#ifdef NETIF_F_TSO
-
- if( unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) &&
- time_after(jiffies, adapter->previous_buffer_info.time_stamp + HZ)))
+ if (unlikely(!(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) &&
+ time_after(jiffies, tx_ring->previous_buffer_info.time_stamp + HZ)))
e1000_unmap_and_free_tx_resource(
- adapter, &adapter->previous_buffer_info);
-
+ adapter, &tx_ring->previous_buffer_info);
#endif
return cleaned;
}
@@ -2852,13 +3395,14 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
static boolean_t
#ifdef CONFIG_E1000_NAPI
-e1000_clean_rx_irq(struct e1000_adapter *adapter, int *work_done,
- int work_to_do)
+e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do)
#else
-e1000_clean_rx_irq(struct e1000_adapter *adapter)
+e1000_clean_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
#endif
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_rx_desc *rx_desc;
@@ -2944,6 +3488,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter)
}
#endif /* CONFIG_E1000_NAPI */
netdev->last_rx = jiffies;
+ rx_ring->pkt++;
next_desc:
rx_desc->status = 0;
@@ -2953,7 +3498,7 @@ next_desc:
rx_desc = E1000_RX_DESC(*rx_ring, i);
}
rx_ring->next_to_clean = i;
- adapter->alloc_rx_buf(adapter);
+ adapter->alloc_rx_buf(adapter, rx_ring);
return cleaned;
}
@@ -2965,13 +3510,14 @@ next_desc:
static boolean_t
#ifdef CONFIG_E1000_NAPI
-e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, int *work_done,
- int work_to_do)
+e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do)
#else
-e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
+e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
#endif
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
union e1000_rx_desc_packet_split *rx_desc;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
@@ -3027,7 +3573,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
/* Good Receive */
skb_put(skb, length);
- for(j = 0; j < PS_PAGE_BUFFERS; j++) {
+ for(j = 0; j < adapter->rx_ps_pages; j++) {
if(!(length = le16_to_cpu(rx_desc->wb.upper.length[j])))
break;
@@ -3048,11 +3594,13 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
rx_desc->wb.lower.hi_dword.csum_ip.csum, skb);
skb->protocol = eth_type_trans(skb, netdev);
-#ifdef HAVE_RX_ZERO_COPY
if(likely(rx_desc->wb.upper.header_status &
- E1000_RXDPS_HDRSTAT_HDRSP))
+ E1000_RXDPS_HDRSTAT_HDRSP)) {
+ adapter->rx_hdr_split++;
+#ifdef HAVE_RX_ZERO_COPY
skb_shinfo(skb)->zero_copy = TRUE;
#endif
+ }
#ifdef CONFIG_E1000_NAPI
if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
@@ -3071,6 +3619,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
}
#endif /* CONFIG_E1000_NAPI */
netdev->last_rx = jiffies;
+ rx_ring->pkt++;
next_desc:
rx_desc->wb.middle.status_error &= ~0xFF;
@@ -3081,7 +3630,7 @@ next_desc:
staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
}
rx_ring->next_to_clean = i;
- adapter->alloc_rx_buf(adapter);
+ adapter->alloc_rx_buf(adapter, rx_ring);
return cleaned;
}
@@ -3092,9 +3641,9 @@ next_desc:
**/
static void
-e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
+e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
struct e1000_rx_desc *rx_desc;
@@ -3178,7 +3727,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
* applicable for weak-ordered memory model archs,
* such as IA-64). */
wmb();
- E1000_WRITE_REG(&adapter->hw, RDT, i);
+ writel(i, adapter->hw.hw_addr + rx_ring->rdt);
}
if(unlikely(++i == rx_ring->count)) i = 0;
@@ -3194,9 +3743,9 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
**/
static void
-e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter)
+e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring)
{
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
union e1000_rx_desc_packet_split *rx_desc;
@@ -3215,22 +3764,26 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter)
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
for(j = 0; j < PS_PAGE_BUFFERS; j++) {
- if(unlikely(!ps_page->ps_page[j])) {
- ps_page->ps_page[j] =
- alloc_page(GFP_ATOMIC);
- if(unlikely(!ps_page->ps_page[j]))
- goto no_buffers;
- ps_page_dma->ps_page_dma[j] =
- pci_map_page(pdev,
- ps_page->ps_page[j],
- 0, PAGE_SIZE,
- PCI_DMA_FROMDEVICE);
- }
- /* Refresh the desc even if buffer_addrs didn't
- * change because each write-back erases this info.
- */
- rx_desc->read.buffer_addr[j+1] =
- cpu_to_le64(ps_page_dma->ps_page_dma[j]);
+ if (j < adapter->rx_ps_pages) {
+ if (likely(!ps_page->ps_page[j])) {
+ ps_page->ps_page[j] =
+ alloc_page(GFP_ATOMIC);
+ if (unlikely(!ps_page->ps_page[j]))
+ goto no_buffers;
+ ps_page_dma->ps_page_dma[j] =
+ pci_map_page(pdev,
+ ps_page->ps_page[j],
+ 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ }
+ /* Refresh the desc even if buffer_addrs didn't
+ * change because each write-back erases
+ * this info.
+ */
+ rx_desc->read.buffer_addr[j+1] =
+ cpu_to_le64(ps_page_dma->ps_page_dma[j]);
+ } else
+ rx_desc->read.buffer_addr[j+1] = ~0;
}
skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN);
@@ -3264,7 +3817,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter)
* descriptors are 32 bytes...so we increment tail
* twice as much.
*/
- E1000_WRITE_REG(&adapter->hw, RDT, i<<1);
+ writel(i<<1, adapter->hw.hw_addr + rx_ring->rdt);
}
if(unlikely(++i == rx_ring->count)) i = 0;
@@ -3715,6 +4268,12 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
}
switch(adapter->hw.mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+ break;
case e1000_82573:
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
@@ -3737,6 +4296,7 @@ e1000_resume(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t manc, ret_val, swsm;
+ uint32_t ctrl_ext;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
@@ -3762,6 +4322,12 @@ e1000_resume(struct pci_dev *pdev)
}
switch(adapter->hw.mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+ break;
case e1000_82573:
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
@@ -3786,7 +4352,7 @@ e1000_netpoll(struct net_device *netdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev, NULL);
- e1000_clean_tx_irq(adapter);
+ e1000_clean_tx_irq(adapter, adapter->tx_ring);
enable_irq(adapter->pdev->irq);
}
#endif
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index 676247f9f1cc..38695d5b4637 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -306,7 +306,8 @@ e1000_check_options(struct e1000_adapter *adapter)
.def = E1000_DEFAULT_TXD,
.arg = { .r = { .min = E1000_MIN_TXD }}
};
- struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+ struct e1000_tx_ring *tx_ring = adapter->tx_ring;
+ int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt.arg.r.max = mac_type < e1000_82544 ?
E1000_MAX_TXD : E1000_MAX_82544_TXD;
@@ -319,6 +320,8 @@ e1000_check_options(struct e1000_adapter *adapter)
} else {
tx_ring->count = opt.def;
}
+ for (i = 0; i < adapter->num_queues; i++)
+ tx_ring[i].count = tx_ring->count;
}
{ /* Receive Descriptor Count */
struct e1000_option opt = {
@@ -329,7 +332,8 @@ e1000_check_options(struct e1000_adapter *adapter)
.def = E1000_DEFAULT_RXD,
.arg = { .r = { .min = E1000_MIN_RXD }}
};
- struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+ struct e1000_rx_ring *rx_ring = adapter->rx_ring;
+ int i;
e1000_mac_type mac_type = adapter->hw.mac_type;
opt.arg.r.max = mac_type < e1000_82544 ? E1000_MAX_RXD :
E1000_MAX_82544_RXD;
@@ -342,6 +346,8 @@ e1000_check_options(struct e1000_adapter *adapter)
} else {
rx_ring->count = opt.def;
}
+ for (i = 0; i < adapter->num_queues; i++)
+ rx_ring[i].count = rx_ring->count;
}
{ /* Checksum Offload Enable/Disable */
struct e1000_option opt = {
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 87f522738bfc..f119ec4e89ea 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1334,7 +1334,7 @@ static void epic_rx_err(struct net_device *dev, struct epic_private *ep)
static int epic_poll(struct net_device *dev, int *budget)
{
struct epic_private *ep = dev->priv;
- int work_done, orig_budget;
+ int work_done = 0, orig_budget;
long ioaddr = dev->base_addr;
orig_budget = (*budget > dev->quota) ? dev->quota : *budget;
@@ -1343,7 +1343,7 @@ rx_action:
epic_tx(dev, ep);
- work_done = epic_rx(dev, *budget);
+ work_done += epic_rx(dev, *budget);
epic_rx_err(dev, ep);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index d6eefdb71c17..22aec6ed80f5 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -95,6 +95,8 @@
* of nv_remove
* 0.42: 06 Aug 2005: Fix lack of link speed initialization
* in the second (and later) nv_open call
+ * 0.43: 10 Aug 2005: Add support for tx checksum.
+ * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -106,7 +108,7 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.41"
+#define FORCEDETH_VERSION "0.44"
#define DRV_NAME "forcedeth"
#include
@@ -145,6 +147,7 @@
#define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */
#define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */
#define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */
+#define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */
enum {
NvRegIrqStatus = 0x000,
@@ -241,6 +244,9 @@ enum {
#define NVREG_TXRXCTL_IDLE 0x0008
#define NVREG_TXRXCTL_RESET 0x0010
#define NVREG_TXRXCTL_RXCHECK 0x0400
+#define NVREG_TXRXCTL_DESC_1 0
+#define NVREG_TXRXCTL_DESC_2 0x02100
+#define NVREG_TXRXCTL_DESC_3 0x02200
NvRegMIIStatus = 0x180,
#define NVREG_MIISTAT_ERROR 0x0001
#define NVREG_MIISTAT_LINKCHANGE 0x0008
@@ -335,6 +341,10 @@ typedef union _ring_type {
/* error and valid are the same for both */
#define NV_TX2_ERROR (1<<30)
#define NV_TX2_VALID (1<<31)
+#define NV_TX2_TSO (1<<28)
+#define NV_TX2_TSO_SHIFT 14
+#define NV_TX2_CHECKSUM_L3 (1<<27)
+#define NV_TX2_CHECKSUM_L4 (1<<26)
#define NV_RX_DESCRIPTORVALID (1<<16)
#define NV_RX_MISSEDFRAME (1<<17)
@@ -417,14 +427,14 @@ typedef union _ring_type {
/*
* desc_ver values:
- * This field has two purposes:
- * - Newer nics uses a different ring layout. The layout is selected by
- * comparing np->desc_ver with DESC_VER_xy.
- * - It contains bits that are forced on when writing to NvRegTxRxControl.
+ * The nic supports three different descriptor types:
+ * - DESC_VER_1: Original
+ * - DESC_VER_2: support for jumbo frames.
+ * - DESC_VER_3: 64-bit format.
*/
-#define DESC_VER_1 0x0
-#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK)
-#define DESC_VER_3 (0x02200|NVREG_TXRXCTL_RXCHECK)
+#define DESC_VER_1 1
+#define DESC_VER_2 2
+#define DESC_VER_3 3
/* PHY defines */
#define PHY_OUI_MARVELL 0x5043
@@ -491,6 +501,7 @@ struct fe_priv {
u32 orig_mac[2];
u32 irqmask;
u32 desc_ver;
+ u32 txrxctl_bits;
void __iomem *base;
@@ -534,7 +545,7 @@ static inline struct fe_priv *get_nvpriv(struct net_device *dev)
static inline u8 __iomem *get_hwbase(struct net_device *dev)
{
- return get_nvpriv(dev)->base;
+ return ((struct fe_priv *)netdev_priv(dev))->base;
}
static inline void pci_push(u8 __iomem *base)
@@ -623,7 +634,7 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
static int phy_reset(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 miicontrol;
unsigned int tries = 0;
@@ -726,7 +737,7 @@ static int phy_init(struct net_device *dev)
static void nv_start_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name);
@@ -782,14 +793,14 @@ static void nv_stop_tx(struct net_device *dev)
static void nv_txrx_reset(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name);
- writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
udelay(NV_TXRX_RESET_DELAY);
- writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
}
@@ -801,7 +812,7 @@ static void nv_txrx_reset(struct net_device *dev)
*/
static struct net_device_stats *nv_get_stats(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
/* It seems that the nic always generates interrupts and doesn't
* accumulate errors internally. Thus the current values in np->stats
@@ -817,7 +828,7 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
*/
static int nv_alloc_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
unsigned int refill_rx = np->refill_rx;
int nr;
@@ -861,7 +872,7 @@ static int nv_alloc_rx(struct net_device *dev)
static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
disable_irq(dev->irq);
if (nv_alloc_rx(dev)) {
@@ -875,7 +886,7 @@ static void nv_do_rx_refill(unsigned long data)
static void nv_init_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int i;
np->cur_rx = RX_RING;
@@ -889,15 +900,17 @@ static void nv_init_rx(struct net_device *dev)
static void nv_init_tx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int i;
np->next_tx = np->nic_tx = 0;
- for (i = 0; i < TX_RING; i++)
+ for (i = 0; i < TX_RING; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[i].FlagLen = 0;
else
np->tx_ring.ex[i].FlagLen = 0;
+ np->tx_skbuff[i] = NULL;
+ }
}
static int nv_init_ring(struct net_device *dev)
@@ -907,21 +920,44 @@ static int nv_init_ring(struct net_device *dev)
return nv_alloc_rx(dev);
}
+static void nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+{
+ struct fe_priv *np = netdev_priv(dev);
+ struct sk_buff *skb = np->tx_skbuff[skbnr];
+ unsigned int j, entry, fragments;
+
+ dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d, skb %p\n",
+ dev->name, skbnr, np->tx_skbuff[skbnr]);
+
+ entry = skbnr;
+ if ((fragments = skb_shinfo(skb)->nr_frags) != 0) {
+ for (j = fragments; j >= 1; j--) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[j-1];
+ pci_unmap_page(np->pci_dev, np->tx_dma[entry],
+ frag->size,
+ PCI_DMA_TODEVICE);
+ entry = (entry - 1) % TX_RING;
+ }
+ }
+ pci_unmap_single(np->pci_dev, np->tx_dma[entry],
+ skb->len - skb->data_len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(skb);
+ np->tx_skbuff[skbnr] = NULL;
+}
+
static void nv_drain_tx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- int i;
+ struct fe_priv *np = netdev_priv(dev);
+ unsigned int i;
+
for (i = 0; i < TX_RING; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
np->tx_ring.orig[i].FlagLen = 0;
else
np->tx_ring.ex[i].FlagLen = 0;
if (np->tx_skbuff[i]) {
- pci_unmap_single(np->pci_dev, np->tx_dma[i],
- np->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(np->tx_skbuff[i]);
- np->tx_skbuff[i] = NULL;
+ nv_release_txskb(dev, i);
np->stats.tx_dropped++;
}
}
@@ -929,7 +965,7 @@ static void nv_drain_tx(struct net_device *dev)
static void nv_drain_rx(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int i;
for (i = 0; i < RX_RING; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
@@ -959,28 +995,69 @@ static void drain_ring(struct net_device *dev)
*/
static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
- int nr = np->next_tx % TX_RING;
-
- np->tx_skbuff[nr] = skb;
- np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len,
- PCI_DMA_TODEVICE);
-
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- else {
- np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- }
+ struct fe_priv *np = netdev_priv(dev);
+ u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
+ unsigned int fragments = skb_shinfo(skb)->nr_frags;
+ unsigned int nr = (np->next_tx + fragments) % TX_RING;
+ unsigned int i;
spin_lock_irq(&np->lock);
- wmb();
- if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
+
+ if ((np->next_tx - np->nic_tx + fragments) > TX_LIMIT_STOP) {
+ spin_unlock_irq(&np->lock);
+ netif_stop_queue(dev);
+ return NETDEV_TX_BUSY;
+ }
+
+ np->tx_skbuff[nr] = skb;
+
+ if (fragments) {
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: buffer contains %d fragments\n", dev->name, fragments);
+ /* setup descriptors in reverse order */
+ for (i = fragments; i >= 1; i--) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
+ np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+ } else {
+ np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (frag->size-1) | np->tx_flags | tx_flags_extra);
+ }
+
+ nr = (nr - 1) % TX_RING;
+
+ if (np->desc_ver == DESC_VER_1)
+ tx_flags_extra &= ~NV_TX_LASTPACKET;
+ else
+ tx_flags_extra &= ~NV_TX2_LASTPACKET;
+ }
+ }
+
+#ifdef NETIF_F_TSO
+ if (skb_shinfo(skb)->tso_size)
+ tx_flags_extra |= NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
else
- np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags );
- dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n",
- dev->name, np->next_tx);
+#endif
+ tx_flags_extra |= (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+
+ np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len-skb->data_len,
+ PCI_DMA_TODEVICE);
+
+ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
+ np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+ } else {
+ np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-skb->data_len-1) | np->tx_flags | tx_flags_extra);
+ }
+
+ dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission. tx_flags_extra: %x\n",
+ dev->name, np->next_tx, tx_flags_extra);
{
int j;
for (j=0; j<64; j++) {
@@ -991,15 +1068,13 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
dprintk("\n");
}
- np->next_tx++;
+ np->next_tx += 1 + fragments;
dev->trans_start = jiffies;
- if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP)
- netif_stop_queue(dev);
spin_unlock_irq(&np->lock);
- writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
pci_push(get_hwbase(dev));
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -1009,9 +1084,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
static void nv_tx_done(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 Flags;
- int i;
+ unsigned int i;
+ struct sk_buff *skb;
while (np->nic_tx != np->next_tx) {
i = np->nic_tx % TX_RING;
@@ -1026,35 +1102,38 @@ static void nv_tx_done(struct net_device *dev)
if (Flags & NV_TX_VALID)
break;
if (np->desc_ver == DESC_VER_1) {
- if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
- NV_TX_UNDERFLOW|NV_TX_ERROR)) {
- if (Flags & NV_TX_UNDERFLOW)
- np->stats.tx_fifo_errors++;
- if (Flags & NV_TX_CARRIERLOST)
- np->stats.tx_carrier_errors++;
- np->stats.tx_errors++;
- } else {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->tx_skbuff[i]->len;
+ if (Flags & NV_TX_LASTPACKET) {
+ skb = np->tx_skbuff[i];
+ if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+ NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+ if (Flags & NV_TX_UNDERFLOW)
+ np->stats.tx_fifo_errors++;
+ if (Flags & NV_TX_CARRIERLOST)
+ np->stats.tx_carrier_errors++;
+ np->stats.tx_errors++;
+ } else {
+ np->stats.tx_packets++;
+ np->stats.tx_bytes += skb->len;
+ }
+ nv_release_txskb(dev, i);
}
} else {
- if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
- NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
- if (Flags & NV_TX2_UNDERFLOW)
- np->stats.tx_fifo_errors++;
- if (Flags & NV_TX2_CARRIERLOST)
- np->stats.tx_carrier_errors++;
- np->stats.tx_errors++;
- } else {
- np->stats.tx_packets++;
- np->stats.tx_bytes += np->tx_skbuff[i]->len;
+ if (Flags & NV_TX2_LASTPACKET) {
+ skb = np->tx_skbuff[i];
+ if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+ NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+ if (Flags & NV_TX2_UNDERFLOW)
+ np->stats.tx_fifo_errors++;
+ if (Flags & NV_TX2_CARRIERLOST)
+ np->stats.tx_carrier_errors++;
+ np->stats.tx_errors++;
+ } else {
+ np->stats.tx_packets++;
+ np->stats.tx_bytes += skb->len;
+ }
+ nv_release_txskb(dev, i);
}
}
- pci_unmap_single(np->pci_dev, np->tx_dma[i],
- np->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(np->tx_skbuff[i]);
- np->tx_skbuff[i] = NULL;
np->nic_tx++;
}
if (np->next_tx - np->nic_tx < TX_LIMIT_START)
@@ -1067,7 +1146,7 @@ static void nv_tx_done(struct net_device *dev)
*/
static void nv_tx_timeout(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name,
@@ -1200,7 +1279,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
static void nv_rx_process(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u32 Flags;
for (;;) {
@@ -1355,7 +1434,7 @@ static void set_bufsize(struct net_device *dev)
*/
static int nv_change_mtu(struct net_device *dev, int new_mtu)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int old_mtu;
if (new_mtu < 64 || new_mtu > np->pkt_limit)
@@ -1408,7 +1487,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
pci_push(base);
- writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
pci_push(base);
/* restart rx engine */
@@ -1440,7 +1519,7 @@ static void nv_copy_mac_to_hw(struct net_device *dev)
*/
static int nv_set_mac_address(struct net_device *dev, void *addr)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
struct sockaddr *macaddr = (struct sockaddr*)addr;
if(!is_valid_ether_addr(macaddr->sa_data))
@@ -1475,7 +1554,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
*/
static void nv_set_multicast(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 addr[2];
u32 mask[2];
@@ -1535,7 +1614,7 @@ static void nv_set_multicast(struct net_device *dev)
static int nv_update_linkspeed(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int adv, lpa;
int newls = np->linkspeed;
@@ -1705,7 +1784,7 @@ static void nv_link_irq(struct net_device *dev)
static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 events;
int i;
@@ -1777,7 +1856,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
static void nv_do_nic_poll(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
disable_irq(dev->irq);
@@ -1801,7 +1880,7 @@ static void nv_poll_controller(struct net_device *dev)
static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
strcpy(info->driver, "forcedeth");
strcpy(info->version, FORCEDETH_VERSION);
strcpy(info->bus_info, pci_name(np->pci_dev));
@@ -1809,7 +1888,7 @@ static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
wolinfo->supported = WAKE_MAGIC;
spin_lock_irq(&np->lock);
@@ -1820,7 +1899,7 @@ static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
spin_lock_irq(&np->lock);
@@ -2021,7 +2100,7 @@ static int nv_get_regs_len(struct net_device *dev)
static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 *rbuf = buf;
int i;
@@ -2035,7 +2114,7 @@ static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void
static int nv_nway_reset(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
int ret;
spin_lock_irq(&np->lock);
@@ -2065,11 +2144,12 @@ static struct ethtool_ops ops = {
.get_regs_len = nv_get_regs_len,
.get_regs = nv_get_regs,
.nway_reset = nv_nway_reset,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
static int nv_open(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
int ret, oom, i;
@@ -2114,9 +2194,9 @@ static int nv_open(struct net_device *dev)
/* 5) continue setup */
writel(np->linkspeed, base + NvRegLinkSpeed);
writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
- writel(np->desc_ver, base + NvRegTxRxControl);
+ writel(np->txrxctl_bits, base + NvRegTxRxControl);
pci_push(base);
- writel(NVREG_TXRXCTL_BIT1|np->desc_ver, base + NvRegTxRxControl);
+ writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl);
reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31,
NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX,
KERN_INFO "open: SetupReg5, Bit 31 remained off\n");
@@ -2205,7 +2285,7 @@ out_drain:
static int nv_close(struct net_device *dev)
{
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base;
spin_lock_irq(&np->lock);
@@ -2261,7 +2341,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (!dev)
goto out;
- np = get_nvpriv(dev);
+ np = netdev_priv(dev);
np->pci_dev = pci_dev;
spin_lock_init(&np->lock);
SET_MODULE_OWNER(dev);
@@ -2313,19 +2393,32 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) {
printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n",
pci_name(pci_dev));
+ } else {
+ dev->features |= NETIF_F_HIGHDMA;
}
+ np->txrxctl_bits = NVREG_TXRXCTL_DESC_3;
} else if (id->driver_data & DEV_HAS_LARGEDESC) {
/* packet format 2: supports jumbo frames */
np->desc_ver = DESC_VER_2;
+ np->txrxctl_bits = NVREG_TXRXCTL_DESC_2;
} else {
/* original packet format */
np->desc_ver = DESC_VER_1;
+ np->txrxctl_bits = NVREG_TXRXCTL_DESC_1;
}
np->pkt_limit = NV_PKTLIMIT_1;
if (id->driver_data & DEV_HAS_LARGEDESC)
np->pkt_limit = NV_PKTLIMIT_2;
+ if (id->driver_data & DEV_HAS_CHECKSUM) {
+ np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
+ dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+#ifdef NETIF_F_TSO
+ dev->features |= NETIF_F_TSO;
+#endif
+ }
+
err = -ENOMEM;
np->base = ioremap(addr, NV_PCI_REGSZ);
if (!np->base)
@@ -2377,8 +2470,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (!is_valid_ether_addr(dev->dev_addr)) {
+ if (!is_valid_ether_addr(dev->perm_addr)) {
/*
* Bad mac address. At least one bios sets the mac address
* to 01:23:45:67:89:ab
@@ -2403,9 +2497,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->wolenabled = 0;
if (np->desc_ver == DESC_VER_1) {
- np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID;
+ np->tx_flags = NV_TX_VALID;
} else {
- np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID;
+ np->tx_flags = NV_TX2_VALID;
}
np->irqmask = NVREG_IRQMASK_WANTED;
if (id->driver_data & DEV_NEED_TIMERIRQ)
@@ -2494,7 +2588,7 @@ out:
static void __devexit nv_remove(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
- struct fe_priv *np = get_nvpriv(dev);
+ struct fe_priv *np = netdev_priv(dev);
unregister_netdev(dev);
@@ -2525,35 +2619,35 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* nForce3 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
},
{ /* nForce3 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
},
{ /* nForce3 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
},
{ /* nForce3 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM,
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* CK804 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* MCP04 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* MCP51 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
@@ -2565,11 +2659,11 @@ static struct pci_device_id pci_tbl[] = {
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{ /* MCP55 Ethernet Controller */
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
- .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA,
+ .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
},
{0,},
};
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 6518334b9280..ae5a2ed3b264 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -29,12 +29,7 @@
* define the configuration needed by the board are defined in a
* board structure in arch/ppc/platforms (though I do not
* discount the possibility that other architectures could one
- * day be supported. One assumption the driver currently makes
- * is that the PHY is configured in such a way to advertise all
- * capabilities. This is a sensible default, and on certain
- * PHYs, changing this default encounters substantial errata
- * issues. Future versions may remove this requirement, but for
- * now, it is best for the firmware to ensure this is the case.
+ * day be supported.
*
* The Gianfar Ethernet Controller uses a ring of buffer
* descriptors. The beginning is indicated by a register
@@ -47,7 +42,7 @@
* corresponding bit in the IMASK register is also set (if
* interrupt coalescing is active, then the interrupt may not
* happen immediately, but will wait until either a set number
- * of frames or amount of time have passed.). In NAPI, the
+ * of frames or amount of time have passed). In NAPI, the
* interrupt handler will signal there is work to be done, and
* exit. Without NAPI, the packet(s) will be handled
* immediately. Both methods will start at the last known empty
@@ -75,6 +70,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -97,9 +93,11 @@
#include
#include
#include
+#include
+#include
#include "gianfar.h"
-#include "gianfar_phy.h"
+#include "gianfar_mii.h"
#define TX_TIMEOUT (1*HZ)
#define SKB_ALLOC_TIMEOUT 1000000
@@ -113,9 +111,8 @@
#endif
const char gfar_driver_name[] = "Gianfar Ethernet";
-const char gfar_driver_version[] = "1.1";
+const char gfar_driver_version[] = "1.2";
-int startup_gfar(struct net_device *dev);
static int gfar_enet_open(struct net_device *dev);
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void gfar_timeout(struct net_device *dev);
@@ -126,17 +123,13 @@ static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void gfar_phy_change(void *data);
-static void gfar_phy_timer(unsigned long data);
static void adjust_link(struct net_device *dev);
static void init_registers(struct net_device *dev);
static int init_phy(struct net_device *dev);
static int gfar_probe(struct device *device);
static int gfar_remove(struct device *device);
-void free_skb_resources(struct gfar_private *priv);
+static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
#ifdef CONFIG_GFAR_NAPI
@@ -144,7 +137,6 @@ static int gfar_poll(struct net_device *dev, int *budget);
#endif
int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
-static void gfar_phy_startup_timer(unsigned long data);
static void gfar_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp);
static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
@@ -162,6 +154,9 @@ int gfar_uses_fcb(struct gfar_private *priv)
else
return 0;
}
+
+/* Set up the ethernet device structure, private data,
+ * and anything else we need before we start */
static int gfar_probe(struct device *device)
{
u32 tempval;
@@ -175,7 +170,7 @@ static int gfar_probe(struct device *device)
einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
- if (einfo == NULL) {
+ if (NULL == einfo) {
printk(KERN_ERR "gfar %d: Missing additional data!\n",
pdev->id);
@@ -185,7 +180,7 @@ static int gfar_probe(struct device *device)
/* Create an ethernet device instance */
dev = alloc_etherdev(sizeof (*priv));
- if (dev == NULL)
+ if (NULL == dev)
return -ENOMEM;
priv = netdev_priv(dev);
@@ -207,20 +202,11 @@ static int gfar_probe(struct device *device)
priv->regs = (struct gfar *)
ioremap(r->start, sizeof (struct gfar));
- if (priv->regs == NULL) {
+ if (NULL == priv->regs) {
err = -ENOMEM;
goto regs_fail;
}
- /* Set the PHY base address */
- priv->phyregs = (struct gfar *)
- ioremap(einfo->phy_reg_addr, sizeof (struct gfar));
-
- if (priv->phyregs == NULL) {
- err = -ENOMEM;
- goto phy_regs_fail;
- }
-
spin_lock_init(&priv->lock);
dev_set_drvdata(device, dev);
@@ -386,12 +372,10 @@ static int gfar_probe(struct device *device)
return 0;
register_fail:
- iounmap((void *) priv->phyregs);
-phy_regs_fail:
iounmap((void *) priv->regs);
regs_fail:
free_netdev(dev);
- return -ENOMEM;
+ return err;
}
static int gfar_remove(struct device *device)
@@ -402,108 +386,41 @@ static int gfar_remove(struct device *device)
dev_set_drvdata(device, NULL);
iounmap((void *) priv->regs);
- iounmap((void *) priv->phyregs);
free_netdev(dev);
return 0;
}
-/* Configure the PHY for dev.
- * returns 0 if success. -1 if failure
+/* Initializes driver's PHY state, and attaches to the PHY.
+ * Returns 0 on success.
*/
static int init_phy(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- struct phy_info *curphy;
- unsigned int timeout = PHY_INIT_TIMEOUT;
- struct gfar *phyregs = priv->phyregs;
- struct gfar_mii_info *mii_info;
- int err;
+ uint gigabit_support =
+ priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
+ SUPPORTED_1000baseT_Full : 0;
+ struct phy_device *phydev;
priv->oldlink = 0;
priv->oldspeed = 0;
priv->oldduplex = -1;
- mii_info = kmalloc(sizeof(struct gfar_mii_info),
- GFP_KERNEL);
+ phydev = phy_connect(dev, priv->einfo->bus_id, &adjust_link, 0);
- if(NULL == mii_info) {
- if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: Could not allocate mii_info\n",
- dev->name);
- return -ENOMEM;
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
}
- mii_info->speed = SPEED_1000;
- mii_info->duplex = DUPLEX_FULL;
- mii_info->pause = 0;
- mii_info->link = 1;
+ /* Remove any features not supported by the controller */
+ phydev->supported &= (GFAR_SUPPORTED | gigabit_support);
+ phydev->advertising = phydev->supported;
- mii_info->advertising = (ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_1000baseT_Full);
- mii_info->autoneg = 1;
-
- spin_lock_init(&mii_info->mdio_lock);
-
- mii_info->mii_id = priv->einfo->phyid;
-
- mii_info->dev = dev;
-
- mii_info->mdio_read = &read_phy_reg;
- mii_info->mdio_write = &write_phy_reg;
-
- priv->mii_info = mii_info;
-
- /* Reset the management interface */
- gfar_write(&phyregs->miimcfg, MIIMCFG_RESET);
-
- /* Setup the MII Mgmt clock speed */
- gfar_write(&phyregs->miimcfg, MIIMCFG_INIT_VALUE);
-
- /* Wait until the bus is free */
- while ((gfar_read(&phyregs->miimind) & MIIMIND_BUSY) &&
- timeout--)
- cpu_relax();
-
- if(timeout <= 0) {
- printk(KERN_ERR "%s: The MII Bus is stuck!\n",
- dev->name);
- err = -1;
- goto bus_fail;
- }
-
- /* get info for this PHY */
- curphy = get_phy_info(priv->mii_info);
-
- if (curphy == NULL) {
- if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: No PHY found\n", dev->name);
- err = -1;
- goto no_phy;
- }
-
- mii_info->phyinfo = curphy;
-
- /* Run the commands which initialize the PHY */
- if(curphy->init) {
- err = curphy->init(priv->mii_info);
-
- if (err)
- goto phy_init_fail;
- }
+ priv->phydev = phydev;
return 0;
-
-phy_init_fail:
-no_phy:
-bus_fail:
- kfree(mii_info);
-
- return err;
}
static void init_registers(struct net_device *dev)
@@ -603,24 +520,13 @@ void stop_gfar(struct net_device *dev)
struct gfar *regs = priv->regs;
unsigned long flags;
+ phy_stop(priv->phydev);
+
/* Lock it down */
spin_lock_irqsave(&priv->lock, flags);
- /* Tell the kernel the link is down */
- priv->mii_info->link = 0;
- adjust_link(dev);
-
gfar_halt(dev);
- if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
- /* Clear any pending interrupts */
- mii_clear_phy_interrupt(priv->mii_info);
-
- /* Disable PHY Interrupts */
- mii_configure_phy_interrupt(priv->mii_info,
- MII_INTERRUPT_DISABLED);
- }
-
spin_unlock_irqrestore(&priv->lock, flags);
/* Free the IRQs */
@@ -629,13 +535,7 @@ void stop_gfar(struct net_device *dev)
free_irq(priv->interruptTransmit, dev);
free_irq(priv->interruptReceive, dev);
} else {
- free_irq(priv->interruptTransmit, dev);
- }
-
- if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
- free_irq(priv->einfo->interruptPHY, dev);
- } else {
- del_timer_sync(&priv->phy_info_timer);
+ free_irq(priv->interruptTransmit, dev);
}
free_skb_resources(priv);
@@ -649,7 +549,7 @@ void stop_gfar(struct net_device *dev)
/* If there are any tx skbs or rx skbs still around, free them.
* Then free tx_skbuff and rx_skbuff */
-void free_skb_resources(struct gfar_private *priv)
+static void free_skb_resources(struct gfar_private *priv)
{
struct rxbd8 *rxbdp;
struct txbd8 *txbdp;
@@ -770,7 +670,7 @@ int startup_gfar(struct net_device *dev)
(struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
priv->tx_ring_size, GFP_KERNEL);
- if (priv->tx_skbuff == NULL) {
+ if (NULL == priv->tx_skbuff) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
dev->name);
@@ -785,7 +685,7 @@ int startup_gfar(struct net_device *dev)
(struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
priv->rx_ring_size, GFP_KERNEL);
- if (priv->rx_skbuff == NULL) {
+ if (NULL == priv->rx_skbuff) {
if (netif_msg_ifup(priv))
printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
dev->name);
@@ -879,13 +779,7 @@ int startup_gfar(struct net_device *dev)
}
}
- /* Set up the PHY change work queue */
- INIT_WORK(&priv->tq, gfar_phy_change, dev);
-
- init_timer(&priv->phy_info_timer);
- priv->phy_info_timer.function = &gfar_phy_startup_timer;
- priv->phy_info_timer.data = (unsigned long) priv->mii_info;
- mod_timer(&priv->phy_info_timer, jiffies + HZ);
+ phy_start(priv->phydev);
/* Configure the coalescing support */
if (priv->txcoalescing)
@@ -933,11 +827,6 @@ tx_skb_fail:
priv->tx_bd_base,
gfar_read(®s->tbase0));
- if (priv->mii_info->phyinfo->close)
- priv->mii_info->phyinfo->close(priv->mii_info);
-
- kfree(priv->mii_info);
-
return err;
}
@@ -1035,7 +924,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
txbdp->status &= TXBD_WRAP;
/* Set up checksumming */
- if ((dev->features & NETIF_F_IP_CSUM)
+ if ((dev->features & NETIF_F_IP_CSUM)
&& (CHECKSUM_HW == skb->ip_summed)) {
fcb = gfar_add_fcb(skb, txbdp);
gfar_tx_checksum(skb, fcb);
@@ -1103,11 +992,9 @@ static int gfar_close(struct net_device *dev)
struct gfar_private *priv = netdev_priv(dev);
stop_gfar(dev);
- /* Shutdown the PHY */
- if (priv->mii_info->phyinfo->close)
- priv->mii_info->phyinfo->close(priv->mii_info);
-
- kfree(priv->mii_info);
+ /* Disconnect from the PHY */
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
netif_stop_queue(dev);
@@ -1343,7 +1230,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
while ((!skb) && timeout--)
skb = dev_alloc_skb(priv->rx_buffer_size + RXBUF_ALIGNMENT);
- if (skb == NULL)
+ if (NULL == skb)
return NULL;
/* We need the data buffer to be aligned properly. We will reserve
@@ -1490,7 +1377,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
struct gfar_private *priv = netdev_priv(dev);
struct rxfcb *fcb = NULL;
- if (skb == NULL) {
+ if (NULL == skb) {
if (netif_msg_rx_err(priv))
printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
priv->stats.rx_dropped++;
@@ -1718,131 +1605,9 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct net_device *dev = (struct net_device *) dev_id;
- struct gfar_private *priv = netdev_priv(dev);
-
- /* Clear the interrupt */
- mii_clear_phy_interrupt(priv->mii_info);
-
- /* Disable PHY interrupts */
- mii_configure_phy_interrupt(priv->mii_info,
- MII_INTERRUPT_DISABLED);
-
- /* Schedule the phy change */
- schedule_work(&priv->tq);
-
- return IRQ_HANDLED;
-}
-
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void gfar_phy_change(void *data)
-{
- struct net_device *dev = (struct net_device *) data;
- struct gfar_private *priv = netdev_priv(dev);
- int result = 0;
-
- /* Delay to give the PHY a chance to change the
- * register state */
- msleep(1);
-
- /* Update the link, speed, duplex */
- result = priv->mii_info->phyinfo->read_status(priv->mii_info);
-
- /* Adjust the known status as long as the link
- * isn't still coming up */
- if((0 == result) || (priv->mii_info->link == 0))
- adjust_link(dev);
-
- /* Reenable interrupts, if needed */
- if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR)
- mii_configure_phy_interrupt(priv->mii_info,
- MII_INTERRUPT_ENABLED);
-}
-
-/* Called every so often on systems that don't interrupt
- * the core for PHY changes */
-static void gfar_phy_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *) data;
- struct gfar_private *priv = netdev_priv(dev);
-
- schedule_work(&priv->tq);
-
- mod_timer(&priv->phy_info_timer, jiffies +
- GFAR_PHY_CHANGE_TIME * HZ);
-}
-
-/* Keep trying aneg for some time
- * If, after GFAR_AN_TIMEOUT seconds, it has not
- * finished, we switch to forced.
- * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
- * using gfar_phy_timer to check status */
-static void gfar_phy_startup_timer(unsigned long data)
-{
- int result;
- static int secondary = GFAR_AN_TIMEOUT;
- struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data;
- struct gfar_private *priv = netdev_priv(mii_info->dev);
-
- /* Configure the Auto-negotiation */
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* If autonegotiation failed to start, and
- * we haven't timed out, reset the timer, and return */
- if (result && secondary--) {
- mod_timer(&priv->phy_info_timer, jiffies + HZ);
- return;
- } else if (result) {
- /* Couldn't start autonegotiation.
- * Try switching to forced */
- mii_info->autoneg = 0;
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* Forcing failed! Give up */
- if(result) {
- if (netif_msg_link(priv))
- printk(KERN_ERR "%s: Forcing failed!\n",
- mii_info->dev->name);
- return;
- }
- }
-
- /* Kill the timer so it can be restarted */
- del_timer_sync(&priv->phy_info_timer);
-
- /* Grab the PHY interrupt, if necessary/possible */
- if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
- if (request_irq(priv->einfo->interruptPHY,
- phy_interrupt,
- SA_SHIRQ,
- "phy_interrupt",
- mii_info->dev) < 0) {
- if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d (PHY)\n",
- mii_info->dev->name,
- priv->einfo->interruptPHY);
- } else {
- mii_configure_phy_interrupt(priv->mii_info,
- MII_INTERRUPT_ENABLED);
- return;
- }
- }
-
- /* Start the timer again, this time in order to
- * handle a change in status */
- init_timer(&priv->phy_info_timer);
- priv->phy_info_timer.function = &gfar_phy_timer;
- priv->phy_info_timer.data = (unsigned long) mii_info->dev;
- mod_timer(&priv->phy_info_timer, jiffies +
- GFAR_PHY_CHANGE_TIME * HZ);
-}
-
/* Called every time the controller might need to be made
* aware of new link state. The PHY code conveys this
- * information through variables in the priv structure, and this
+ * information through variables in the phydev structure, and this
* function converts those variables into the appropriate
* register values, and can bring down the device if needed.
*/
@@ -1850,84 +1615,68 @@ static void adjust_link(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar *regs = priv->regs;
- u32 tempval;
- struct gfar_mii_info *mii_info = priv->mii_info;
+ unsigned long flags;
+ struct phy_device *phydev = priv->phydev;
+ int new_state = 0;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (phydev->link) {
+ u32 tempval = gfar_read(®s->maccfg2);
- if (mii_info->link) {
/* Now we make sure that we can be in full duplex mode.
* If not, we operate in half-duplex mode. */
- if (mii_info->duplex != priv->oldduplex) {
- if (!(mii_info->duplex)) {
- tempval = gfar_read(®s->maccfg2);
+ if (phydev->duplex != priv->oldduplex) {
+ new_state = 1;
+ if (!(phydev->duplex))
tempval &= ~(MACCFG2_FULL_DUPLEX);
- gfar_write(®s->maccfg2, tempval);
-
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Half Duplex\n",
- dev->name);
- } else {
- tempval = gfar_read(®s->maccfg2);
+ else
tempval |= MACCFG2_FULL_DUPLEX;
- gfar_write(®s->maccfg2, tempval);
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Full Duplex\n",
- dev->name);
- }
-
- priv->oldduplex = mii_info->duplex;
+ priv->oldduplex = phydev->duplex;
}
- if (mii_info->speed != priv->oldspeed) {
- switch (mii_info->speed) {
+ if (phydev->speed != priv->oldspeed) {
+ new_state = 1;
+ switch (phydev->speed) {
case 1000:
- tempval = gfar_read(®s->maccfg2);
tempval =
((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII);
- gfar_write(®s->maccfg2, tempval);
break;
case 100:
case 10:
- tempval = gfar_read(®s->maccfg2);
tempval =
((tempval & ~(MACCFG2_IF)) | MACCFG2_MII);
- gfar_write(®s->maccfg2, tempval);
break;
default:
if (netif_msg_link(priv))
printk(KERN_WARNING
- "%s: Ack! Speed (%d) is not 10/100/1000!\n",
- dev->name, mii_info->speed);
+ "%s: Ack! Speed (%d) is not 10/100/1000!\n",
+ dev->name, phydev->speed);
break;
}
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
- mii_info->speed);
-
- priv->oldspeed = mii_info->speed;
+ priv->oldspeed = phydev->speed;
}
+ gfar_write(®s->maccfg2, tempval);
+
if (!priv->oldlink) {
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Link is up\n", dev->name);
+ new_state = 1;
priv->oldlink = 1;
- netif_carrier_on(dev);
netif_schedule(dev);
}
- } else {
- if (priv->oldlink) {
- if (netif_msg_link(priv))
- printk(KERN_INFO "%s: Link is down\n",
- dev->name);
- priv->oldlink = 0;
- priv->oldspeed = 0;
- priv->oldduplex = -1;
- netif_carrier_off(dev);
- }
+ } else if (priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
}
-}
+ if (new_state && netif_msg_link(priv))
+ phy_print_status(phydev);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
/* Update the hash table based on the current list of multicast
* addresses we subscribe to. Also, change the promiscuity of
@@ -2122,12 +1871,23 @@ static struct device_driver gfar_driver = {
static int __init gfar_init(void)
{
- return driver_register(&gfar_driver);
+ int err = gfar_mdio_init();
+
+ if (err)
+ return err;
+
+ err = driver_register(&gfar_driver);
+
+ if (err)
+ gfar_mdio_exit();
+
+ return err;
}
static void __exit gfar_exit(void)
{
driver_unregister(&gfar_driver);
+ gfar_mdio_exit();
}
module_init(gfar_init);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 28af087d9fbb..c77ca6c0d04a 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -17,7 +17,6 @@
*
* Still left to do:
* -Add support for module parameters
- * -Add support for ethtool -s
* -Add patch for ethtool phys id
*/
#ifndef __GIANFAR_H
@@ -37,7 +36,8 @@
#include
#include
#include
-#include
+#include
+#include
#include
#include
@@ -48,7 +48,8 @@
#include
#include
#include
-#include "gianfar_phy.h"
+#include
+#include "gianfar_mii.h"
/* The maximum number of packets to be handled in one call of gfar_poll */
#define GFAR_DEV_WEIGHT 64
@@ -73,7 +74,7 @@
#define PHY_INIT_TIMEOUT 100000
#define GFAR_PHY_CHANGE_TIME 2
-#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.1, "
+#define DEVICE_NAME "%s: Gianfar Ethernet Controller Version 1.2, "
#define DRV_NAME "gfar-enet"
extern const char gfar_driver_name[];
extern const char gfar_driver_version[];
@@ -578,12 +579,7 @@ struct gfar {
u32 hafdup; /* 0x.50c - Half Duplex Register */
u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */
u8 res18[12];
- u32 miimcfg; /* 0x.520 - MII Management Configuration Register */
- u32 miimcom; /* 0x.524 - MII Management Command Register */
- u32 miimadd; /* 0x.528 - MII Management Address Register */
- u32 miimcon; /* 0x.52c - MII Management Control Register */
- u32 miimstat; /* 0x.530 - MII Management Status Register */
- u32 miimind; /* 0x.534 - MII Management Indicator Register */
+ u8 gfar_mii_regs[24]; /* See gianfar_phy.h */
u8 res19[4];
u32 ifstat; /* 0x.53c - Interface Status Register */
u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */
@@ -688,9 +684,6 @@ struct gfar_private {
struct gfar *regs; /* Pointer to the GFAR memory mapped Registers */
u32 *hash_regs[16];
int hash_width;
- struct gfar *phyregs;
- struct work_struct tq;
- struct timer_list phy_info_timer;
struct net_device_stats stats; /* linux network statistics */
struct gfar_extra_stats extra_stats;
spinlock_t lock;
@@ -710,7 +703,8 @@ struct gfar_private {
unsigned int interruptError;
struct gianfar_platform_data *einfo;
- struct gfar_mii_info *mii_info;
+ struct phy_device *phydev;
+ struct mii_bus *mii_bus;
int oldspeed;
int oldduplex;
int oldlink;
@@ -732,4 +726,12 @@ extern inline void gfar_write(volatile unsigned *addr, u32 val)
extern struct ethtool_ops *gfar_op_array[];
+extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern int startup_gfar(struct net_device *dev);
+extern void stop_gfar(struct net_device *dev);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
+ int enable, u32 regnum, u32 read);
+void gfar_setup_stashing(struct net_device *dev);
+
#endif /* __GIANFAR_H */
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index a451de629197..68e3578e7613 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -39,17 +39,18 @@
#include
#include
#include
+#include
+#include
#include "gianfar.h"
#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-extern int startup_gfar(struct net_device *dev);
-extern void stop_gfar(struct net_device *dev);
-extern void gfar_halt(struct net_device *dev);
extern void gfar_start(struct net_device *dev);
extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+#define GFAR_MAX_COAL_USECS 0xffff
+#define GFAR_MAX_COAL_FRAMES 0xff
static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
u64 * buf);
static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
@@ -182,38 +183,32 @@ static void gfar_gdrvinfo(struct net_device *dev, struct
drvinfo->eedump_len = 0;
}
+
+static int gfar_ssettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+
+ if (NULL == phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(phydev, cmd);
+}
+
+
/* Return the current settings in the ethtool_cmd structure */
static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gfar_private *priv = netdev_priv(dev);
- uint gigabit_support =
- priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
- SUPPORTED_1000baseT_Full : 0;
- uint gigabit_advert =
- priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ?
- ADVERTISED_1000baseT_Full: 0;
+ struct phy_device *phydev = priv->phydev;
- cmd->supported = (SUPPORTED_10baseT_Half
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | gigabit_support | SUPPORTED_Autoneg);
-
- /* For now, we always advertise everything */
- cmd->advertising = (ADVERTISED_10baseT_Half
- | ADVERTISED_100baseT_Half
- | ADVERTISED_100baseT_Full
- | gigabit_advert | ADVERTISED_Autoneg);
-
- cmd->speed = priv->mii_info->speed;
- cmd->duplex = priv->mii_info->duplex;
- cmd->port = PORT_MII;
- cmd->phy_address = priv->mii_info->mii_id;
- cmd->transceiver = XCVR_EXTERNAL;
- cmd->autoneg = AUTONEG_ENABLE;
+ if (NULL == phydev)
+ return -ENODEV;
+
cmd->maxtxpkt = priv->txcount;
cmd->maxrxpkt = priv->rxcount;
- return 0;
+ return phy_ethtool_gset(phydev, cmd);
}
/* Return the length of the register structure */
@@ -241,14 +236,14 @@ static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int use
unsigned int count;
/* The timer is different, depending on the interface speed */
- switch (priv->mii_info->speed) {
- case 1000:
+ switch (priv->phydev->speed) {
+ case SPEED_1000:
count = GFAR_GBIT_TIME;
break;
- case 100:
+ case SPEED_100:
count = GFAR_100_TIME;
break;
- case 10:
+ case SPEED_10:
default:
count = GFAR_10_TIME;
break;
@@ -265,14 +260,14 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
unsigned int count;
/* The timer is different, depending on the interface speed */
- switch (priv->mii_info->speed) {
- case 1000:
+ switch (priv->phydev->speed) {
+ case SPEED_1000:
count = GFAR_GBIT_TIME;
break;
- case 100:
+ case SPEED_100:
count = GFAR_100_TIME;
break;
- case 10:
+ case SPEED_10:
default:
count = GFAR_10_TIME;
break;
@@ -292,6 +287,9 @@ static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
return -EOPNOTSUPP;
+ if (NULL == priv->phydev)
+ return -ENODEV;
+
cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -348,6 +346,22 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
else
priv->rxcoalescing = 1;
+ if (NULL == priv->phydev)
+ return -ENODEV;
+
+ /* Check the bounds of the values */
+ if (cvals->rx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
+ pr_info("Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
+ return -EINVAL;
+ }
+
+ if (cvals->rx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
+ pr_info("Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
+ return -EINVAL;
+ }
+
priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs);
priv->rxcount = cvals->rx_max_coalesced_frames;
@@ -358,6 +372,19 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals
else
priv->txcoalescing = 1;
+ /* Check the bounds of the values */
+ if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
+ pr_info("Coalescing is limited to %d microseconds\n",
+ GFAR_MAX_COAL_USECS);
+ return -EINVAL;
+ }
+
+ if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
+ pr_info("Coalescing is limited to %d frames\n",
+ GFAR_MAX_COAL_FRAMES);
+ return -EINVAL;
+ }
+
priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs);
priv->txcount = cvals->tx_max_coalesced_frames;
@@ -536,6 +563,7 @@ static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
struct ethtool_ops gfar_ethtool_ops = {
.get_settings = gfar_gsettings,
+ .set_settings = gfar_ssettings,
.get_drvinfo = gfar_gdrvinfo,
.get_regs_len = gfar_reglen,
.get_regs = gfar_get_regs,
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
new file mode 100644
index 000000000000..1eca1dbca7f1
--- /dev/null
+++ b/drivers/net/gianfar_mii.c
@@ -0,0 +1,219 @@
+/*
+ * drivers/net/gianfar_mii.c
+ *
+ * Gianfar Ethernet Driver -- MIIM bus implementation
+ * Provides Bus interface for MIIM regs
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "gianfar.h"
+#include "gianfar_mii.h"
+
+/* Write value to the PHY at mii_id at register regnum,
+ * on the bus, waiting until the write is done before returning.
+ * All PHY configuration is done through the TSEC1 MIIM regs */
+int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+ struct gfar_mii *regs = bus->priv;
+
+ /* Set the PHY address and the register address we want to write */
+ gfar_write(®s->miimadd, (mii_id << 8) | regnum);
+
+ /* Write out the value we want */
+ gfar_write(®s->miimcon, value);
+
+ /* Wait for the transaction to finish */
+ while (gfar_read(®s->miimind) & MIIMIND_BUSY)
+ cpu_relax();
+
+ return 0;
+}
+
+/* Read the bus for PHY at addr mii_id, register regnum, and
+ * return the value. Clears miimcom first. All PHY
+ * configuration has to be done through the TSEC1 MIIM regs */
+int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct gfar_mii *regs = bus->priv;
+ u16 value;
+
+ /* Set the PHY address and the register address we want to read */
+ gfar_write(®s->miimadd, (mii_id << 8) | regnum);
+
+ /* Clear miimcom, and then initiate a read */
+ gfar_write(®s->miimcom, 0);
+ gfar_write(®s->miimcom, MII_READ_COMMAND);
+
+ /* Wait for the transaction to finish */
+ while (gfar_read(®s->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
+ cpu_relax();
+
+ /* Grab the value of the register from miimstat */
+ value = gfar_read(®s->miimstat);
+
+ return value;
+}
+
+
+/* Reset the MIIM registers, and wait for the bus to free */
+int gfar_mdio_reset(struct mii_bus *bus)
+{
+ struct gfar_mii *regs = bus->priv;
+ unsigned int timeout = PHY_INIT_TIMEOUT;
+
+ spin_lock_bh(&bus->mdio_lock);
+
+ /* Reset the management interface */
+ gfar_write(®s->miimcfg, MIIMCFG_RESET);
+
+ /* Setup the MII Mgmt clock speed */
+ gfar_write(®s->miimcfg, MIIMCFG_INIT_VALUE);
+
+ /* Wait until the bus is free */
+ while ((gfar_read(®s->miimind) & MIIMIND_BUSY) &&
+ timeout--)
+ cpu_relax();
+
+ spin_unlock_bh(&bus->mdio_lock);
+
+ if(timeout <= 0) {
+ printk(KERN_ERR "%s: The MII Bus is stuck!\n",
+ bus->name);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+int gfar_mdio_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gianfar_mdio_data *pdata;
+ struct gfar_mii *regs;
+ struct mii_bus *new_bus;
+ int err = 0;
+
+ if (NULL == dev)
+ return -EINVAL;
+
+ new_bus = kmalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (NULL == new_bus)
+ return -ENOMEM;
+
+ new_bus->name = "Gianfar MII Bus",
+ new_bus->read = &gfar_mdio_read,
+ new_bus->write = &gfar_mdio_write,
+ new_bus->reset = &gfar_mdio_reset,
+ new_bus->id = pdev->id;
+
+ pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data;
+
+ if (NULL == pdata) {
+ printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id);
+ return -ENODEV;
+ }
+
+ /* Set the PHY base address */
+ regs = (struct gfar_mii *) ioremap(pdata->paddr,
+ sizeof (struct gfar_mii));
+
+ if (NULL == regs) {
+ err = -ENOMEM;
+ goto reg_map_fail;
+ }
+
+ new_bus->priv = regs;
+
+ new_bus->irq = pdata->irq;
+
+ new_bus->dev = dev;
+ dev_set_drvdata(dev, new_bus);
+
+ err = mdiobus_register(new_bus);
+
+ if (0 != err) {
+ printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
+ new_bus->name);
+ goto bus_register_fail;
+ }
+
+ return 0;
+
+bus_register_fail:
+ iounmap((void *) regs);
+reg_map_fail:
+ kfree(new_bus);
+
+ return err;
+}
+
+
+int gfar_mdio_remove(struct device *dev)
+{
+ struct mii_bus *bus = dev_get_drvdata(dev);
+
+ mdiobus_unregister(bus);
+
+ dev_set_drvdata(dev, NULL);
+
+ iounmap((void *) (&bus->priv));
+ bus->priv = NULL;
+ kfree(bus);
+
+ return 0;
+}
+
+static struct device_driver gianfar_mdio_driver = {
+ .name = "fsl-gianfar_mdio",
+ .bus = &platform_bus_type,
+ .probe = gfar_mdio_probe,
+ .remove = gfar_mdio_remove,
+};
+
+int __init gfar_mdio_init(void)
+{
+ return driver_register(&gianfar_mdio_driver);
+}
+
+void __exit gfar_mdio_exit(void)
+{
+ driver_unregister(&gianfar_mdio_driver);
+}
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
new file mode 100644
index 000000000000..56e5665d5c9b
--- /dev/null
+++ b/drivers/net/gianfar_mii.h
@@ -0,0 +1,45 @@
+/*
+ * drivers/net/gianfar_mii.h
+ *
+ * Gianfar Ethernet Driver -- MII Management Bus Implementation
+ * Driver for the MDIO bus controller in the Gianfar register space
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala (kumar.gala@freescale.com)
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __GIANFAR_MII_H
+#define __GIANFAR_MII_H
+
+#define MIIMIND_BUSY 0x00000001
+#define MIIMIND_NOTVALID 0x00000004
+
+#define MII_READ_COMMAND 0x00000001
+
+#define GFAR_SUPPORTED (SUPPORTED_10baseT_Half \
+ | SUPPORTED_100baseT_Half \
+ | SUPPORTED_100baseT_Full \
+ | SUPPORTED_Autoneg \
+ | SUPPORTED_MII)
+
+struct gfar_mii {
+ u32 miimcfg; /* 0x.520 - MII Management Config Register */
+ u32 miimcom; /* 0x.524 - MII Management Command Register */
+ u32 miimadd; /* 0x.528 - MII Management Address Register */
+ u32 miimcon; /* 0x.52c - MII Management Control Register */
+ u32 miimstat; /* 0x.530 - MII Management Status Register */
+ u32 miimind; /* 0x.534 - MII Management Indicator Register */
+};
+
+int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
+int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int __init gfar_mdio_init(void);
+void __exit gfar_mdio_exit(void);
+#endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/gianfar_phy.c b/drivers/net/gianfar_phy.c
deleted file mode 100644
index 7c965f268a82..000000000000
--- a/drivers/net/gianfar_phy.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * drivers/net/gianfar_phy.c
- *
- * Gianfar Ethernet Driver -- PHY handling
- * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560
- * Based on 8260_io/fcc_enet.c
- *
- * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
- *
- * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "gianfar.h"
-#include "gianfar_phy.h"
-
-static void config_genmii_advert(struct gfar_mii_info *mii_info);
-static void genmii_setup_forced(struct gfar_mii_info *mii_info);
-static void genmii_restart_aneg(struct gfar_mii_info *mii_info);
-static int gbit_config_aneg(struct gfar_mii_info *mii_info);
-static int genmii_config_aneg(struct gfar_mii_info *mii_info);
-static int genmii_update_link(struct gfar_mii_info *mii_info);
-static int genmii_read_status(struct gfar_mii_info *mii_info);
-u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum);
-void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val);
-
-/* Write value to the PHY for this device to the register at regnum, */
-/* waiting until the write is done before it returns. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value)
-{
- struct gfar_private *priv = netdev_priv(dev);
- struct gfar *regbase = priv->phyregs;
-
- /* Set the PHY address and the register address we want to write */
- gfar_write(®base->miimadd, (mii_id << 8) | regnum);
-
- /* Write out the value we want */
- gfar_write(®base->miimcon, value);
-
- /* Wait for the transaction to finish */
- while (gfar_read(®base->miimind) & MIIMIND_BUSY)
- cpu_relax();
-}
-
-/* Reads from register regnum in the PHY for device dev, */
-/* returning the value. Clears miimcom first. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
-{
- struct gfar_private *priv = netdev_priv(dev);
- struct gfar *regbase = priv->phyregs;
- u16 value;
-
- /* Set the PHY address and the register address we want to read */
- gfar_write(®base->miimadd, (mii_id << 8) | regnum);
-
- /* Clear miimcom, and then initiate a read */
- gfar_write(®base->miimcom, 0);
- gfar_write(®base->miimcom, MII_READ_COMMAND);
-
- /* Wait for the transaction to finish */
- while (gfar_read(®base->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
- cpu_relax();
-
- /* Grab the value of the register from miimstat */
- value = gfar_read(®base->miimstat);
-
- return value;
-}
-
-void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info)
-{
- if(mii_info->phyinfo->ack_interrupt)
- mii_info->phyinfo->ack_interrupt(mii_info);
-}
-
-
-void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts)
-{
- mii_info->interrupts = interrupts;
- if(mii_info->phyinfo->config_intr)
- mii_info->phyinfo->config_intr(mii_info);
-}
-
-
-/* Writes MII_ADVERTISE with the appropriate values, after
- * sanitizing advertise to make sure only supported features
- * are advertised
- */
-static void config_genmii_advert(struct gfar_mii_info *mii_info)
-{
- u32 advertise;
- u16 adv;
-
- /* Only allow advertising what this PHY supports */
- mii_info->advertising &= mii_info->phyinfo->features;
- advertise = mii_info->advertising;
-
- /* Setup standard advertisement */
- adv = phy_read(mii_info, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- phy_write(mii_info, MII_ADVERTISE, adv);
-}
-
-static void genmii_setup_forced(struct gfar_mii_info *mii_info)
-{
- u16 ctrl;
- u32 features = mii_info->phyinfo->features;
-
- ctrl = phy_read(mii_info, MII_BMCR);
-
- ctrl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPEED1000|BMCR_ANENABLE);
- ctrl |= BMCR_RESET;
-
- switch(mii_info->speed) {
- case SPEED_1000:
- if(features & (SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full)) {
- ctrl |= BMCR_SPEED1000;
- break;
- }
- mii_info->speed = SPEED_100;
- case SPEED_100:
- if (features & (SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full)) {
- ctrl |= BMCR_SPEED100;
- break;
- }
- mii_info->speed = SPEED_10;
- case SPEED_10:
- if (features & (SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full))
- break;
- default: /* Unsupported speed! */
- printk(KERN_ERR "%s: Bad speed!\n",
- mii_info->dev->name);
- break;
- }
-
- phy_write(mii_info, MII_BMCR, ctrl);
-}
-
-
-/* Enable and Restart Autonegotiation */
-static void genmii_restart_aneg(struct gfar_mii_info *mii_info)
-{
- u16 ctl;
-
- ctl = phy_read(mii_info, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- phy_write(mii_info, MII_BMCR, ctl);
-}
-
-
-static int gbit_config_aneg(struct gfar_mii_info *mii_info)
-{
- u16 adv;
- u32 advertise;
-
- if(mii_info->autoneg) {
- /* Configure the ADVERTISE register */
- config_genmii_advert(mii_info);
- advertise = mii_info->advertising;
-
- adv = phy_read(mii_info, MII_1000BASETCONTROL);
- adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
- MII_1000BASETCONTROL_HALFDUPLEXCAP);
- if (advertise & SUPPORTED_1000baseT_Half)
- adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
- if (advertise & SUPPORTED_1000baseT_Full)
- adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
- phy_write(mii_info, MII_1000BASETCONTROL, adv);
-
- /* Start/Restart aneg */
- genmii_restart_aneg(mii_info);
- } else
- genmii_setup_forced(mii_info);
-
- return 0;
-}
-
-static int marvell_config_aneg(struct gfar_mii_info *mii_info)
-{
- /* The Marvell PHY has an errata which requires
- * that certain registers get written in order
- * to restart autonegotiation */
- phy_write(mii_info, MII_BMCR, BMCR_RESET);
-
- phy_write(mii_info, 0x1d, 0x1f);
- phy_write(mii_info, 0x1e, 0x200c);
- phy_write(mii_info, 0x1d, 0x5);
- phy_write(mii_info, 0x1e, 0);
- phy_write(mii_info, 0x1e, 0x100);
-
- gbit_config_aneg(mii_info);
-
- return 0;
-}
-static int genmii_config_aneg(struct gfar_mii_info *mii_info)
-{
- if (mii_info->autoneg) {
- config_genmii_advert(mii_info);
- genmii_restart_aneg(mii_info);
- } else
- genmii_setup_forced(mii_info);
-
- return 0;
-}
-
-
-static int genmii_update_link(struct gfar_mii_info *mii_info)
-{
- u16 status;
-
- /* Do a fake read */
- phy_read(mii_info, MII_BMSR);
-
- /* Read link and autonegotiation status */
- status = phy_read(mii_info, MII_BMSR);
- if ((status & BMSR_LSTATUS) == 0)
- mii_info->link = 0;
- else
- mii_info->link = 1;
-
- /* If we are autonegotiating, and not done,
- * return an error */
- if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
- return -EAGAIN;
-
- return 0;
-}
-
-static int genmii_read_status(struct gfar_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- if (mii_info->autoneg) {
- status = phy_read(mii_info, MII_LPA);
-
- if (status & (LPA_10FULL | LPA_100FULL))
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
- if (status & (LPA_100FULL | LPA_100HALF))
- mii_info->speed = SPEED_100;
- else
- mii_info->speed = SPEED_10;
- mii_info->pause = 0;
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-static int marvell_read_status(struct gfar_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- int speed;
- status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
-
-#if 0
- /* If speed and duplex aren't resolved,
- * return an error. Isn't this handled
- * by checking aneg?
- */
- if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
- return -EAGAIN;
-#endif
-
- /* Get the duplexity */
- if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
-
- /* Get the speed */
- speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
- switch(speed) {
- case MII_M1011_PHY_SPEC_STATUS_1000:
- mii_info->speed = SPEED_1000;
- break;
- case MII_M1011_PHY_SPEC_STATUS_100:
- mii_info->speed = SPEED_100;
- break;
- default:
- mii_info->speed = SPEED_10;
- break;
- }
- mii_info->pause = 0;
- }
-
- return 0;
-}
-
-
-static int cis820x_read_status(struct gfar_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- int speed;
-
- status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
- if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
-
- speed = status & MII_CIS8201_AUXCONSTAT_SPEED;
-
- switch (speed) {
- case MII_CIS8201_AUXCONSTAT_GBIT:
- mii_info->speed = SPEED_1000;
- break;
- case MII_CIS8201_AUXCONSTAT_100:
- mii_info->speed = SPEED_100;
- break;
- default:
- mii_info->speed = SPEED_10;
- break;
- }
- }
-
- return 0;
-}
-
-static int marvell_ack_interrupt(struct gfar_mii_info *mii_info)
-{
- /* Clear the interrupts by reading the reg */
- phy_read(mii_info, MII_M1011_IEVENT);
-
- return 0;
-}
-
-static int marvell_config_intr(struct gfar_mii_info *mii_info)
-{
- if(mii_info->interrupts == MII_INTERRUPT_ENABLED)
- phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
- else
- phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
-
- return 0;
-}
-
-static int cis820x_init(struct gfar_mii_info *mii_info)
-{
- phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
- MII_CIS8201_AUXCONSTAT_INIT);
- phy_write(mii_info, MII_CIS8201_EXT_CON1,
- MII_CIS8201_EXTCON1_INIT);
-
- return 0;
-}
-
-static int cis820x_ack_interrupt(struct gfar_mii_info *mii_info)
-{
- phy_read(mii_info, MII_CIS8201_ISTAT);
-
- return 0;
-}
-
-static int cis820x_config_intr(struct gfar_mii_info *mii_info)
-{
- if(mii_info->interrupts == MII_INTERRUPT_ENABLED)
- phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
- else
- phy_write(mii_info, MII_CIS8201_IMASK, 0);
-
- return 0;
-}
-
-#define DM9161_DELAY 10
-
-static int dm9161_read_status(struct gfar_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- status = phy_read(mii_info, MII_DM9161_SCSR);
- if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
- mii_info->speed = SPEED_100;
- else
- mii_info->speed = SPEED_10;
-
- if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
- }
-
- return 0;
-}
-
-
-static int dm9161_config_aneg(struct gfar_mii_info *mii_info)
-{
- struct dm9161_private *priv = mii_info->priv;
-
- if(0 == priv->resetdone)
- return -EAGAIN;
-
- return 0;
-}
-
-static void dm9161_timer(unsigned long data)
-{
- struct gfar_mii_info *mii_info = (struct gfar_mii_info *)data;
- struct dm9161_private *priv = mii_info->priv;
- u16 status = phy_read(mii_info, MII_BMSR);
-
- if (status & BMSR_ANEGCOMPLETE) {
- priv->resetdone = 1;
- } else
- mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-}
-
-static int dm9161_init(struct gfar_mii_info *mii_info)
-{
- struct dm9161_private *priv;
-
- /* Allocate the private data structure */
- priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
-
- if (NULL == priv)
- return -ENOMEM;
-
- mii_info->priv = priv;
-
- /* Reset is not done yet */
- priv->resetdone = 0;
-
- /* Isolate the PHY */
- phy_write(mii_info, MII_BMCR, BMCR_ISOLATE);
-
- /* Do not bypass the scrambler/descrambler */
- phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
-
- /* Clear 10BTCSR to default */
- phy_write(mii_info, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT);
-
- /* Reconnect the PHY, and enable Autonegotiation */
- phy_write(mii_info, MII_BMCR, BMCR_ANENABLE);
-
- /* Start a timer for DM9161_DELAY seconds to wait
- * for the PHY to be ready */
- init_timer(&priv->timer);
- priv->timer.function = &dm9161_timer;
- priv->timer.data = (unsigned long) mii_info;
- mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-
- return 0;
-}
-
-static void dm9161_close(struct gfar_mii_info *mii_info)
-{
- struct dm9161_private *priv = mii_info->priv;
-
- del_timer_sync(&priv->timer);
- kfree(priv);
-}
-
-#if 0
-static int dm9161_ack_interrupt(struct gfar_mii_info *mii_info)
-{
- phy_read(mii_info, MII_DM9161_INTR);
-
- return 0;
-}
-#endif
-
-/* Cicada 820x */
-static struct phy_info phy_info_cis820x = {
- 0x000fc440,
- "Cicada Cis8204",
- 0x000fffc0,
- .features = MII_GBIT_FEATURES,
- .init = &cis820x_init,
- .config_aneg = &gbit_config_aneg,
- .read_status = &cis820x_read_status,
- .ack_interrupt = &cis820x_ack_interrupt,
- .config_intr = &cis820x_config_intr,
-};
-
-static struct phy_info phy_info_dm9161 = {
- .phy_id = 0x0181b880,
- .name = "Davicom DM9161E",
- .phy_id_mask = 0x0ffffff0,
- .init = dm9161_init,
- .config_aneg = dm9161_config_aneg,
- .read_status = dm9161_read_status,
- .close = dm9161_close,
-};
-
-static struct phy_info phy_info_marvell = {
- .phy_id = 0x01410c00,
- .phy_id_mask = 0xffffff00,
- .name = "Marvell 88E1101/88E1111",
- .features = MII_GBIT_FEATURES,
- .config_aneg = &marvell_config_aneg,
- .read_status = &marvell_read_status,
- .ack_interrupt = &marvell_ack_interrupt,
- .config_intr = &marvell_config_intr,
-};
-
-static struct phy_info phy_info_genmii= {
- .phy_id = 0x00000000,
- .phy_id_mask = 0x00000000,
- .name = "Generic MII",
- .features = MII_BASIC_FEATURES,
- .config_aneg = genmii_config_aneg,
- .read_status = genmii_read_status,
-};
-
-static struct phy_info *phy_info[] = {
- &phy_info_cis820x,
- &phy_info_marvell,
- &phy_info_dm9161,
- &phy_info_genmii,
- NULL
-};
-
-u16 phy_read(struct gfar_mii_info *mii_info, u16 regnum)
-{
- u16 retval;
- unsigned long flags;
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-
- return retval;
-}
-
-void phy_write(struct gfar_mii_info *mii_info, u16 regnum, u16 val)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- mii_info->mdio_write(mii_info->dev,
- mii_info->mii_id,
- regnum, val);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-}
-
-/* Use the PHY ID registers to determine what type of PHY is attached
- * to device dev. return a struct phy_info structure describing that PHY
- */
-struct phy_info * get_phy_info(struct gfar_mii_info *mii_info)
-{
- u16 phy_reg;
- u32 phy_ID;
- int i;
- struct phy_info *theInfo = NULL;
- struct net_device *dev = mii_info->dev;
-
- /* Grab the bits from PHYIR1, and put them in the upper half */
- phy_reg = phy_read(mii_info, MII_PHYSID1);
- phy_ID = (phy_reg & 0xffff) << 16;
-
- /* Grab the bits from PHYIR2, and put them in the lower half */
- phy_reg = phy_read(mii_info, MII_PHYSID2);
- phy_ID |= (phy_reg & 0xffff);
-
- /* loop through all the known PHY types, and find one that */
- /* matches the ID we read from the PHY. */
- for (i = 0; phy_info[i]; i++)
- if (phy_info[i]->phy_id ==
- (phy_ID & phy_info[i]->phy_id_mask)) {
- theInfo = phy_info[i];
- break;
- }
-
- /* This shouldn't happen, as we have generic PHY support */
- if (theInfo == NULL) {
- printk("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
- return NULL;
- } else {
- printk("%s: PHY is %s (%x)\n", dev->name, theInfo->name,
- phy_ID);
- }
-
- return theInfo;
-}
diff --git a/drivers/net/gianfar_phy.h b/drivers/net/gianfar_phy.h
deleted file mode 100644
index 1e9b3abf1e6d..000000000000
--- a/drivers/net/gianfar_phy.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * drivers/net/gianfar_phy.h
- *
- * Gianfar Ethernet Driver -- PHY handling
- * Driver for FEC on MPC8540 and TSEC on MPC8540/MPC8560
- * Based on 8260_io/fcc_enet.c
- *
- * Author: Andy Fleming
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
- *
- * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-#ifndef __GIANFAR_PHY_H
-#define __GIANFAR_PHY_H
-
-#define MII_end ((u32)-2)
-#define MII_read ((u32)-1)
-
-#define MIIMIND_BUSY 0x00000001
-#define MIIMIND_NOTVALID 0x00000004
-
-#define GFAR_AN_TIMEOUT 2000
-
-/* 1000BT control (Marvell & BCM54xx at least) */
-#define MII_1000BASETCONTROL 0x09
-#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200
-#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100
-
-/* Cicada Extended Control Register 1 */
-#define MII_CIS8201_EXT_CON1 0x17
-#define MII_CIS8201_EXTCON1_INIT 0x0000
-
-/* Cicada Interrupt Mask Register */
-#define MII_CIS8201_IMASK 0x19
-#define MII_CIS8201_IMASK_IEN 0x8000
-#define MII_CIS8201_IMASK_SPEED 0x4000
-#define MII_CIS8201_IMASK_LINK 0x2000
-#define MII_CIS8201_IMASK_DUPLEX 0x1000
-#define MII_CIS8201_IMASK_MASK 0xf000
-
-/* Cicada Interrupt Status Register */
-#define MII_CIS8201_ISTAT 0x1a
-#define MII_CIS8201_ISTAT_STATUS 0x8000
-#define MII_CIS8201_ISTAT_SPEED 0x4000
-#define MII_CIS8201_ISTAT_LINK 0x2000
-#define MII_CIS8201_ISTAT_DUPLEX 0x1000
-
-/* Cicada Auxiliary Control/Status Register */
-#define MII_CIS8201_AUX_CONSTAT 0x1c
-#define MII_CIS8201_AUXCONSTAT_INIT 0x0004
-#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020
-#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018
-#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010
-#define MII_CIS8201_AUXCONSTAT_100 0x0008
-
-/* 88E1011 PHY Status Register */
-#define MII_M1011_PHY_SPEC_STATUS 0x11
-#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000
-#define MII_M1011_PHY_SPEC_STATUS_100 0x4000
-#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000
-#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000
-#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800
-#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400
-
-#define MII_M1011_IEVENT 0x13
-#define MII_M1011_IEVENT_CLEAR 0x0000
-
-#define MII_M1011_IMASK 0x12
-#define MII_M1011_IMASK_INIT 0x6400
-#define MII_M1011_IMASK_CLEAR 0x0000
-
-#define MII_DM9161_SCR 0x10
-#define MII_DM9161_SCR_INIT 0x0610
-
-/* DM9161 Specified Configuration and Status Register */
-#define MII_DM9161_SCSR 0x11
-#define MII_DM9161_SCSR_100F 0x8000
-#define MII_DM9161_SCSR_100H 0x4000
-#define MII_DM9161_SCSR_10F 0x2000
-#define MII_DM9161_SCSR_10H 0x1000
-
-/* DM9161 Interrupt Register */
-#define MII_DM9161_INTR 0x15
-#define MII_DM9161_INTR_PEND 0x8000
-#define MII_DM9161_INTR_DPLX_MASK 0x0800
-#define MII_DM9161_INTR_SPD_MASK 0x0400
-#define MII_DM9161_INTR_LINK_MASK 0x0200
-#define MII_DM9161_INTR_MASK 0x0100
-#define MII_DM9161_INTR_DPLX_CHANGE 0x0010
-#define MII_DM9161_INTR_SPD_CHANGE 0x0008
-#define MII_DM9161_INTR_LINK_CHANGE 0x0004
-#define MII_DM9161_INTR_INIT 0x0000
-#define MII_DM9161_INTR_STOP \
-(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
- | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
-
-/* DM9161 10BT Configuration/Status */
-#define MII_DM9161_10BTCSR 0x12
-#define MII_DM9161_10BTCSR_INIT 0x7800
-
-#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
- SUPPORTED_10baseT_Full | \
- SUPPORTED_100baseT_Half | \
- SUPPORTED_100baseT_Full | \
- SUPPORTED_Autoneg | \
- SUPPORTED_TP | \
- SUPPORTED_MII)
-
-#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
- SUPPORTED_1000baseT_Half | \
- SUPPORTED_1000baseT_Full)
-
-#define MII_READ_COMMAND 0x00000001
-
-#define MII_INTERRUPT_DISABLED 0x0
-#define MII_INTERRUPT_ENABLED 0x1
-/* Taken from mii_if_info and sungem_phy.h */
-struct gfar_mii_info {
- /* Information about the PHY type */
- /* And management functions */
- struct phy_info *phyinfo;
-
- /* forced speed & duplex (no autoneg)
- * partner speed & duplex & pause (autoneg)
- */
- int speed;
- int duplex;
- int pause;
-
- /* The most recently read link state */
- int link;
-
- /* Enabled Interrupts */
- u32 interrupts;
-
- u32 advertising;
- int autoneg;
- int mii_id;
-
- /* private data pointer */
- /* For use by PHYs to maintain extra state */
- void *priv;
-
- /* Provided by host chip */
- struct net_device *dev;
-
- /* A lock to ensure that only one thing can read/write
- * the MDIO bus at a time */
- spinlock_t mdio_lock;
-
- /* Provided by ethernet driver */
- int (*mdio_read) (struct net_device *dev, int mii_id, int reg);
- void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val);
-};
-
-/* struct phy_info: a structure which defines attributes for a PHY
- *
- * id will contain a number which represents the PHY. During
- * startup, the driver will poll the PHY to find out what its
- * UID--as defined by registers 2 and 3--is. The 32-bit result
- * gotten from the PHY will be ANDed with phy_id_mask to
- * discard any bits which may change based on revision numbers
- * unimportant to functionality
- *
- * There are 6 commands which take a gfar_mii_info structure.
- * Each PHY must declare config_aneg, and read_status.
- */
-struct phy_info {
- u32 phy_id;
- char *name;
- unsigned int phy_id_mask;
- u32 features;
-
- /* Called to initialize the PHY */
- int (*init)(struct gfar_mii_info *mii_info);
-
- /* Called to suspend the PHY for power */
- int (*suspend)(struct gfar_mii_info *mii_info);
-
- /* Reconfigures autonegotiation (or disables it) */
- int (*config_aneg)(struct gfar_mii_info *mii_info);
-
- /* Determines the negotiated speed and duplex */
- int (*read_status)(struct gfar_mii_info *mii_info);
-
- /* Clears any pending interrupts */
- int (*ack_interrupt)(struct gfar_mii_info *mii_info);
-
- /* Enables or disables interrupts */
- int (*config_intr)(struct gfar_mii_info *mii_info);
-
- /* Clears up any memory if needed */
- void (*close)(struct gfar_mii_info *mii_info);
-};
-
-struct phy_info *get_phy_info(struct gfar_mii_info *mii_info);
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum);
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value);
-void mii_clear_phy_interrupt(struct gfar_mii_info *mii_info);
-void mii_configure_phy_interrupt(struct gfar_mii_info *mii_info, u32 interrupts);
-
-struct dm9161_private {
- struct timer_list timer;
- int resetdone;
-};
-
-#endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index de087cd609d9..896aa02000d7 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -1,6 +1,7 @@
config MKISS
tristate "Serial port KISS driver"
depends on AX25
+ select CRC16
---help---
KISS is a protocol used for the exchange of data between a computer
and a Terminal Node Controller (a small embedded system commonly
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 1756f0ed54cc..cb43a9d28774 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -144,7 +144,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev)
{
struct bpqdev *bpq;
- list_for_each_entry(bpq, &bpq_devices, bpq_list) {
+ list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) {
if (bpq->ethdev == dev)
return bpq->axdev;
}
@@ -399,7 +399,7 @@ static void *bpq_seq_start(struct seq_file *seq, loff_t *pos)
if (*pos == 0)
return SEQ_START_TOKEN;
- list_for_each_entry(bpqdev, &bpq_devices, bpq_list) {
+ list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) {
if (i == *pos)
return bpqdev;
}
@@ -418,7 +418,7 @@ static void *bpq_seq_next(struct seq_file *seq, void *v, loff_t *pos)
p = ((struct bpqdev *)v)->bpq_list.next;
return (p == &bpq_devices) ? NULL
- : list_entry(p, struct bpqdev, bpq_list);
+ : rcu_dereference(list_entry(p, struct bpqdev, bpq_list));
}
static void bpq_seq_stop(struct seq_file *seq, void *v)
@@ -561,8 +561,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;
- rcu_read_lock();
-
switch (event) {
case NETDEV_UP: /* new ethernet device -> new BPQ interface */
if (bpq_get_ax25_dev(dev) == NULL)
@@ -581,7 +579,6 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi
default:
break;
}
- rcu_read_unlock();
return NOTIFY_DONE;
}
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d9fe64b46f4b..85d6dc005be0 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -14,13 +14,14 @@
*
* Copyright (C) Hans Alblas PE1AYX
* Copyright (C) 2004, 05 Ralf Baechle DL5RB
+ * Copyright (C) 2004, 05 Thomas Osterried DL9SAU
*/
-
#include