diff options
221 files changed, 4051 insertions, 4407 deletions
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl index 6df1dfd..375ae76 100644 --- a/Documentation/DocBook/libata.tmpl +++ b/Documentation/DocBook/libata.tmpl @@ -84,6 +84,14 @@ void (*port_disable) (struct ata_port *); Called from ata_bus_probe() and ata_bus_reset() error paths, as well as when unregistering from the SCSI module (rmmod, hot unplug). + This function should do whatever needs to be done to take the + port out of use. In most cases, ata_port_disable() can be used + as this hook. + </para> + <para> + Called from ata_bus_probe() on a failed probe. + Called from ata_bus_reset() on a failed bus reset. + Called from ata_scsi_release(). </para> </sect2> @@ -98,6 +106,13 @@ void (*dev_config) (struct ata_port *, struct ata_device *); found. Typically used to apply device-specific fixups prior to issue of SET FEATURES - XFER MODE, and prior to operation. </para> + <para> + Called by ata_device_add() after ata_dev_identify() determines + a device is present. + </para> + <para> + This entry may be specified as NULL in ata_port_operations. + </para> </sect2> @@ -135,6 +150,8 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); registers / DMA buffers. ->tf_read() is called to read the hardware registers / DMA buffers, to obtain the current set of taskfile register values. + Most drivers for taskfile-based hardware (PIO or MMIO) use + ata_tf_load() and ata_tf_read() for these hooks. </para> </sect2> @@ -147,6 +164,8 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); <para> causes an ATA command, previously loaded with ->tf_load(), to be initiated in hardware. + Most drivers for taskfile-based hardware use ata_exec_command() + for this hook. </para> </sect2> @@ -161,6 +180,10 @@ Allow low-level driver to filter ATA PACKET commands, returning a status indicating whether or not it is OK to use DMA for the supplied PACKET command. </para> + <para> + This hook may be specified as NULL, in which case libata will + assume that atapi dma can be supported. + </para> </sect2> @@ -175,6 +198,14 @@ u8 (*check_err)(struct ata_port *ap); Reads the Status/AltStatus/Error ATA shadow register from hardware. On some hardware, reading the Status register has the side effect of clearing the interrupt condition. + Most drivers for taskfile-based hardware use + ata_check_status() for this hook. + </para> + <para> + Note that because this is called from ata_device_add(), at + least a dummy function that clears device interrupts must be + provided for all drivers, even if the controller doesn't + actually have a taskfile status register. </para> </sect2> @@ -188,7 +219,13 @@ void (*dev_select)(struct ata_port *ap, unsigned int device); Issues the low-level hardware command(s) that causes one of N hardware devices to be considered 'selected' (active and available for use) on the ATA bus. This generally has no -meaning on FIS-based devices. + meaning on FIS-based devices. + </para> + <para> + Most drivers for taskfile-based hardware use + ata_std_dev_select() for this hook. Controllers which do not + support second drives on a port (such as SATA contollers) will + use ata_noop_dev_select(). </para> </sect2> @@ -204,6 +241,8 @@ void (*phy_reset) (struct ata_port *ap); for device presence (PATA and SATA), typically a soft reset (SRST) will be performed. Drivers typically use the helper functions ata_bus_reset() or sata_phy_reset() for this hook. + Many SATA drivers use sata_phy_reset() or call it from within + their own phy_reset() functions. </para> </sect2> @@ -227,6 +266,25 @@ PCI IDE DMA Status register. These hooks are typically either no-ops, or simply not implemented, in FIS-based drivers. </para> + <para> +Most legacy IDE drivers use ata_bmdma_setup() for the bmdma_setup() +hook. ata_bmdma_setup() will write the pointer to the PRD table to +the IDE PRD Table Address register, enable DMA in the DMA Command +register, and call exec_command() to begin the transfer. + </para> + <para> +Most legacy IDE drivers use ata_bmdma_start() for the bmdma_start() +hook. ata_bmdma_start() will write the ATA_DMA_START flag to the DMA +Command register. + </para> + <para> +Many legacy IDE drivers use ata_bmdma_stop() for the bmdma_stop() +hook. ata_bmdma_stop() clears the ATA_DMA_START flag in the DMA +command register. + </para> + <para> +Many legacy IDE drivers use ata_bmdma_status() as the bmdma_status() hook. + </para> </sect2> @@ -250,6 +308,10 @@ int (*qc_issue) (struct ata_queued_cmd *qc); helper function ata_qc_issue_prot() for taskfile protocol-based dispatch. More advanced drivers implement their own ->qc_issue. </para> + <para> + ata_qc_issue_prot() calls ->tf_load(), ->bmdma_setup(), and + ->bmdma_start() as necessary to initiate a transfer. + </para> </sect2> @@ -279,6 +341,21 @@ void (*irq_clear) (struct ata_port *); before the interrupt handler is registered, to be sure hardware is quiet. </para> + <para> + The second argument, dev_instance, should be cast to a pointer + to struct ata_host_set. + </para> + <para> + Most legacy IDE drivers use ata_interrupt() for the + irq_handler hook, which scans all ports in the host_set, + determines which queued command was active (if any), and calls + ata_host_intr(ap,qc). + </para> + <para> + Most legacy IDE drivers use ata_bmdma_irq_clear() for the + irq_clear() hook, which simply clears the interrupt and error + flags in the DMA status register. + </para> </sect2> @@ -292,6 +369,7 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, <para> Read and write standard SATA phy registers. Currently only used if ->phy_reset hook called the sata_phy_reset() helper function. + sc_reg is one of SCR_STATUS, SCR_CONTROL, SCR_ERROR, or SCR_ACTIVE. </para> </sect2> @@ -307,17 +385,29 @@ void (*host_stop) (struct ata_host_set *host_set); ->port_start() is called just after the data structures for each port are initialized. Typically this is used to alloc per-port DMA buffers / tables / rings, enable DMA engines, and similar - tasks. + tasks. Some drivers also use this entry point as a chance to + allocate driver-private memory for ap->private_data. + </para> + <para> + Many drivers use ata_port_start() as this hook or call + it from their own port_start() hooks. ata_port_start() + allocates space for a legacy IDE PRD table and returns. </para> <para> ->port_stop() is called after ->host_stop(). It's sole function is to release DMA/memory resources, now that they are no longer - actively being used. + actively being used. Many drivers also free driver-private + data from port at this time. + </para> + <para> + Many drivers use ata_port_stop() as this hook, which frees the + PRD table. </para> <para> ->host_stop() is called after all ->port_stop() calls have completed. The hook must finalize hardware shutdown, release DMA and other resources, etc. + This hook may be specified as NULL, in which case it is not called. </para> </sect2> diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers index de3b252..c3cca92 100644 --- a/Documentation/SubmittingDrivers +++ b/Documentation/SubmittingDrivers @@ -13,13 +13,14 @@ Allocating Device Numbers ------------------------- Major and minor numbers for block and character devices are allocated -by the Linux assigned name and number authority (currently better -known as H Peter Anvin). The site is http://www.lanana.org/. This +by the Linux assigned name and number authority (currently this is +Torben Mathiasen). The site is http://www.lanana.org/. This also deals with allocating numbers for devices that are not going to be submitted to the mainstream kernel. +See Documentation/devices.txt for more information on this. -If you don't use assigned numbers then when you device is submitted it will -get given an assigned number even if that is different from values you may +If you don't use assigned numbers then when your device is submitted it will +be given an assigned number even if that is different from values you may have shipped to customers before. Who To Submit Drivers To @@ -32,7 +33,8 @@ Linux 2.2: If the code area has a general maintainer then please submit it to the maintainer listed in MAINTAINERS in the kernel file. If the maintainer does not respond or you cannot find the appropriate - maintainer then please contact Alan Cox <alan@lxorguk.ukuu.org.uk> + maintainer then please contact the 2.2 kernel maintainer: + Marc-Christian Petersen <m.c.p@wolk-project.de>. Linux 2.4: The same rules apply as 2.2. The final contact point for Linux 2.4 @@ -48,7 +50,7 @@ What Criteria Determine Acceptance Licensing: The code must be released to us under the GNU General Public License. We don't insist on any kind - of exclusively GPL licensing, and if you wish the driver + of exclusive GPL licensing, and if you wish the driver to be useful to other communities such as BSD you may well wish to release under multiple licenses. diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 4d1f41b..6761a7b 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -35,7 +35,7 @@ not in any lower subdirectory. To create a patch for a single file, it is often sufficient to do: - SRCTREE= linux-2.4 + SRCTREE= linux-2.6 MYFILE= drivers/net/mydriver.c cd $SRCTREE @@ -48,17 +48,18 @@ To create a patch for multiple files, you should unpack a "vanilla", or unmodified kernel source tree, and generate a diff against your own source tree. For example: - MYSRC= /devel/linux-2.4 + MYSRC= /devel/linux-2.6 - tar xvfz linux-2.4.0-test11.tar.gz - mv linux linux-vanilla - wget http://www.moses.uklinux.net/patches/dontdiff - diff -uprN -X dontdiff linux-vanilla $MYSRC > /tmp/patch - rm -f dontdiff + tar xvfz linux-2.6.12.tar.gz + mv linux-2.6.12 linux-2.6.12-vanilla + diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \ + linux-2.6.12-vanilla $MYSRC > /tmp/patch "dontdiff" is a list of files which are generated by the kernel during the build process, and should be ignored in any diff(1)-generated -patch. dontdiff is maintained by Tigran Aivazian <tigran@veritas.com> +patch. The "dontdiff" file is included in the kernel tree in +2.6.12 and later. For earlier kernel versions, you can get it +from <http://www.xenotime.net/linux/doc/dontdiff>. Make sure your patch does not include any extra files which do not belong in a patch submission. Make sure to review your patch -after- @@ -66,18 +67,20 @@ generated it with diff(1), to ensure accuracy. If your changes produce a lot of deltas, you may want to look into splitting them into individual patches which modify things in -logical stages, this will facilitate easier reviewing by other +logical stages. This will facilitate easier reviewing by other kernel developers, very important if you want your patch accepted. -There are a number of scripts which can aid in this; +There are a number of scripts which can aid in this: Quilt: http://savannah.nongnu.org/projects/quilt Randy Dunlap's patch scripts: -http://developer.osdl.org/rddunlap/scripts/patching-scripts.tgz +http://www.xenotime.net/linux/scripts/patching-scripts-002.tar.gz Andrew Morton's patch scripts: -http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.16 +http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.20 + + 2) Describe your changes. @@ -163,6 +166,8 @@ patches. Trivial patches must qualify for one of the following rules: since people copy, as long as it's trivial) Any fix by the author/maintainer of the file. (ie. patch monkey in re-transmission mode) +URL: <http://www.kernel.org/pub/linux/kernel/people/rusty/trivial/> + @@ -291,6 +296,17 @@ now, but you can do this to mark internal company procedures or just point out some special detail about the sign-off. + +12) More references for submitting patches + +Andrew Morton, "The perfect patch" (tpp). + <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt> + +Jeff Garzik, "Linux kernel patch submission format." + <http://linux.yyz.us/patch-format.html> + + + ----------------------------------- SECTION 2 - HINTS, TIPS, AND TRICKS ----------------------------------- @@ -359,7 +375,5 @@ and 'extern __inline__'. 4) Don't over-design. Don't try to anticipate nebulous future cases which may or may not -be useful: "Make it as simple as you can, and no simpler" - - +be useful: "Make it as simple as you can, and no simpler." diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 89cd417..4ec75c0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -622,6 +622,17 @@ running once the system is up. ips= [HW,SCSI] Adaptec / IBM ServeRAID controller See header of drivers/scsi/ips.c. + irqfixup [HW] + When an interrupt is not handled search all handlers + for it. Intended to get systems with badly broken + firmware running. + + irqpoll [HW] + When an interrupt is not handled search all handlers + for it. Also check all handlers each timer + interrupt. Intended to get systems with badly broken + firmware running. + isapnp= [ISAPNP] Format: <RDP>, <reset>, <pci_scan>, <verbosity> @@ -1030,6 +1041,10 @@ running once the system is up. irqmask=0xMMMM [IA-32] Set a bit mask of IRQs allowed to be assigned automatically to PCI devices. You can make the kernel exclude IRQs of your ISA cards this way. + pirqaddr=0xAAAAA [IA-32] Specify the physical address + of the PIRQ table (normally generated + by the BIOS) if it is outside the + F0000h-100000h range. lastbus=N [IA-32] Scan all buses till bus #N. Can be useful if the kernel is unable to find your secondary buses and you want to tell it explicitly which ones they are. diff --git a/Documentation/video4linux/API.html b/Documentation/video4linux/API.html index 4b3d8f6..441407b 100644 --- a/Documentation/video4linux/API.html +++ b/Documentation/video4linux/API.html @@ -1,399 +1,16 @@ -<HTML><HEAD> -<TITLE>Video4Linux Kernel API Reference v0.1:19990430</TITLE> -</HEAD> -<! Revision History: > -<! 4/30/1999 - Fred Gleason (fredg@wava.com)> -<! Documented extensions for the Radio Data System (RDS) extensions > -<BODY bgcolor="#ffffff"> -<H3>Devices</H3> -Video4Linux provides the following sets of device files. These live on the -character device formerly known as "/dev/bttv". /dev/bttv should be a -symlink to /dev/video0 for most people. -<P> -<TABLE> -<TR><TH>Device Name</TH><TH>Minor Range</TH><TH>Function</TH> -<TR><TD>/dev/video</TD><TD>0-63</TD><TD>Video Capture Interface</TD> -<TR><TD>/dev/radio</TD><TD>64-127</TD><TD>AM/FM Radio Devices</TD> -<TR><TD>/dev/vtx</TD><TD>192-223</TD><TD>Teletext Interface Chips</TD> -<TR><TD>/dev/vbi</TD><TD>224-239</TD><TD>Raw VBI Data (Intercast/teletext)</TD> -</TABLE> -<P> -Video4Linux programs open and scan the devices to find what they are looking -for. Capability queries define what each interface supports. The -described API is only defined for video capture cards. The relevant subset -applies to radio cards. Teletext interfaces talk the existing VTX API. -<P> -<H3>Capability Query Ioctl</H3> -The <B>VIDIOCGCAP</B> ioctl call is used to obtain the capability -information for a video device. The <b>struct video_capability</b> object -passed to the ioctl is completed and returned. It contains the following -information -<P> -<TABLE> -<TR><TD><b>name[32]</b><TD>Canonical name for this interface</TD> -<TR><TD><b>type</b><TD>Type of interface</TD> -<TR><TD><b>channels</b><TD>Number of radio/tv channels if appropriate</TD> -<TR><TD><b>audios</b><TD>Number of audio devices if appropriate</TD> -<TR><TD><b>maxwidth</b><TD>Maximum capture width in pixels</TD> -<TR><TD><b>maxheight</b><TD>Maximum capture height in pixels</TD> -<TR><TD><b>minwidth</b><TD>Minimum capture width in pixels</TD> -<TR><TD><b>minheight</b><TD>Minimum capture height in pixels</TD> -</TABLE> -<P> -The type field lists the capability flags for the device. These are -as follows -<P> -<TABLE> -<TR><TH>Name</TH><TH>Description</TH> -<TR><TD><b>VID_TYPE_CAPTURE</b><TD>Can capture to memory</TD> -<TR><TD><b>VID_TYPE_TUNER</b><TD>Has a tuner of some form</TD> -<TR><TD><b>VID_TYPE_TELETEXT</b><TD>Has teletext capability</TD> -<TR><TD><b>VID_TYPE_OVERLAY</b><TD>Can overlay its image onto the frame buffer</TD> -<TR><TD><b>VID_TYPE_CHROMAKEY</b><TD>Overlay is Chromakeyed</TD> -<TR><TD><b>VID_TYPE_CLIPPING</b><TD>Overlay clipping is supported</TD> -<TR><TD><b>VID_TYPE_FRAMERAM</b><TD>Overlay overwrites frame buffer memory</TD> -<TR><TD><b>VID_TYPE_SCALES</b><TD>The hardware supports image scaling</TD> -<TR><TD><b>VID_TYPE_MONOCHROME</b><TD>Image capture is grey scale only</TD> -<TR><TD><b>VID_TYPE_SUBCAPTURE</b><TD>Capture can be of only part of the image</TD> -</TABLE> -<P> -The minimum and maximum sizes listed for a capture device do not imply all -that all height/width ratios or sizes within the range are possible. A -request to set a size will be honoured by the largest available capture -size whose capture is no large than the requested rectangle in either -direction. For example the quickcam has 3 fixed settings. -<P> -<H3>Frame Buffer</H3> -Capture cards that drop data directly onto the frame buffer must be told the -base address of the frame buffer, its size and organisation. This is a -privileged ioctl and one that eventually X itself should set. -<P> -The <b>VIDIOCSFBUF</b> ioctl sets the frame buffer parameters for a capture -card. If the card does not do direct writes to the frame buffer then this -ioctl will be unsupported. The <b>VIDIOCGFBUF</b> ioctl returns the -currently used parameters. The structure used in both cases is a -<b>struct video_buffer</b>. -<P> -<TABLE> -<TR><TD><b>void *base</b></TD><TD>Base physical address of the buffer</TD> -<TR><TD><b>int height</b></TD><TD>Height of the frame buffer</TD> -<TR><TD><b>int width</b></TD><TD>Width of the frame buffer</TD> -<TR><TD><b>int depth</b></TD><TD>Depth of the frame buffer</TD> -<TR><TD><b>int bytesperline</b></TD><TD>Number of bytes of memory between the start of two adjacent lines</TD> -</TABLE> -<P> -Note that these values reflect the physical layout of the frame buffer. -The visible area may be smaller. In fact under XFree86 this is commonly the -case. XFree86 DGA can provide the parameters required to set up this ioctl. -Setting the base address to NULL indicates there is no physical frame buffer -access. -<P> -<H3>Capture Windows</H3> -The capture area is described by a <b>struct video_window</b>. This defines -a capture area and the clipping information if relevant. The -<b>VIDIOCGWIN</b> ioctl recovers the current settings and the -<b>VIDIOCSWIN</b> sets new values. A successful call to <b>VIDIOCSWIN</b> -indicates that a suitable set of parameters have been chosen. They do not -indicate that exactly what was requested was granted. The program should -call <b>VIDIOCGWIN</b> to check if the nearest match was suitable. The -<b>struct video_window</b> contains the following fields. -<P> -<TABLE> -<TR><TD><b>x</b><TD>The X co-ordinate specified in X windows format.</TD> -<TR><TD><b>y</b><TD>The Y co-ordinate specified in X windows format.</TD> -<TR><TD><b>width</b><TD>The width of the image capture.</TD> -<TR><TD><b>height</b><TD>The height of the image capture.</TD> -<TR><TD><b>chromakey</b><TD>A host order RGB32 value for the chroma key.</TD> -<TR><TD><b>flags</b><TD>Additional capture flags.</TD> -<TR><TD><b>clips</b><TD>A list of clipping rectangles. <em>(Set only)</em></TD> -<TR><TD><b>clipcount</b><TD>The number of clipping rectangles. <em>(Set only)</em></TD> -</TABLE> -<P> -Clipping rectangles are passed as an array. Each clip consists of the following -fields available to the user. -<P> -<TABLE> -<TR><TD><b>x</b></TD><TD>X co-ordinate of rectangle to skip</TD> -<TR><TD><b>y</b></TD><TD>Y co-ordinate of rectangle to skip</TD> -<TR><TD><b>width</b></TD><TD>Width of rectangle to skip</TD> -<TR><TD><b>height</b></TD><TD>Height of rectangle to skip</TD> -</TABLE> -<P> -Merely setting the window does not enable capturing. Overlay capturing -(i.e. PCI-PCI transfer to the frame buffer of the video card) -is activated by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and -disabled by passing it a value of 0. -<P> -Some capture devices can capture a subfield of the image they actually see. -This is indicated when VIDEO_TYPE_SUBCAPTURE is defined. -The video_capture describes the time and special subfields to capture. -The video_capture structure contains the following fields. -<P> -<TABLE> -<TR><TD><b>x</b></TD><TD>X co-ordinate of source rectangle to grab</TD> -<TR><TD><b>y</b></TD><TD>Y co-ordinate of source rectangle to grab</TD> -<TR><TD><b>width</b></TD><TD>Width of source rectangle to grab</TD> -<TR><TD><b>height</b></TD><TD>Height of source rectangle to grab</TD> -<TR><TD><b>decimation</b></TD><TD>Decimation to apply</TD> -<TR><TD><b>flags</b></TD><TD>Flag settings for grabbing</TD> -</TABLE> -The available flags are -<P> -<TABLE> -<TR><TH>Name</TH><TH>Description</TH> -<TR><TD><b>VIDEO_CAPTURE_ODD</b><TD>Capture only odd frames</TD> -<TR><TD><b>VIDEO_CAPTURE_EVEN</b><TD>Capture only even frames</TD> -</TABLE> -<P> -<H3>Video Sources</H3> -Each video4linux video or audio device captures from one or more -source <b>channels</b>. Each channel can be queries with the -<b>VDIOCGCHAN</b> ioctl call. Before invoking this function the caller -must set the channel field to the channel that is being queried. On return -the <b>struct video_channel</b> is filled in with information about the -nature of the channel itself. -<P> -The <b>VIDIOCSCHAN</b> ioctl takes an integer argument and switches the -capture to this input. It is not defined whether parameters such as colour -settings or tuning are maintained across a channel switch. The caller should -maintain settings as desired for each channel. (This is reasonable as -different video inputs may have different properties). -<P> -The <b>struct video_channel</b> consists of the following -<P> -<TABLE> -<TR><TD><b>channel</b></TD><TD>The channel number</TD> -<TR><TD><b>name</b></TD><TD>The input name - preferably reflecting the label -on the card input itself</TD> -<TR><TD><b>tuners</b></TD><TD>Number of tuners for this input</TD> -<TR><TD><b>flags</b></TD><TD>Properties the tuner has</TD> -<TR><TD><b>type</b></TD><TD>Input type (if known)</TD> -<TR><TD><b>norm</b><TD>The norm for this channel</TD> -</TABLE> -<P> -The flags defined are -<P> -<TABLE> -<TR><TD><b>VIDEO_VC_TUNER</b><TD>Channel has tuners.</TD> -<TR><TD><b>VIDEO_VC_AUDIO</b><TD>Channel has audio.</TD> -<TR><TD><b>VIDEO_VC_NORM</b><TD>Channel has norm setting.</TD> -</TABLE> -<P> -The types defined are -<P> -<TABLE> -<TR><TD><b>VIDEO_TYPE_TV</b><TD>The input is a TV input.</TD> -<TR><TD><b>VIDEO_TYPE_CAMERA</b><TD>The input is a camera.</TD> -</TABLE> -<P> -<H3>Image Properties</H3> -The image properties of the picture can be queried with the <b>VIDIOCGPICT</b> -ioctl which fills in a <b>struct video_picture</b>. The <b>VIDIOCSPICT</b> -ioctl allows values to be changed. All values except for the palette type -are scaled between 0-65535. -<P> -The <b>struct video_picture</b> consists of the following fields -<P> -<TABLE> -<TR><TD><b>brightness</b><TD>Picture brightness</TD> -<TR><TD><b>hue</b><TD>Picture hue (colour only)</TD> -<TR><TD><b>colour</b><TD>Picture colour (colour only)</TD> -<TR><TD><b>contrast</b><TD>Picture contrast</TD> -<TR><TD><b>whiteness</b><TD>The whiteness (greyscale only)</TD> -<TR><TD><b>depth</b><TD>The capture depth (may need to match the frame buffer depth)</TD> -<TR><TD><b>palette</b><TD>Reports the palette that should be used for this image</TD> -</TABLE> -<P> -The following palettes are defined -<P> -<TABLE> -<TR><TD><b>VIDEO_PALETTE_GREY</b><TD>Linear intensity grey scale (255 is brightest).</TD> -<TR><TD><b>VIDEO_PALETTE_HI240</b><TD>The BT848 8bit colour cube.</TD> -<TR><TD><b>VIDEO_PALETTE_RGB565</b><TD>RGB565 packed into 16 bit words.</TD> -<TR><TD><b>VIDEO_PALETTE_RGB555</b><TD>RGV555 packed into 16 bit words, top bit undefined.</TD> -<TR><TD><b>VIDEO_PALETTE_RGB24</b><TD>RGB888 packed into 24bit words.</TD> -<TR><TD><b>VIDEO_PALETTE_RGB32</b><TD>RGB888 packed into the low 3 bytes of 32bit words. The top 8bits are undefined.</TD> -<TR><TD><b>VIDEO_PALETTE_YUV422</b><TD>Video style YUV422 - 8bits packed 4bits Y 2bits U 2bits V</TD> -<TR><TD><b>VIDEO_PALETTE_YUYV</b><TD>Describe me</TD> -<TR><TD><b>VIDEO_PALETTE_UYVY</b><TD>Describe me</TD> -<TR><TD><b>VIDEO_PALETTE_YUV420</b><TD>YUV420 capture</TD> -<TR><TD><b>VIDEO_PALETTE_YUV411</b><TD>YUV411 capture</TD> -<TR><TD><b>VIDEO_PALETTE_RAW</b><TD>RAW capture (BT848)</TD> -<TR><TD><b>VIDEO_PALETTE_YUV422P</b><TD>YUV 4:2:2 Planar</TD> -<TR><TD><b>VIDEO_PALETTE_YUV411P</b><TD>YUV 4:1:1 Planar</TD> -</TABLE> -<P> -<H3>Tuning</H3> -Each video input channel can have one or more tuners associated with it. Many -devices will not have tuners. TV cards and radio cards will have one or more -tuners attached. -<P> -Tuners are described by a <b>struct video_tuner</b> which can be obtained by -the <b>VIDIOCGTUNER</b> ioctl. Fill in the tuner number in the structure -then pass the structure to the ioctl to have the data filled in. The -tuner can be switched using <b>VIDIOCSTUNER</b> which takes an integer argument -giving the tuner to use. A struct tuner has the following fields -<P> -<TABLE> -<TR><TD><b>tuner</b><TD>Number of the tuner</TD> -<TR><TD><b>name</b><TD>Canonical name for this tuner (eg FM/AM/TV)</TD> -<TR><TD><b>rangelow</b><TD>Lowest tunable frequency</TD> -<TR><TD><b>rangehigh</b><TD>Highest tunable frequency</TD> -<TR><TD><b>flags</b><TD>Flags describing the tuner</TD> -<TR><TD><b>mode</b><TD>The video signal mode if relevant</TD> -<TR><TD><b>signal</b><TD>Signal strength if known - between 0-65535</TD> -</TABLE> -<P> -The following flags exist -<P> -<TABLE> -<TR><TD><b>VIDEO_TUNER_PAL</b><TD>PAL tuning is supported</TD> -<TR><TD><b>VIDEO_TUNER_NTSC</b><TD>NTSC tuning is supported</TD> -<TR><TD><b>VIDEO_TUNER_SECAM</b><TD>SECAM tuning is supported</TD> -<TR><TD><b>VIDEO_TUNER_LOW</b><TD>Frequency is in a lower range</TD> -<TR><TD><b>VIDEO_TUNER_NORM</b><TD>The norm for this tuner is settable</TD> -<TR><TD><b>VIDEO_TUNER_STEREO_ON</b><TD>The tuner is seeing stereo audio</TD> -<TR><TD><b>VIDEO_TUNER_RDS_ON</b><TD>The tuner is seeing a RDS datastream</TD> -<TR><TD><b>VIDEO_TUNER_MBS_ON</b><TD>The tuner is seeing a MBS datastream</TD> -</TABLE> -<P> -The following modes are defined -<P> -<TABLE> -<TR><TD><b>VIDEO_MODE_PAL</b><TD>The tuner is in PAL mode</TD> -<TR><TD><b>VIDEO_MODE_NTSC</b><TD>The tuner is in NTSC mode</TD> -<TR><TD><b>VIDEO_MODE_SECAM</b><TD>The tuner is in SECAM mode</TD> -<TR><TD><b>VIDEO_MODE_AUTO</b><TD>The tuner auto switches, or mode does not apply</TD> -</TABLE> -<P> -Tuning frequencies are an unsigned 32bit value in 1/16th MHz or if the -<b>VIDEO_TUNER_LOW</b> flag is set they are in 1/16th KHz. The current -frequency is obtained as an unsigned long via the <b>VIDIOCGFREQ</b> ioctl and -set by the <b>VIDIOCSFREQ</b> ioctl. -<P> -<H3>Audio</H3> -TV and Radio devices have one or more audio inputs that may be selected. -The audio properties are queried by passing a <b>struct video_audio</b> to <b>VIDIOCGAUDIO</b> ioctl. The -<b>VIDIOCSAUDIO</b> ioctl sets audio properties. -<P> -The structure contains the following fields -<P> -<TABLE> -<TR><TD><b>audio</b><TD>The channel number</TD> -<TR><TD><b>volume</b><TD>The volume level</TD> -<TR><TD><b>bass</b><TD>The bass level</TD> -<TR><TD><b>treble</b><TD>The treble level</TD> -<TR><TD><b>flags</b><TD>Flags describing the audio channel</TD> -<TR><TD><b>name</b><TD>Canonical name for the audio input</TD> -<TR><TD><b>mode</b><TD>The mode the audio input is in</TD> -<TR><TD><b>balance</b><TD>The left/right balance</TD> -<TR><TD><b>step</b><TD>Actual step used by the hardware</TD> -</TABLE> -<P> -The following flags are defined -<P> -<TABLE> -<TR><TD><b>VIDEO_AUDIO_MUTE</b><TD>The audio is muted</TD> -<TR><TD><b>VIDEO_AUDIO_MUTABLE</b><TD>Audio muting is supported</TD> -<TR><TD><b>VIDEO_AUDIO_VOLUME</b><TD>The volume is controllable</TD> -<TR><TD><b>VIDEO_AUDIO_BASS</b><TD>The bass is controllable</TD> -<TR><TD><b>VIDEO_AUDIO_TREBLE</b><TD>The treble is controllable</TD> -<TR><TD><b>VIDEO_AUDIO_BALANCE</b><TD>The balance is controllable</TD> -</TABLE> -<P> -The following decoding modes are defined -<P> -<TABLE> -<TR><TD><b>VIDEO_SOUND_MONO</b><TD>Mono signal</TD> -<TR><TD><b>VIDEO_SOUND_STEREO</b><TD>Stereo signal (NICAM for TV)</TD> -<TR><TD><b>VIDEO_SOUND_LANG1</b><TD>European TV alternate language 1</TD> -<TR><TD><b>VIDEO_SOUND_LANG2</b><TD>European TV alternate language 2</TD> -</TABLE> -<P> -<H3>Reading Images</H3> -Each call to the <b>read</b> syscall returns the next available image -from the device. It is up to the caller to set format and size (using -the VIDIOCSPICT and VIDIOCSWIN ioctls) and then to pass a suitable -size buffer and length to the function. Not all devices will support -read operations. -<P> -A second way to handle image capture is via the mmap interface if supported. -To use the mmap interface a user first sets the desired image size and depth -properties. Next the VIDIOCGMBUF ioctl is issued. This reports the size -of buffer to mmap and the offset within the buffer for each frame. The -number of frames supported is device dependent and may only be one. -<P> -The video_mbuf structure contains the following fields -<P> -<TABLE> -<TR><TD><b>size</b><TD>The number of bytes to map</TD> -<TR><TD><b>frames</b><TD>The number of frames</TD> -<TR><TD><b>offsets</b><TD>The offset of each frame</TD> -</TABLE> -<P> -Once the mmap has been made the VIDIOCMCAPTURE ioctl starts the -capture to a frame using the format and image size specified in the -video_mmap (which should match or be below the initial query size). -When the VIDIOCMCAPTURE ioctl returns the frame is <em>not</em> -captured yet, the driver just instructed the hardware to start the -capture. The application has to use the VIDIOCSYNC ioctl to wait -until the capture of a frame is finished. VIDIOCSYNC takes the frame -number you want to wait for as argument. -<p> -It is allowed to call VIDIOCMCAPTURE multiple times (with different -frame numbers in video_mmap->frame of course) and thus have multiple -outstanding capture requests. A simple way do to double-buffering -using this feature looks like this: -<pre> -/* setup everything */ -VIDIOCMCAPTURE(0) -while (whatever) { - VIDIOCMCAPTURE(1) - VIDIOCSYNC(0) - /* process frame 0 while the hardware captures frame 1 */ - VIDIOCMCAPTURE(0) - VIDIOCSYNC(1) - /* process frame 1 while the hardware captures frame 0 */ -} -</pre> -Note that you are <em>not</em> limited to only two frames. The API -allows up to 32 frames, the VIDIOCGMBUF ioctl returns the number of -frames the driver granted. Thus it is possible to build deeper queues -to avoid loosing frames on load peaks. -<p> -While capturing to memory the driver will make a "best effort" attempt -to capture to screen as well if requested. This normally means all -frames that "miss" memory mapped capture will go to the display. -<P> -A final ioctl exists to allow a device to obtain related devices if a -driver has multiple components (for example video0 may not be associated -with vbi0 which would cause an intercast display program to make a bad -mistake). The VIDIOCGUNIT ioctl reports the unit numbers of the associated -devices if any exist. The video_unit structure has the following fields. -<P> -<TABLE> -<TR><TD><b>video</b><TD>Video capture device</TD> -<TR><TD><b>vbi</b><TD>VBI capture device</TD> -<TR><TD><b>radio</b><TD>Radio device</TD> -<TR><TD><b>audio</b><TD>Audio mixer</TD> -<TR><TD><b>teletext</b><TD>Teletext device</TD> -</TABLE> -<P> -<H3>RDS Datastreams</H3> -For radio devices that support it, it is possible to receive Radio Data -System (RDS) data by means of a read() on the device. The data is packed in -groups of three, as follows: -<TABLE> -<TR><TD>First Octet</TD><TD>Least Significant Byte of RDS Block</TD></TR> -<TR><TD>Second Octet</TD><TD>Most Significant Byte of RDS Block -<TR><TD>Third Octet</TD><TD>Bit 7:</TD><TD>Error bit. Indicates that -an uncorrectable error occurred during reception of this block.</TD></TR> -<TR><TD> </TD><TD>Bit 6:</TD><TD>Corrected bit. Indicates that -an error was corrected for this data block.</TD></TR> -<TR><TD> </TD><TD>Bits 5-3:</TD><TD>Received Offset. Indicates the -offset received by the sync system.</TD></TR> -<TR><TD> </TD><TD>Bits 2-0:</TD><TD>Offset Name. Indicates the -offset applied to this data.</TD></TR> -</TABLE> -</BODY> -</HTML> +<TITLE>V4L API</TITLE> +<H1>Video For Linux APIs</H1> +<table border=0> +<tr> +<td> +<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html> +V4L original API</a> +</td><td> +Obsoleted by V4L2 API +</td></tr><tr><td> +<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API.html> +V4L2 API</a> +</td><td> +Should be used for new projects +</td></tr> +</table> diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 216f705..4377aa1 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -13,17 +13,17 @@ card=11 - Prolink PlayTV PVR card=12 - ASUS PVR-416 card=13 - MSI TV-@nywhere card=14 - KWorld/VStream XPert DVB-T -card=15 - DVICO FusionHDTV DVB-T1 +card=15 - DViCO FusionHDTV DVB-T1 card=16 - KWorld LTV883RF -card=17 - DViCO - FusionHDTV 3 Gold +card=17 - DViCO FusionHDTV 3 Gold-Q card=18 - Hauppauge Nova-T DVB-T card=19 - Conexant DVB-T reference design card=20 - Provideo PV259 -card=21 - DVICO FusionHDTV DVB-T Plus +card=21 - DViCO FusionHDTV DVB-T Plus card=22 - digitalnow DNTV Live! DVB-T card=23 - pcHDTV HD3000 HDTV card=24 - Hauppauge WinTV 28xxx (Roslyn) models card=25 - Digital-Logic MICROSPACE Entertainment Center (MEC) card=26 - IODATA GV/BCTV7E card=27 - PixelView PlayTV Ultra Pro (Stereo) -card=28 - DViCO - FusionHDTV 3 Gold-T +card=28 - DViCO FusionHDTV 3 Gold-T diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index d5ed95d..735e8ba 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -54,3 +54,9 @@ 55 -> LifeView FlyDVB-T DUO [5168:0306] 56 -> Avermedia AVerTV 307 [1461:a70a] 57 -> Avermedia AVerTV GO 007 FM [1461:f31f] + 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0370] + 59 -> Kworld/Tevion V-Stream Xpert TV PVR7134 + 60 -> Typhoon DVB-T Duo Digital/Analog Cardbus + 61 -> Philips TOUGH DVB-T reference design + 62 -> Compro VideoMate TV Gold+II + 63 -> Kworld Xpert TV PVR7134 diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index aeb8df8..e78020f 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -59,3 +59,6 @@ tuner=57 - Philips FQ1236A MK4 tuner=58 - Ymec TVision TVF-8531MF tuner=59 - Ymec TVision TVF-5533MF tuner=60 - Thomson DDT 7611 (ATSC/NTSC) +tuner=61 - Tena TNF9533-D/IF +tuner=62 - Philips TEA5767HN FM Radio +tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner diff --git a/Documentation/video4linux/README.saa7134 b/Documentation/video4linux/README.saa7134 index 1a446c6..1f788e4 100644 --- a/Documentation/video4linux/README.saa7134 +++ b/Documentation/video4linux/README.saa7134 @@ -57,6 +57,15 @@ Cards can use either of these two crystals (xtal): - 24.576MHz -> .audio_clock=0x200000 (xtal * .audio_clock = 51539600) +Some details about 30/34/35: + + - saa7130 - low-price chip, doesn't have mute, that is why all those + cards should have .mute field defined in their tuner structure. + + - saa7134 - usual chip + + - saa7133/35 - saa7135 is probably a marketing decision, since all those + chips identifies itself as 33 on pci. Credits ======= diff --git a/MAINTAINERS b/MAINTAINERS index 4db63de..19a9a1c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -512,11 +512,11 @@ W: http://linuxppc64.org S: Supported BTTV VIDEO4LINUX DRIVER -P: Gerd Knorr -M: kraxel@bytesex.org +P: Mauro Carvalho Chehab +M: mchehab@brturbo.com.br L: video4linux-list@redhat.com -W: http://bytesex.org/bttv/ -S: Orphan +W: http://linuxtv.org +S: Maintained BUSLOGIC SCSI DRIVER P: Leonard N. Zubkoff @@ -2625,10 +2625,11 @@ W: http://rio500.sourceforge.net S: Maintained VIDEO FOR LINUX -P: Gerd Knorr -M: kraxel@bytesex.org +P: Mauro Carvalho Chehab +M: mchehab@brturbo.com.br L: video4linux-list@redhat.com -S: Orphan +W: http://linuxtv.org +S: Maintained W1 DALLAS'S 1-WIRE BUS P: Evgeniy Polyakov @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 -SUBLEVEL = 12 -EXTRAVERSION = +SUBLEVEL = 13 +EXTRAVERSION =-rc1 NAME=Woozy Numbat # *DOCUMENTATION* diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c8d94dc..620f2ca 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -361,6 +361,11 @@ config NO_IDLE_HZ Alternatively, if you want dynamic tick automatically enabled during boot, pass "dyntick=enable" via the kernel command string. + Please note that dynamic tick may affect the accuracy of + timekeeping on some platforms depending on the implementation. + Currently at least OMAP platform is known to have accurate + timekeeping with dynamic tick. + config ARCH_DISCONTIGMEM_ENABLE bool default (ARCH_LH7A40X && !LH7A40X_CONTIGMEM) diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c index b668c48..cf9f46d 100644 --- a/arch/arm/mach-s3c2410/irq.c +++ b/arch/arm/mach-s3c2410/irq.c @@ -40,8 +40,11 @@ * 04-Nov-2004 Ben Dooks * Fix standard IRQ wake for EINT0..4 and RTC * - * 22-Feb-2004 Ben Dooks + * 22-Feb-2005 Ben Dooks * Fixed edge-triggering on ADC IRQ + * + * 28-Jun-2005 Ben Dooks + * Mark IRQ_LCD valid */ #include <linux/init.h> @@ -366,7 +369,6 @@ static struct irqchip s3c_irq_eint0t4 = { #define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0)) #define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0)) #define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0)) -#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0)) static inline void s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit, @@ -716,7 +718,6 @@ void __init s3c24xx_init_irq(void) case IRQ_UART0: case IRQ_UART1: case IRQ_UART2: - case IRQ_LCD: case IRQ_ADCPARENT: set_irq_chip(irqno, &s3c_irq_level_chip); set_irq_handler(irqno, do_level_IRQ); diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile index ba1a6e9..8ffb523 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 +oprofile-y := $(DRIVER_OBJS) init.o backtrace.o oprofile-$(CONFIG_CPU_XSCALE) += common.o op_model_xscale.o diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c new file mode 100644 index 0000000..ec58d3e --- /dev/null +++ b/arch/arm/oprofile/backtrace.c @@ -0,0 +1,144 @@ +/* + * Arm specific backtracing code for oprofile + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie <rpurdie@openedhand.com> + * + * Based on i386 oprofile backtrace code by John Levon, David Smith + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/oprofile.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <asm/ptrace.h> +#include <asm/uaccess.h> + + +/* + * The registers we're interested in are at the end of the variable + * length saved register structure. The fp points at the end of this + * structure so the address of this struct is: + * (struct frame_tail *)(xxx->fp)-1 + */ +struct frame_tail { + struct frame_tail *fp; + unsigned long sp; + unsigned long lr; +} __attribute__((packed)); + + +#ifdef CONFIG_FRAME_POINTER +static struct frame_tail* kernel_backtrace(struct frame_tail *tail) +{ + oprofile_add_trace(tail->lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= tail->fp) + return NULL; + + return tail->fp-1; +} +#endif + +static struct frame_tail* user_backtrace(struct frame_tail *tail) +{ + struct frame_tail buftail; + + /* hardware pte might not be valid due to dirty/accessed bit emulation + * so we use copy_from_user and benefit from exception fixups */ + if (copy_from_user(&buftail, tail, sizeof(struct frame_tail))) + return NULL; + + oprofile_add_trace(buftail.lr); + + /* frame pointers should strictly progress back up the stack + * (towards higher addresses) */ + if (tail >= buftail.fp) + return NULL; + + return buftail.fp-1; +} + +/* Compare two addresses and see if they're on the same page */ +#define CMP_ADDR_EQUAL(x,y,offset) ((((unsigned long) x) >> PAGE_SHIFT) \ + == ((((unsigned long) y) + offset) >> PAGE_SHIFT)) + +/* check that the page(s) containing the frame tail are present */ +static int pages_present(struct frame_tail *tail) +{ + struct mm_struct * mm = current->mm; + + if (!check_user_page_readable(mm, (unsigned long)tail)) + return 0; + + if (CMP_ADDR_EQUAL(tail, tail, 8)) + return 1; + + if (!check_user_page_readable(mm, ((unsigned long)tail) + 8)) + return 0; + + return 1; +} + +/* + * | | /\ Higher addresses + * | | + * --------------- stack base (address of current_thread_info) + * | thread info | + * . . + * | stack | + * --------------- saved regs->ARM_fp value if valid (frame_tail address) + * . . + * --------------- struct pt_regs stored on stack (struct pt_regs *) + * | | + * . . + * | | + * --------------- %esp + * | | + * | | \/ Lower addresses + * + * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values + */ +static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs) +{ + unsigned long tailaddr = (unsigned long)tail; + unsigned long stack = (unsigned long)regs; + unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE; + + return (tailaddr > stack) && (tailaddr < stack_base); +} + +void arm_backtrace(struct pt_regs const *regs, unsigned int depth) +{ + struct frame_tail *tail; + unsigned long last_address = 0; + + tail = ((struct frame_tail *) regs->ARM_fp) - 1; + + if (!user_mode(regs)) { + +#ifdef CONFIG_FRAME_POINTER + while (depth-- && tail && valid_kernel_stack(tail, regs)) { + tail = kernel_backtrace(tail); + } +#endif + return; + } + + while (depth-- && tail && !((unsigned long) tail & 3)) { + if ((!CMP_ADDR_EQUAL(last_address, tail, 0) + || !CMP_ADDR_EQUAL(last_address, tail, 8)) + && !pages_present(tail)) + return; + last_address = (unsigned long) tail; + tail = user_backtrace(tail); + } +} + diff --git a/arch/arm/oprofile/init.c b/arch/arm/oprofile/init.c index cce3d30..d315a3a 100644 --- a/arch/arm/oprofile/init.c +++ b/arch/arm/oprofile/init.c @@ -20,6 +20,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ret = pmu_init(ops, &op_xscale_spec); #endif + ops->backtrace = arm_backtrace; + return ret; } diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h index 2d4caf4..2148d07 100644 --- a/arch/arm/oprofile/op_arm_model.h +++ b/arch/arm/oprofile/op_arm_model.h @@ -24,6 +24,8 @@ struct op_arm_model_spec { extern struct op_arm_model_spec op_xscale_spec; #endif +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); #endif /* OP_ARM_MODEL_H */ diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c index 4a17956..6835f6d 100644 --- a/arch/i386/boot/tools/build.c +++ b/arch/i386/boot/tools/build.c @@ -70,7 +70,8 @@ void usage(void) int main(int argc, char ** argv) { - unsigned int i, c, sz, setup_sectors; + unsigned int i, sz, setup_sectors; + int c; u32 sys_size; byte major_root, minor_root; struct stat sb; diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 9f63ae0..b7808a8 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -159,9 +159,15 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) #endif #ifdef CONFIG_PCI_MMCONFIG -static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ +struct acpi_table_mcfg_config *pci_mmcfg_config; +int pci_mmcfg_config_num; + +int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) { struct acpi_table_mcfg *mcfg; + unsigned long i; + int config_size; if (!phys_addr || !size) return -EINVAL; @@ -172,18 +178,38 @@ static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) return -ENODEV; } - if (mcfg->base_reserved) { - printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); + /* how many config structures do we have */ + pci_mmcfg_config_num = 0; + i = size - sizeof(struct acpi_table_mcfg); + while (i >= sizeof(struct acpi_table_mcfg_config)) { + ++pci_mmcfg_config_num; + i -= sizeof(struct acpi_table_mcfg_config); + }; + if (pci_mmcfg_config_num == 0) { + printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); return -ENODEV; } - pci_mmcfg_base_addr = mcfg->base_address; + config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config); + pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL); + if (!pci_mmcfg_config) { + printk(KERN_WARNING PREFIX + "No memory for MCFG config tables\n"); + return -ENOMEM; + } + + memcpy(pci_mmcfg_config, &mcfg->config, config_size); + for (i = 0; i < pci_mmcfg_config_num; ++i) { + if (mcfg->config[i].base_reserved) { + printk(KERN_ERR PREFIX + "MMCONFIG not in low 4GB of memory\n"); + return -ENODEV; + } + } return 0; } -#else -#define acpi_parse_mcfg NULL -#endif /* !CONFIG_PCI_MMCONFIG */ +#endif /* CONFIG_PCI_MMCONFIG */ #ifdef CONFIG_X86_LOCAL_APIC static int __init @@ -507,6 +533,22 @@ acpi_unmap_lsapic(int cpu) EXPORT_SYMBOL(acpi_unmap_lsapic); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ +int +acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) +{ + /* TBD */ + return -EINVAL; +} +EXPORT_SYMBOL(acpi_register_ioapic); + +int +acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base) +{ + /* TBD */ + return -EINVAL; +} +EXPORT_SYMBOL(acpi_unregister_ioapic); + static unsigned long __init acpi_scan_rsdp ( unsigned long start, @@ -1123,7 +1165,6 @@ int __init acpi_boot_init(void) acpi_process_madt(); acpi_table_parse(ACPI_HPET, acpi_parse_hpet); - acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); return 0; } diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index 720975e..8732526 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c @@ -25,7 +25,8 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | int pci_routeirq; int pcibios_last_bus = -1; -struct pci_bus *pci_root_bus = NULL; +unsigned long pirq_table_addr; +struct pci_bus *pci_root_bus; struct pci_raw_ops *raw_pci_ops; static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) @@ -133,7 +134,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) printk("PCI: Probing PCI hardware (bus %02x)\n", busnum); - return pci_scan_bus(busnum, &pci_root_ops, NULL); + return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL); } extern u8 pci_cache_line_size; @@ -188,6 +189,9 @@ char * __devinit pcibios_setup(char *str) } else if (!strcmp(str, "biosirq")) { pci_probe |= PCI_BIOS_IRQ_SCAN; return NULL; + } else if (!strncmp(str, "pirqaddr=", 9)) { + pirq_table_addr = simple_strtoul(str+9, NULL, 0); + return NULL; } #endif #ifdef CONFIG_PCI_DIRECT diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 83458f8..78ca1ec 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -58,6 +58,35 @@ struct irq_router_handler { int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; /* + * Check passed address for the PCI IRQ Routing Table signature + * and perform checksum verification. + */ + +static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr) +{ + struct irq_routing_table *rt; + int i; + u8 sum; + + rt = (struct irq_routing_table *) addr; + if (rt->signature != PIRQ_SIGNATURE || + rt->version != PIRQ_VERSION || + rt->size % 16 || + rt->size < sizeof(struct irq_routing_table)) + return NULL; + sum = 0; + for (i=0; i < rt->size; i++) + sum += addr[i]; + if (!sum) { + DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt); + return rt; + } + return NULL; +} + + + +/* * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. */ @@ -65,23 +94,17 @@ static struct irq_routing_table * __init pirq_find_routing_table(void) { u8 *addr; struct irq_routing_table *rt; - int i; - u8 sum; + if (pirq_table_addr) { + rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr)); + if (rt) + return rt; + printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n"); + } for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { - rt = (struct irq_routing_table *) addr; - if (rt->signature != PIRQ_SIGNATURE || - rt->version != PIRQ_VERSION || - rt->size % 16 || - rt->size < sizeof(struct irq_routing_table)) - continue; - sum = 0; - for(i=0; i<rt->size; i++) - sum += addr[i]; - if (!sum) { - DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt); + rt = pirq_check_routing_table(addr); + if (rt) return rt; - } } return NULL; } diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c index 1492e37..149a958 100644 --- a/arch/i386/pci/legacy.c +++ b/arch/i386/pci/legacy.c @@ -45,6 +45,8 @@ static int __init pci_legacy_init(void) printk("PCI: Probing PCI hardware\n"); pci_root_bus = pcibios_scan_root(0); + if (pci_root_bus) + pci_bus_add_devices(pci_root_bus); pcibios_fixup_peer_bridges(); diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 021a50a..60f0e7a 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -11,11 +11,9 @@ #include <linux/pci.h> #include <linux/init.h> +#include <linux/acpi.h> #include "pci.h" -/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ -u32 pci_mmcfg_base_addr; - #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) /* The base address of the last MMCONFIG device accessed */ @@ -24,10 +22,31 @@ static u32 mmcfg_last_accessed_device; /* * Functions for accessing PCI configuration space with MMCONFIG accesses */ +static u32 get_base_addr(unsigned int seg, int bus) +{ + int cfg_num = -1; + struct acpi_table_mcfg_config *cfg; + + while (1) { + ++cfg_num; + if (cfg_num >= pci_mmcfg_config_num) { + /* something bad is going on, no cfg table is found. */ + /* so we fall back to the old way we used to do this */ + /* and just rely on the first entry to be correct. */ + return pci_mmcfg_config[0].base_address; + } + cfg = &pci_mmcfg_config[cfg_num]; + if (cfg->pci_segment_group_number != seg) + continue; + if ((cfg->start_bus_number <= bus) && + (cfg->end_bus_number >= bus)) + return cfg->base_address; + } +} -static inline void pci_exp_set_dev_base(int bus, int devfn) +static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn) { - u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12); + u32 dev_base = get_base_addr(seg, bus) | (bus << 20) | (devfn << 12); if (dev_base != mmcfg_last_accessed_device) { mmcfg_last_accessed_device = dev_base; set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); @@ -44,7 +63,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, spin_lock_irqsave(&pci_config_lock, flags); - pci_exp_set_dev_base(bus, devfn); + pci_exp_set_dev_base(seg, bus, devfn); switch (len) { case 1: @@ -73,7 +92,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, spin_lock_irqsave(&pci_config_lock, flags); - pci_exp_set_dev_base(bus, devfn); + pci_exp_set_dev_base(seg, bus, devfn); switch (len) { case 1: @@ -101,7 +120,11 @@ static int __init pci_mmcfg_init(void) { if ((pci_probe & PCI_PROBE_MMCONF) == 0) goto out; - if (!pci_mmcfg_base_addr) + + acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + if ((pci_mmcfg_config_num == 0) || + (pci_mmcfg_config == NULL) || + (pci_mmcfg_config[0].base_address == 0)) goto out; /* Kludge for now. Don't use mmconfig on AMD systems because diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c index 9e36954..adbe17a 100644 --- a/arch/i386/pci/numa.c +++ b/arch/i386/pci/numa.c @@ -115,6 +115,8 @@ static int __init pci_numa_init(void) return 0; pci_root_bus = pcibios_scan_root(0); + if (pci_root_bus) + pci_bus_add_devices(pci_root_bus); if (num_online_nodes() > 1) for_each_online_node(quad) { if (quad == 0) diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index a8fc80c..a80f0f5 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h @@ -27,6 +27,7 @@ #define PCI_ASSIGN_ALL_BUSSES 0x4000 extern unsigned int pci_probe; +extern unsigned long pirq_table_addr; /* pci-i386.c */ diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 72dfd9e..cda06f8 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end) if (BAD_MADT_ENTRY(iosapic, end)) return -EINVAL; - iosapic_init(iosapic->address, iosapic->global_irq_base); - - return 0; + return iosapic_init(iosapic->address, iosapic->global_irq_base); } @@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic); #ifdef CONFIG_ACPI_NUMA -acpi_status __init +acpi_status __devinit acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; @@ -825,4 +823,28 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) return AE_OK; } #endif /* CONFIG_NUMA */ + +int +acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base) +{ + int err; + + if ((err = iosapic_init(phys_addr, gsi_base))) + return err; + +#if CONFIG_ACPI_NUMA + acpi_map_iosapic(handle, 0, NULL, NULL); +#endif /* CONFIG_ACPI_NUMA */ + + return 0; +} +EXPORT_SYMBOL(acpi_register_ioapic); + +int +acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base) +{ + return iosapic_remove(gsi_base); +} +EXPORT_SYMBOL(acpi_unregister_ioapic); + #endif /* CONFIG_ACPI_BOOT */ diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 88b0143..c170be0 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -129,14 +129,13 @@ static struct iosapic { char __iomem *addr; /* base address of IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned short num_rte; /* number of RTE in this IOSAPIC */ + int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ #ifdef CONFIG_NUMA unsigned short node; /* numa node association via pxm */ #endif } iosapic_lists[NR_IOSAPICS]; -static int num_iosapic; - -static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ +static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ static int iosapic_kmalloc_ok; static LIST_HEAD(free_rte_list); @@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi) { int i; - for (i = 0; i < num_iosapic; i++) { + for (i = 0; i < NR_IOSAPICS; i++) { if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) return i; } @@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, rte->refcnt++; list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); iosapic_intr_info[vector].count++; + iosapic_lists[index].rtes_inuse++; } else if (vector_is_shared(vector)) { struct iosapic_intr_info *info = &iosapic_intr_info[vector]; @@ -778,7 +778,7 @@ void iosapic_unregister_intr (unsigned int gsi) { unsigned long flags; - int irq, vector; + int irq, vector, index; irq_desc_t *idesc; u32 low32; unsigned long trigger, polarity; @@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi) list_del(&rte->rte_list); iosapic_intr_info[vector].count--; iosapic_free_rte(rte); + index = find_iosapic(gsi); + iosapic_lists[index].rtes_inuse--; + WARN_ON(iosapic_lists[index].rtes_inuse < 0); trigger = iosapic_intr_info[vector].trigger; polarity = iosapic_intr_info[vector].polarity; @@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat) } } -void __init +static inline int +iosapic_alloc (void) +{ + int index; + + for (index = 0; index < NR_IOSAPICS; index++) + if (!iosapic_lists[index].addr) + return index; + + printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__); + return -1; +} + +static inline void +iosapic_free (int index) +{ + memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0])); +} + +static inline int +iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) +{ + int index; + unsigned int gsi_end, base, end; + + /* check gsi range */ + gsi_end = gsi_base + ((ver >> 16) & 0xff); + for (index = 0; index < NR_IOSAPICS; index++) { + if (!iosapic_lists[index].addr) + continue; + + base = iosapic_lists[index].gsi_base; + end = base + iosapic_lists[index].num_rte - 1; + + if (gsi_base < base && gsi_end < base) + continue;/* OK */ + + if (gsi_base > end && gsi_end > end) + continue; /* OK */ + + return -EBUSY; + } + return 0; +} + +int __devinit iosapic_init (unsigned long phys_addr, unsigned int gsi_base) { - int num_rte; + int num_rte, err, index; unsigned int isa_irq, ver; char __iomem *addr; + unsigned long flags; + + spin_lock_irqsave(&iosapic_lock, flags); + { + addr = ioremap(phys_addr, 0); + ver = iosapic_version(addr); - addr = ioremap(phys_addr, 0); - ver = iosapic_version(addr); + if ((err = iosapic_check_gsi_range(gsi_base, ver))) { + iounmap(addr); + spin_unlock_irqrestore(&iosapic_lock, flags); + return err; + } - /* - * The MAX_REDIR register holds the highest input pin - * number (starting from 0). - * We add 1 so that we can use it for number of pins (= RTEs) - */ - num_rte = ((ver >> 16) & 0xff) + 1; + /* + * The MAX_REDIR register holds the highest input pin + * number (starting from 0). + * We add 1 so that we can use it for number of pins (= RTEs) + */ + num_rte = ((ver >> 16) & 0xff) + 1; - iosapic_lists[num_iosapic].addr = addr; - iosapic_lists[num_iosapic].gsi_base = gsi_base; - iosapic_lists[num_iosapic].num_rte = num_rte; + index = iosapic_alloc(); + iosapic_lists[index].addr = addr; + iosapic_lists[index].gsi_base = gsi_base; + iosapic_lists[index].num_rte = num_rte; #ifdef CONFIG_NUMA - iosapic_lists[num_iosapic].node = MAX_NUMNODES; + iosapic_lists[index].node = MAX_NUMNODES; #endif - num_iosapic++; + } + spin_unlock_irqrestore(&iosapic_lock, flags); if ((gsi_base == 0) && pcat_compat) { /* @@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) for (isa_irq = 0; isa_irq < 16; ++isa_irq) iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); } + return 0; +} + +#ifdef CONFIG_HOTPLUG +int +iosapic_remove (unsigned int gsi_base) +{ + int index, err = 0; + unsigned long flags; + + spin_lock_irqsave(&iosapic_lock, flags); + { + index = find_iosapic(gsi_base); + if (index < 0) { + printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n", + __FUNCTION__, gsi_base); + goto out; + } + + if (iosapic_lists[index].rtes_inuse) { + err = -EBUSY; + printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", + __FUNCTION__, gsi_base); + goto out; + } + + iounmap(iosapic_lists[index].addr); + iosapic_free(index); + } + out: + spin_unlock_irqrestore(&iosapic_lock, flags); + return err; } +#endif /* CONFIG_HOTPLUG */ #ifdef CONFIG_NUMA -void __init +void __devinit map_iosapic_to_node(unsigned int gsi_base, int node) { int index; diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index e3fc4ed..720a861 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c @@ -312,7 +312,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus) acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window, &info); - pbus = pci_scan_bus(bus, &pci_root_ops, controller); + pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller); if (pbus) pcibios_setup_root_windows(pbus, controller); @@ -373,6 +373,25 @@ void pcibios_bus_to_resource(struct pci_dev *dev, res->end = region->end + offset; } +static int __devinit is_valid_resource(struct pci_dev *dev, int idx) +{ + unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; + struct resource *devr = &dev->resource[idx]; + + if (!dev->bus) + return 0; + for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) { + struct resource *busr = dev->bus->resource[i]; + + if (!busr || ((busr->flags ^ devr->flags) & type_mask)) + continue; + if ((devr->start) && (devr->start >= busr->start) && + (devr->end <= busr->end)) + return 1; + } + return 0; +} + static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) { struct pci_bus_region region; @@ -386,7 +405,8 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) region.start = dev->resource[i].start; region.end = dev->resource[i].end; pcibios_bus_to_resource(dev, &dev->resource[i], ®ion); - pci_claim_resource(dev, i); + if ((is_valid_resource(dev, i))) + pci_claim_resource(dev, i); } } @@ -398,6 +418,10 @@ pcibios_fixup_bus (struct pci_bus *b) { struct pci_dev *dev; + if (b->self) { + pci_read_bridge_bases(b); + pcibios_fixup_device_resources(b->self); + } list_for_each_entry(dev, &b->devices, bus_list) pcibios_fixup_device_resources(dev); @@ -418,18 +442,24 @@ pcibios_enable_resources (struct pci_dev *dev, int mask) u16 cmd, old_cmd; int idx; struct resource *r; + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; if (!dev) return -EINVAL; pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; - for (idx=0; idx<6; idx++) { + for (idx=0; idx<PCI_NUM_RESOURCES; idx++) { /* Only set up the desired resources. */ if (!(mask & (1 << idx))) continue; r = &dev->resource[idx]; + if (!(r->flags & type_mask)) + continue; + if ((idx == PCI_ROM_RESOURCE) && + (!(r->flags & IORESOURCE_ROM_ENABLE))) + continue; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", @@ -441,8 +471,6 @@ pcibios_enable_resources (struct pci_dev *dev, int mask) if (r->flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } - if (dev->resource[PCI_ROM_RESOURCE].start) - cmd |= PCI_COMMAND_MEMORY; if (cmd != old_cmd) { printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd); diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 6d7b92d..70cfb6f 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -1495,7 +1495,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, *offset += hose->pci_mem_offset; res_bit = IORESOURCE_MEM; } else { - io_offset = (unsigned long)hose->io_base_virt; + io_offset = hose->io_base_virt - ___IO_BASE; *offset += io_offset; res_bit = IORESOURCE_IO; } @@ -1522,7 +1522,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, /* found it! construct the final physical address */ if (mmap_state == pci_mmap_io) - *offset += hose->io_base_phys - _IO_BASE; + *offset += hose->io_base_phys - io_offset; return rp; } @@ -1739,6 +1739,23 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) return result; } +void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, + u64 *start, u64 *end) +{ + struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); + unsigned long offset = 0; + + if (hose == NULL) + return; + + if (rsrc->flags & IORESOURCE_IO) + offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys; + + *start = rsrc->start + offset; + *end = rsrc->end + offset; +} + void __init pci_init_resource(struct resource *res, unsigned long start, unsigned long end, int flags, char *name) diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index 3defc8c..ffe3006 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c @@ -245,7 +245,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq) spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 580676f..ae6f579 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -351,7 +351,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, *offset += hose->pci_mem_offset; res_bit = IORESOURCE_MEM; } else { - io_offset = (unsigned long)hose->io_base_virt; + io_offset = (unsigned long)hose->io_base_virt - pci_io_base; *offset += io_offset; res_bit = IORESOURCE_IO; } @@ -378,7 +378,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, /* found it! construct the final physical address */ if (mmap_state == pci_mmap_io) - *offset += hose->io_base_phys - io_offset; + *offset += hose->io_base_phys - io_offset; return rp; } @@ -944,4 +944,22 @@ int pci_read_irq_line(struct pci_dev *pci_dev) } EXPORT_SYMBOL(pci_read_irq_line); +void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, + u64 *start, u64 *end) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + unsigned long offset = 0; + + if (hose == NULL) + return; + + if (rsrc->flags & IORESOURCE_IO) + offset = pci_io_base - (unsigned long)hose->io_base_virt + + hose->io_base_phys; + + *start = rsrc->start + offset; + *end = rsrc->end + offset; +} + #endif /* CONFIG_PPC_MULTIPLATFORM */ diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 262e13d..7a117ef 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -270,66 +270,10 @@ endmenu source "drivers/Kconfig" -config PRINTER - tristate "Parallel printer support" - depends on PARPORT - ---help--- - If you intend to attach a printer to the parallel port of your Linux - box (as opposed to using a serial printer; if the connector at the - printer has 9 or 25 holes ["female"], then it's serial), say Y. - Also read the Printing-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - It is possible to share one parallel port among several devices - (e.g. printer and ZIP drive) and it is safe to compile the - corresponding drivers into the kernel. If you want to compile this - driver as a module however, choose M here and read - <file:Documentation/parport.txt>. The module will be called lp. - - If you have several parallel ports, you can specify which ports to - use with the "lp" kernel command line option. (Try "man bootparam" - or see the documentation of your boot loader (silo) about how to pass - options to the kernel at boot time.) The syntax of the "lp" command - line option can be found in <file:drivers/char/lp.c>. - - If you have more than 8 printers, you need to increase the LP_NO - macro in lp.c and the PARPORT_MAX macro in parport.h. - -source "mm/Kconfig" - -endmenu - -source "drivers/base/Kconfig" - -source "drivers/video/Kconfig" - -source "drivers/mtd/Kconfig" - -source "drivers/serial/Kconfig" - if !SUN4 source "drivers/sbus/char/Kconfig" endif -source "drivers/block/Kconfig" - -# Don't frighten a common SBus user -if PCI - -source "drivers/ide/Kconfig" - -endif - -source "drivers/isdn/Kconfig" - -source "drivers/scsi/Kconfig" - -source "drivers/fc4/Kconfig" - -source "drivers/md/Kconfig" - -source "net/Kconfig" - # This one must be before the filesystem configs. -DaveM menu "Unix98 PTY support" diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index b693c23..657e88a 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c @@ -7,25 +7,50 @@ #include <linux/pci.h> #include <linux/init.h> +#include <linux/acpi.h> #include "pci.h" #define MMCONFIG_APER_SIZE (256*1024*1024) -/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ -u32 pci_mmcfg_base_addr; - /* Static virtual mapping of the MMCONFIG aperture */ -char *pci_mmcfg_virt; +struct mmcfg_virt { + struct acpi_table_mcfg_config *cfg; + char *virt; +}; +static struct mmcfg_virt *pci_mmcfg_virt; -static inline char *pci_dev_base(unsigned int bus, unsigned int devfn) +static char *get_virt(unsigned int seg, int bus) { - return pci_mmcfg_virt + ((bus << 20) | (devfn << 12)); + int cfg_num = -1; + struct acpi_table_mcfg_config *cfg; + + while (1) { + ++cfg_num; + if (cfg_num >= pci_mmcfg_config_num) { + /* something bad is going on, no cfg table is found. */ + /* so we fall back to the old way we used to do this */ + /* and just rely on the first entry to be correct. */ + return pci_mmcfg_virt[0].virt; + } + cfg = pci_mmcfg_virt[cfg_num].cfg; + if (cfg->pci_segment_group_number != seg) + continue; + if ((cfg->start_bus_number <= bus) && + (cfg->end_bus_number >= bus)) + return pci_mmcfg_virt[cfg_num].virt; + } +} + +static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) +{ + + return get_virt(seg, bus) + ((bus << 20) | (devfn << 12)); } static int pci_mmcfg_read(unsigned int seg, unsigned int bus, unsigned int devfn, int reg, int len, u32 *value) { - char *addr = pci_dev_base(bus, devfn); + char *addr = pci_dev_base(seg, bus, devfn); if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) return -EINVAL; @@ -48,7 +73,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, static int pci_mmcfg_write(unsigned int seg, unsigned int bus, unsigned int devfn, int reg, int len, u32 value) { - char *addr = pci_dev_base(bus,devfn); + char *addr = pci_dev_base(seg, bus, devfn); if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) return -EINVAL; @@ -75,9 +100,15 @@ static struct pci_raw_ops pci_mmcfg = { static int __init pci_mmcfg_init(void) { + int i; + if ((pci_probe & PCI_PROBE_MMCONF) == 0) return 0; - if (!pci_mmcfg_base_addr) + + acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + if ((pci_mmcfg_config_num == 0) || + (pci_mmcfg_config == NULL) || + (pci_mmcfg_config[0].base_address == 0)) return 0; /* Kludge for now. Don't use mmconfig on AMD systems because @@ -88,13 +119,22 @@ static int __init pci_mmcfg_init(void) return 0; /* RED-PEN i386 doesn't do _nocache right now */ - pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE); - if (!pci_mmcfg_virt) { - printk("PCI: Cannot map mmconfig aperture\n"); + pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); + if (pci_mmcfg_virt == NULL) { + printk("PCI: Can not allocate memory for mmconfig structures\n"); return 0; - } + } + for (i = 0; i < pci_mmcfg_config_num; ++i) { + pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; + pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE); + if (!pci_mmcfg_virt[i].virt) { + printk("PCI: Cannot map mmconfig aperture for segment %d\n", + pci_mmcfg_config[i].pci_segment_group_number); + return 0; + } + printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address); + } - printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_base_addr); raw_pci_ops = &pci_mmcfg; pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 5a0adbf..97013dd 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle) return_VALUE(-ENODEV); } - result = acpi_bus_scan(*device); + result = acpi_bus_start(*device); return_VALUE(result); } diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 5d19b39..5148f3c 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -61,15 +61,14 @@ acpi_pci_data_handler ( /** - * acpi_os_get_pci_id + * acpi_get_pci_id * ------------------ * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem) * to resolve PCI information for ACPI-PCI devices defined in the namespace. * This typically occurs when resolving PCI operation region information. */ -#ifdef ACPI_FUTURE_USAGE acpi_status -acpi_os_get_pci_id ( +acpi_get_pci_id ( acpi_handle handle, struct acpi_pci_id *id) { @@ -78,7 +77,7 @@ acpi_os_get_pci_id ( struct acpi_device *device = NULL; struct acpi_pci_data *data = NULL; - ACPI_FUNCTION_TRACE("acpi_os_get_pci_id"); + ACPI_FUNCTION_TRACE("acpi_get_pci_id"); if (!id) return_ACPI_STATUS(AE_BAD_PARAMETER); @@ -92,7 +91,7 @@ acpi_os_get_pci_id ( } status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data); - if (ACPI_FAILURE(status) || !data || !data->dev) { + if (ACPI_FAILURE(status) || !data) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid ACPI-PCI context for device %s\n", acpi_device_bid(device))); @@ -115,7 +114,7 @@ acpi_os_get_pci_id ( return_ACPI_STATUS(AE_OK); } -#endif /* ACPI_FUTURE_USAGE */ +EXPORT_SYMBOL(acpi_get_pci_id); int @@ -129,6 +128,8 @@ acpi_pci_bind ( char *pathname = NULL; struct acpi_buffer buffer = {0, NULL}; acpi_handle handle = NULL; + struct pci_dev *dev; + struct pci_bus *bus; ACPI_FUNCTION_TRACE("acpi_pci_bind"); @@ -193,8 +194,20 @@ acpi_pci_bind ( * Locate matching device in PCI namespace. If it doesn't exist * this typically means that the device isn't currently inserted * (e.g. docking station, port replicator, etc.). + * We cannot simply search the global pci device list, since + * PCI devices are added to the global pci list when the root + * bridge start ops are run, which may not have happened yet. */ - data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function)); + bus = pci_find_bus(data->id.segment, data->id.bus); + if (bus) { + list_for_each_entry(dev, &bus->devices, bus_list) { + if (dev->devfn == PCI_DEVFN(data->id.device, + data->id.function)) { + data->dev = dev; + break; + } + } + } if (!data->dev) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %02x:%02x:%02x.%02x not present in PCI namespace\n", diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 7e6b8e3..5d2f77f 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -46,6 +46,7 @@ ACPI_MODULE_NAME ("pci_root") static int acpi_pci_root_add (struct acpi_device *device); static int acpi_pci_root_remove (struct acpi_device *device, int type); +static int acpi_pci_root_start (struct acpi_device *device); static struct acpi_driver acpi_pci_root_driver = { .name = ACPI_PCI_ROOT_DRIVER_NAME, @@ -54,6 +55,7 @@ static struct acpi_driver acpi_pci_root_driver = { .ops = { .add = acpi_pci_root_add, .remove = acpi_pci_root_remove, + .start = acpi_pci_root_start, }, }; @@ -169,6 +171,7 @@ acpi_pci_root_add ( if (!root) return_VALUE(-ENOMEM); memset(root, 0, sizeof(struct acpi_pci_root)); + INIT_LIST_HEAD(&root->node); root->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); @@ -298,12 +301,31 @@ acpi_pci_root_add ( root->id.bus); end: - if (result) + if (result) { + if (!list_empty(&root->node)) + list_del(&root->node); kfree(root); + } return_VALUE(result); } +static int +acpi_pci_root_start ( + struct acpi_device *device) +{ + struct acpi_pci_root *root; + + ACPI_FUNCTION_TRACE("acpi_pci_root_start"); + + list_for_each_entry(root, &acpi_pci_roots, node) { + if (root->handle == device->handle) { + pci_bus_add_devices(root->bus); + return_VALUE(0); + } + } + return_VALUE(-ENODEV); +} static int acpi_pci_root_remove ( diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index f477874..76156ac 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -723,7 +723,7 @@ int acpi_processor_device_add( return_VALUE(-ENODEV); } - acpi_bus_scan(*device); + acpi_bus_start(*device); pr = acpi_driver_data(*device); if (!pr) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e858855..337d49b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -553,20 +553,29 @@ acpi_bus_driver_init ( * upon possible configuration and currently allocated resources. */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); + return_VALUE(0); +} + +int +acpi_start_single_object ( + struct acpi_device *device) +{ + int result = 0; + struct acpi_driver *driver; + + ACPI_FUNCTION_TRACE("acpi_start_single_object"); + + if (!(driver = device->driver)) + return_VALUE(0); + if (driver->ops.start) { result = driver->ops.start(device); if (result && driver->ops.remove) driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); - return_VALUE(result); } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); - - if (driver->ops.scan) { - driver->ops.scan(device); - } - - return_VALUE(0); + return_VALUE(result); } static int acpi_driver_attach(struct acpi_driver * drv) @@ -586,6 +595,7 @@ static int acpi_driver_attach(struct acpi_driver * drv) if (!acpi_bus_match(dev, drv)) { if (!acpi_bus_driver_init(dev, drv)) { + acpi_start_single_object(dev); atomic_inc(&drv->references); count++; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", @@ -1009,8 +1019,8 @@ acpi_bus_remove ( } -int -acpi_bus_add ( +static int +acpi_add_single_object ( struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, @@ -1019,7 +1029,7 @@ acpi_bus_add ( int result = 0; struct acpi_device *device = NULL; - ACPI_FUNCTION_TRACE("acpi_bus_add"); + ACPI_FUNCTION_TRACE("acpi_add_single_object"); if (!child) return_VALUE(-EINVAL); @@ -1140,7 +1150,7 @@ acpi_bus_add ( * * TBD: Assumes LDM provides driver hot-plug capability. */ - acpi_bus_find_driver(device); + result = acpi_bus_find_driver(device); end: if (!result) @@ -1153,10 +1163,10 @@ end: return_VALUE(result); } -EXPORT_SYMBOL(acpi_bus_add); -int acpi_bus_scan (struct acpi_device *start) +static int acpi_bus_scan (struct acpi_device *start, + struct acpi_bus_ops *ops) { acpi_status status = AE_OK; struct acpi_device *parent = NULL; @@ -1229,9 +1239,20 @@ int acpi_bus_scan (struct acpi_device *start) continue; } - status = acpi_bus_add(&child, parent, chandle, type); - if (ACPI_FAILURE(status)) - continue; + if (ops->acpi_op_add) + status = acpi_add_single_object(&child, parent, + chandle, type); + else + status = acpi_bus_get_device(chandle, &child); + + if (ACPI_FAILURE(status)) + continue; + + if (ops->acpi_op_start) { + status = acpi_start_single_object(child); + if (ACPI_FAILURE(status)) + continue; + } /* * If the device is present, enabled, and functioning then @@ -1257,8 +1278,50 @@ int acpi_bus_scan (struct acpi_device *start) return_VALUE(0); } -EXPORT_SYMBOL(acpi_bus_scan); +int +acpi_bus_add ( + struct acpi_device **child, + struct acpi_device *parent, + acpi_handle handle, + int type) +{ + int result; + struct acpi_bus_ops ops; + + ACPI_FUNCTION_TRACE("acpi_bus_add"); + + result = acpi_add_single_object(child, parent, handle, type); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + result = acpi_bus_scan(*child, &ops); + } + return_VALUE(result); +} +EXPORT_SYMBOL(acpi_bus_add); + +int +acpi_bus_start ( + struct acpi_device *device) +{ + int result; + struct acpi_bus_ops ops; + + ACPI_FUNCTION_TRACE("acpi_bus_start"); + + if (!device) + return_VALUE(-EINVAL); + + result = acpi_start_single_object(device); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_start = 1; + result = acpi_bus_scan(device, &ops); + } + return_VALUE(result); +} +EXPORT_SYMBOL(acpi_bus_start); static int acpi_bus_trim(struct acpi_device *start, @@ -1331,13 +1394,19 @@ acpi_bus_scan_fixed ( /* * Enumerate all fixed-feature devices. */ - if (acpi_fadt.pwr_button == 0) - result = acpi_bus_add(&device, acpi_root, + if (acpi_fadt.pwr_button == 0) { + result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_POWER_BUTTON); + if (!result) + result = acpi_start_single_object(device); + } - if (acpi_fadt.sleep_button == 0) - result = acpi_bus_add(&device, acpi_root, + if (acpi_fadt.sleep_button == 0) { + result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); + if (!result) + result = acpi_start_single_object(device); + } return_VALUE(result); } @@ -1346,6 +1415,7 @@ acpi_bus_scan_fixed ( static int __init acpi_scan_init(void) { int result; + struct acpi_bus_ops ops; ACPI_FUNCTION_TRACE("acpi_scan_init"); @@ -1357,17 +1427,23 @@ static int __init acpi_scan_init(void) /* * Create the root device in the bus's device tree */ - result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, + result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SYSTEM); if (result) goto Done; + result = acpi_start_single_object(acpi_root); + /* * Enumerate devices in the ACPI namespace. */ result = acpi_bus_scan_fixed(acpi_root); - if (!result) - result = acpi_bus_scan(acpi_root); + if (!result) { + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_add = 1; + ops.acpi_op_start = 1; + result = acpi_bus_scan(acpi_root, &ops); + } if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 97fe13f..6522814 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -74,6 +74,8 @@ static ssize_t firmware_timeout_store(struct class *class, const char *buf, size_t count) { loading_timeout = simple_strtol(buf, NULL, 10); + if (loading_timeout < 0) + loading_timeout = 0; return count; } @@ -138,6 +140,10 @@ firmware_loading_store(struct class_device *class_dev, switch (loading) { case 1: down(&fw_lock); + if (!fw_priv->fw) { + up(&fw_lock); + break; + } vfree(fw_priv->fw->data); fw_priv->fw->data = NULL; fw_priv->fw->size = 0; @@ -178,7 +184,7 @@ firmware_data_read(struct kobject *kobj, down(&fw_lock); fw = fw_priv->fw; - if (test_bit(FW_STATUS_DONE, &fw_priv->status)) { + if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { ret_count = -ENODEV; goto out; } @@ -238,9 +244,10 @@ firmware_data_write(struct kobject *kobj, if (!capable(CAP_SYS_RAWIO)) return -EPERM; + down(&fw_lock); fw = fw_priv->fw; - if (test_bit(FW_STATUS_DONE, &fw_priv->status)) { + if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { retval = -ENODEV; goto out; } @@ -418,7 +425,7 @@ request_firmware(const struct firmware **firmware_p, const char *name, fw_priv = class_get_devdata(class_dev); - if (loading_timeout) { + if (loading_timeout > 0) { fw_priv->timeout.expires = jiffies + loading_timeout * HZ; add_timer(&fw_priv->timeout); } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 653512b..3e9fb6e 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -786,7 +786,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, case CCISS_GETLUNINFO: { LogvolInfo_struct luninfo; - int i; luninfo.LunID = drv->LunID; luninfo.num_opens = drv->usage_count; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 234fdcf..692a5fc 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1867,19 +1867,20 @@ static void freed_request(request_queue_t *q, int rw) #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist) /* - * Get a free request, queue_lock must not be held + * Get a free request, queue_lock must be held. + * Returns NULL on failure, with queue_lock held. + * 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) { struct request *rq = NULL; struct request_list *rl = &q->rq; - struct io_context *ioc = get_io_context(gfp_mask); + struct io_context *ioc = current_io_context(GFP_ATOMIC); if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) goto out; - spin_lock_irq(q->queue_lock); if (rl->count[rw]+1 >= q->nr_requests) { /* * The queue will fill after this allocation, so set it as @@ -1907,11 +1908,18 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio, * The queue is full and the allocating process is not a * "batcher", and not exempted by the IO scheduler */ - spin_unlock_irq(q->queue_lock); goto out; } get_rq: + /* + * Only allow batching queuers to allocate up to 50% over the defined + * limit of requests, otherwise we could have thousands of requests + * allocated with any setting of ->nr_requests + */ + if (rl->count[rw] >= (3 * q->nr_requests / 2)) + goto out; + rl->count[rw]++; rl->starved[rw] = 0; if (rl->count[rw] >= queue_congestion_on_threshold(q)) @@ -1941,7 +1949,6 @@ rq_starved: if (unlikely(rl->count[rw] == 0)) rl->starved[rw] = 1; - spin_unlock_irq(q->queue_lock); goto out; } @@ -1951,21 +1958,23 @@ rq_starved: rq_init(q, rq); rq->rl = rl; out: - put_io_context(ioc); return rq; } /* * No available requests for this queue, unplug the device and wait for some * requests to become available. + * + * Called with q->queue_lock held, and returns with it unlocked. */ static struct request *get_request_wait(request_queue_t *q, int rw, struct bio *bio) { - DEFINE_WAIT(wait); struct request *rq; - do { + rq = get_request(q, rw, bio, GFP_NOIO); + while (!rq) { + DEFINE_WAIT(wait); struct request_list *rl = &q->rq; prepare_to_wait_exclusive(&rl->wait[rw], &wait, @@ -1976,7 +1985,8 @@ static struct request *get_request_wait(request_queue_t *q, int rw, if (!rq) { struct io_context *ioc; - generic_unplug_device(q); + __generic_unplug_device(q); + spin_unlock_irq(q->queue_lock); io_schedule(); /* @@ -1985,12 +1995,13 @@ static struct request *get_request_wait(request_queue_t *q, int rw, * up to a big batch of them for a small period time. * See ioc_batching, ioc_set_batching */ - ioc = get_io_context(GFP_NOIO); + ioc = current_io_context(GFP_NOIO); ioc_set_batching(q, ioc); - put_io_context(ioc); + + spin_lock_irq(q->queue_lock); } finish_wait(&rl->wait[rw], &wait); - } while (!rq); + } return rq; } @@ -2001,14 +2012,18 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask) BUG_ON(rw != READ && rw != WRITE); - if (gfp_mask & __GFP_WAIT) + spin_lock_irq(q->queue_lock); + if (gfp_mask & __GFP_WAIT) { rq = get_request_wait(q, rw, NULL); - else + } else { rq = get_request(q, rw, NULL, gfp_mask); + if (!rq) + spin_unlock_irq(q->queue_lock); + } + /* q->queue_lock is unlocked at this point */ return rq; } - EXPORT_SYMBOL(blk_get_request); /** @@ -2512,7 +2527,7 @@ EXPORT_SYMBOL(blk_attempt_remerge); static int __make_request(request_queue_t *q, struct bio *bio) { - struct request *req, *freereq = NULL; + struct request *req; int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync; unsigned short prio; sector_t sector; @@ -2540,14 +2555,9 @@ static int __make_request(request_queue_t *q, struct bio *bio) goto end_io; } -again: spin_lock_irq(q->queue_lock); - if (elv_queue_empty(q)) { - blk_plug_device(q); - goto get_rq; - } - if (barrier) + if (unlikely(barrier) || elv_queue_empty(q)) goto get_rq; el_ret = elv_merge(q, &req, bio); @@ -2592,40 +2602,24 @@ again: elv_merged_request(q, req); goto out; - /* - * elevator says don't/can't merge. get new request - */ - case ELEVATOR_NO_MERGE: - break; - + /* ELV_NO_MERGE: elevator says don't/can't merge. */ default: - printk("elevator returned crap (%d)\n", el_ret); - BUG(); + ; } +get_rq: /* - * Grab a free request from the freelist - if that is empty, check - * if we are doing read ahead and abort instead of blocking for - * a free slot. + * Grab a free request. This is might sleep but can not fail. + * Returns with the queue unlocked. + */ + req = get_request_wait(q, rw, bio); + + /* + * After dropping the lock and possibly sleeping here, our request + * may now be mergeable after it had proven unmergeable (above). + * We don't worry about that case for efficiency. It won't happen + * often, and the elevators are able to handle it. */ -get_rq: - if (freereq) { - req = freereq; - freereq = NULL; - } else { - spin_unlock_irq(q->queue_lock); - if ((freereq = get_request(q, rw, bio, GFP_ATOMIC)) == NULL) { - /* - * READA bit set - */ - err = -EWOULDBLOCK; - if (bio_rw_ahead(bio)) - goto end_io; - - freereq = get_request_wait(q, rw, bio); - } - goto again; - } req->flags |= REQ_CMD; @@ -2654,10 +2648,11 @@ get_rq: req->rq_disk = bio->bi_bdev->bd_disk; req->start_time = jiffies; + spin_lock_irq(q->queue_lock); + if (elv_queue_empty(q)) + blk_plug_device(q); add_request(q, req); out: - if (freereq) - __blk_put_request(q, freereq); if (sync) __generic_unplug_device(q); @@ -3284,24 +3279,20 @@ void exit_io_context(void) /* * If the current task has no IO context then create one and initialise it. - * If it does have a context, take a ref on it. + * Otherwise, return its existing IO context. * - * This is always called in the context of the task which submitted the I/O. - * But weird things happen, so we disable local interrupts to ensure exclusive - * access to *current. + * This returned IO context doesn't have a specifically elevated refcount, + * 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 *get_io_context(int gfp_flags) +struct io_context *current_io_context(int gfp_flags) { struct task_struct *tsk = current; - unsigned long flags; struct io_context *ret; - local_irq_save(flags); ret = tsk->io_context; - if (ret) - goto out; - - local_irq_restore(flags); + if (likely(ret)) + return ret; ret = kmem_cache_alloc(iocontext_cachep, gfp_flags); if (ret) { @@ -3312,25 +3303,25 @@ struct io_context *get_io_context(int gfp_flags) ret->nr_batch_requests = 0; /* because this is 0 */ ret->aic = NULL; ret->cic = NULL; + tsk->io_context = ret; + } - local_irq_save(flags); - - /* - * very unlikely, someone raced with us in setting up the task - * io context. free new context and just grab a reference. - */ - if (!tsk->io_context) - tsk->io_context = ret; - else { - kmem_cache_free(iocontext_cachep, ret); - ret = tsk->io_context; - } + return ret; +} +EXPORT_SYMBOL(current_io_context); -out: +/* + * If the current task has no IO context then create one and initialise it. + * If it does have a context, take a ref on it. + * + * 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 *ret; + ret = current_io_context(gfp_flags); + if (likely(ret)) atomic_inc(&ret->refcount); - local_irq_restore(flags); - } - return ret; } EXPORT_SYMBOL(get_io_context); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 1407945..59f589d 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -686,6 +686,15 @@ static struct pci_device_id agp_amd64_pci_table[] = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, + /* SIS 760 */ + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_760, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, { } }; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 1813d0d..e16c13f 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -1088,8 +1088,8 @@ static inline int i_ipmi_request(ipmi_user_t user, long seqid; int broadcast = 0; - if (addr->channel > IPMI_NUM_CHANNELS) { - spin_lock_irqsave(&intf->counter_lock, flags); + if (addr->channel >= IPMI_MAX_CHANNELS) { + spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); rv = -EINVAL; diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 7c24fbe..95f7046 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -451,7 +451,7 @@ static int __init moxa_init(void) int n = (sizeof(moxa_pcibrds) / sizeof(moxa_pcibrds[0])) - 1; i = 0; while (i < n) { - while ((p = pci_find_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL) + while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL) { if (pci_enable_device(p)) continue; diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 7db3370..d7d4840 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -1095,7 +1095,7 @@ static int __init rio_init(void) #ifdef CONFIG_PCI /* First look for the JET devices: */ - while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) { if (pci_enable_device(pdev)) continue; @@ -1169,7 +1169,7 @@ static int __init rio_init(void) */ /* Then look for the older RIO/PCI devices: */ - while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) { if (pci_enable_device(pdev)) continue; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index ff4f098..d8f9e94 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -78,6 +78,7 @@ #include <linux/sysctl.h> #include <linux/wait.h> #include <linux/bcd.h> +#include <linux/delay.h> #include <asm/current.h> #include <asm/uaccess.h> @@ -894,7 +895,6 @@ static int __init rtc_init(void) struct proc_dir_entry *ent; #if defined(__alpha__) || defined(__mips__) unsigned int year, ctrl; - unsigned long uip_watchdog; char *guess = NULL; #endif #ifdef __sparc__ @@ -1000,12 +1000,8 @@ no_irq: /* Each operating system on an Alpha uses its own epoch. Let's try to guess which one we are using now. */ - uip_watchdog = jiffies; if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + msleep(20); spin_lock_irq(&rtc_lock); year = CMOS_READ(RTC_YEAR); @@ -1213,7 +1209,6 @@ static int rtc_proc_open(struct inode *inode, struct file *file) void rtc_get_rtc_time(struct rtc_time *rtc_tm) { - unsigned long uip_watchdog = jiffies; unsigned char ctrl; #ifdef CONFIG_MACH_DECSTATION unsigned int real_year; @@ -1221,7 +1216,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) /* * read RTC once any update in progress is done. The update - * can take just over 2ms. We wait 10 to 20ms. There is no need to + * can take just over 2ms. We wait 20ms. There is no need to * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. * If you need to know *exactly* when a second has started, enable * periodic update complete interrupts, (via ioctl) and then @@ -1230,10 +1225,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) */ if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + msleep(20); /* * Only the values that we read from the RTC are set. We leave diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 659335d8..ec78d2f 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -396,7 +396,7 @@ static struct file_operations tipar_fops = { static int __init tipar_setup(char *str) { - int ints[2]; + int ints[3]; str = get_options(str, ARRAY_SIZE(ints), ints); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 5859799..f19cf9d 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -476,11 +476,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, ld = tty_ldisc_ref(tty); switch (arg) { case TCIFLUSH: - if (ld->flush_buffer) + if (ld && ld->flush_buffer) ld->flush_buffer(tty); break; case TCIOFLUSH: - if (ld->flush_buffer) + if (ld && ld->flush_buffer) ld->flush_buffer(tty); /* fall through */ case TCOFLUSH: diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 8971484..1d44f69 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -25,6 +25,7 @@ #include <linux/fs.h> #include <linux/console.h> #include <linux/signal.h> +#include <linux/timex.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -386,7 +387,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (!perm) return -EPERM; if (arg) - arg = 1193182 / arg; + arg = CLOCK_TICK_RATE / arg; kd_mksound(arg, 0); return 0; @@ -403,7 +404,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ticks = HZ * ((arg >> 16) & 0xffff) / 1000; count = ticks ? (arg & 0xffff) : 0; if (count) - count = 1193182 / count; + count = CLOCK_TICK_RATE / count; kd_mksound(count, ticks); return 0; } diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index 4e98c21..4b03951 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -162,7 +162,7 @@ ixp2000_wdt_release(struct inode *inode, struct file *file) if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { wdt_disable(); } else { - printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - " + printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " "timer will not stop\n"); } diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c index 82396e0..83df369 100644 --- a/drivers/char/watchdog/ixp4xx_wdt.c +++ b/drivers/char/watchdog/ixp4xx_wdt.c @@ -156,7 +156,7 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file) if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { wdt_disable(); } else { - printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - " + printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " "timer will not stop\n"); } diff --git a/drivers/isdn/hardware/eicon/dadapter.c b/drivers/isdn/hardware/eicon/dadapter.c index 6e548a2..8949789 100644 --- a/drivers/isdn/hardware/eicon/dadapter.c +++ b/drivers/isdn/hardware/eicon/dadapter.c @@ -44,7 +44,7 @@ static didd_adapter_change_notification_t\ Array to held adapter information -------------------------------------------------------------------------- */ static DESCRIPTOR HandleTable[NEW_MAX_DESCRIPTORS]; -dword Adapters = 0; /* Number of adapters */ +static dword Adapters = 0; /* Number of adapters */ /* -------------------------------------------------------------------------- Shadow IDI_DIMAINT and 'shadow' debug stuff diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c index 6e7e060..7333377a 100644 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ b/drivers/isdn/hisax/hfc4s8s_l1.c @@ -312,7 +312,7 @@ wait_busy(hfc4s8s_hw * a) /* function to read critical counter registers that */ /* may be udpated by the chip during read */ /******************************************************/ -static volatile u_char +static u_char Read_hfc8_stable(hfc4s8s_hw * hw, int reg) { u_char ref8; @@ -324,7 +324,7 @@ Read_hfc8_stable(hfc4s8s_hw * hw, int reg) return in8; } -static volatile int +static int Read_hfc16_stable(hfc4s8s_hw * hw, int reg) { int ref16; @@ -1465,7 +1465,7 @@ hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode) /******************************************/ /* disable memory mapped ports / io ports */ /******************************************/ -void +static void release_pci_ports(hfc4s8s_hw * hw) { pci_write_config_word(hw->pdev, PCI_COMMAND, 0); @@ -1481,7 +1481,7 @@ release_pci_ports(hfc4s8s_hw * hw) /*****************************************/ /* enable memory mapped ports / io ports */ /*****************************************/ -void +static void enable_pci_ports(hfc4s8s_hw * hw) { #ifdef CONFIG_HISAX_HFC4S8S_PCIMEM diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c index 8ee25b2..1fd3d4e 100644 --- a/drivers/isdn/hysdn/hycapi.c +++ b/drivers/isdn/hysdn/hycapi.c @@ -42,6 +42,8 @@ typedef struct _hycapi_appl { static hycapi_appl hycapi_applications[CAPI_MAXAPPL]; +static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); + static inline int _hycapi_appCheck(int app_id, int ctrl_no) { if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) || @@ -57,7 +59,7 @@ static inline int _hycapi_appCheck(int app_id, int ctrl_no) Kernel-Capi callback reset_ctr ******************************/ -void +static void hycapi_reset_ctr(struct capi_ctr *ctrl) { hycapictrl_info *cinfo = ctrl->driverdata; @@ -73,7 +75,7 @@ hycapi_reset_ctr(struct capi_ctr *ctrl) Kernel-Capi callback remove_ctr ******************************/ -void +static void hycapi_remove_ctr(struct capi_ctr *ctrl) { int i; @@ -215,7 +217,7 @@ Error-checking is done for CAPI-compliance. The application is recorded in the internal list. *************************************************************/ -void +static void hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) { @@ -291,7 +293,7 @@ Release the application from the internal list an remove it's registration at controller-level ******************************************************************/ -void +static void hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl) { int chk; @@ -364,7 +366,7 @@ firmware-releases that do not check the MsgLen-Indication! ***************************************************************/ -u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) +static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) { __u16 appl_id; int _len, _len2; @@ -437,8 +439,8 @@ Informations provided in the /proc/capi-entries. *********************************************************************/ -int hycapi_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *ctrl) +static int hycapi_read_proc(char *page, char **start, off_t off, + int count, int *eof, struct capi_ctr *ctrl) { hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); hysdn_card *card = cinfo->card; @@ -485,7 +487,7 @@ on capi-interface registration. **************************************************************/ -int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) +static int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) { #ifdef HYCAPI_PRINTFNAMES printk(KERN_NOTICE "hycapi_load_firmware\n"); @@ -494,7 +496,7 @@ int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) } -char *hycapi_procinfo(struct capi_ctr *ctrl) +static char *hycapi_procinfo(struct capi_ctr *ctrl) { hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); #ifdef HYCAPI_PRINTFNAMES diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c index 6c04281..7bfba19 100644 --- a/drivers/isdn/hysdn/hysdn_boot.c +++ b/drivers/isdn/hysdn/hysdn_boot.c @@ -53,7 +53,7 @@ struct boot_data { /* to be called at start of POF file reading, */ /* before starting any decryption on any POF record. */ /*****************************************************/ -void +static void StartDecryption(struct boot_data *boot) { boot->Cryptor = CRYPT_STARTTERM; @@ -66,7 +66,7 @@ StartDecryption(struct boot_data *boot) /* to HI and LO boot loader and (all) seq tags, because */ /* global Cryptor is started for whole POF. */ /***************************************************************/ -void +static void DecryptBuf(struct boot_data *boot, int cnt) { uchar *bufp = boot->buf.BootBuf; diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h index 4cee26e..432f6f9 100644 --- a/drivers/isdn/hysdn/hysdn_defs.h +++ b/drivers/isdn/hysdn/hysdn_defs.h @@ -227,7 +227,6 @@ typedef struct hycapictrl_info hycapictrl_info; /*****************/ /* exported vars */ /*****************/ -extern int cardmax; /* number of found cards */ extern hysdn_card *card_root; /* pointer to first card */ @@ -244,7 +243,6 @@ extern void hysdn_procconf_release(void); /* deinit proc config filesys */ /* hysdn_proclog.c */ extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */ extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */ -extern void put_log_buffer(hysdn_card *, char *); /* output log data */ extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */ extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */ @@ -278,16 +276,6 @@ extern unsigned int hycapi_enable; extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ extern int hycapi_capi_release(hysdn_card *); /* delete the device */ extern int hycapi_capi_stop(hysdn_card *card); /* suspend */ -extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *); -extern void hycapi_reset_ctr(struct capi_ctr *); -extern void hycapi_remove_ctr(struct capi_ctr *); -extern void hycapi_register_appl(struct capi_ctr *, __u16 appl, - capi_register_params *); -extern void hycapi_release_appl(struct capi_ctr *, __u16 appl); -extern u16 hycapi_send_message(struct capi_ctr *, struct sk_buff *skb); -extern char *hycapi_procinfo(struct capi_ctr *); -extern int hycapi_read_proc(char *page, char **start, off_t off, - int count, int *eof, struct capi_ctr *card); extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len); extern void hycapi_tx_capiack(hysdn_card * card); extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card); diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c index 5cac2bf..12c8137 100644 --- a/drivers/isdn/hysdn/hysdn_init.c +++ b/drivers/isdn/hysdn/hysdn_init.c @@ -34,7 +34,7 @@ MODULE_AUTHOR("Werner Cornelius"); MODULE_LICENSE("GPL"); static char *hysdn_init_revision = "$Revision: 1.6.6.6 $"; -int cardmax; /* number of found cards */ +static int cardmax; /* number of found cards */ hysdn_card *card_root = NULL; /* pointer to first card */ /**********************************************/ diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 8ef2b7c..4d57011 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -22,6 +22,8 @@ /* the proc subdir for the interface is defined in the procconf module */ extern struct proc_dir_entry *hysdn_proc_entry; +static void put_log_buffer(hysdn_card * card, char *cp); + /*************************************************/ /* structure keeping ascii log for device output */ /*************************************************/ @@ -93,7 +95,7 @@ hysdn_addlog(hysdn_card * card, char *fmt,...) /* opened for read got the contents. */ /* Flushes buffers not longer in use. */ /********************************************/ -void +static void put_log_buffer(hysdn_card * card, char *cp) { struct log_data *ib; diff --git a/drivers/md/md.c b/drivers/md/md.c index 3802f7a..4a0c57d 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -338,6 +338,7 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error) if (atomic_dec_and_test(&rdev->mddev->pending_writes)) wake_up(&rdev->mddev->sb_wait); + bio_put(bio); return 0; } diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 2dc906f..810e7aa 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -7,8 +7,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o - +tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 290289a..7d62b39 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1,5 +1,5 @@ /* - $Id: bttv-driver.c,v 1.38 2005/06/10 17:20:24 mchehab Exp $ + $Id: bttv-driver.c,v 1.40 2005/06/16 21:38:45 nsh Exp $ bttv - Bt848 frame grabber driver @@ -76,6 +76,9 @@ static unsigned int whitecrush_upper = 0xCF; static unsigned int whitecrush_lower = 0x7F; static unsigned int vcr_hack = 0; static unsigned int irq_iswitch = 0; +static unsigned int uv_ratio = 50; +static unsigned int full_luma_range = 0; +static unsigned int coring = 0; /* API features (turn on/off stuff for testing) */ static unsigned int v4l2 = 1; @@ -106,6 +109,9 @@ module_param(adc_crush, int, 0444); module_param(whitecrush_upper, int, 0444); module_param(whitecrush_lower, int, 0444); module_param(vcr_hack, int, 0444); +module_param(uv_ratio, int, 0444); +module_param(full_luma_range, int, 0444); +module_param(coring, int, 0444); module_param_array(radio, int, NULL, 0444); @@ -124,6 +130,9 @@ MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); +MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50"); +MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)"); +MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)"); MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards"); MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); @@ -484,7 +493,10 @@ static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats); #define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) #define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) #define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8) +#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9) +#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10) +#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11) static const struct v4l2_queryctrl no_ctl = { .name = "42", @@ -618,8 +630,32 @@ static const struct v4l2_queryctrl bttv_ctls[] = { .step = 1, .default_value = 0x7F, .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_UV_RATIO, + .name = "uv ratio", + .minimum = 0, + .maximum = 100, + .step = 1, + .default_value = 50, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, + .name = "full luma range", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_PRIVATE_CORING, + .name = "coring", + .minimum = 0, + .maximum = 3, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, } + + }; static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls); @@ -833,8 +869,8 @@ static void bt848_sat(struct bttv *btv, int color) btv->saturation = color; /* 0-511 for the color */ - val_u = color >> 7; - val_v = ((color>>7)*180L)/254; + val_u = ((color * btv->opt_uv_ratio) / 50) >> 7; + val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254; hibits = (val_u >> 7) & 2; hibits |= (val_v >> 8) & 1; btwrite(val_u & 0xff, BT848_SAT_U_LO); @@ -1151,6 +1187,15 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: c->value = btv->opt_whitecrush_lower; break; + case V4L2_CID_PRIVATE_UV_RATIO: + c->value = btv->opt_uv_ratio; + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + c->value = btv->opt_full_luma_range; + break; + case V4L2_CID_PRIVATE_CORING: + c->value = btv->opt_coring; + break; default: return -EINVAL; } @@ -1247,6 +1292,18 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) btv->opt_whitecrush_lower = c->value; btwrite(c->value, BT848_WC_DOWN); break; + case V4L2_CID_PRIVATE_UV_RATIO: + btv->opt_uv_ratio = c->value; + bt848_sat(btv, btv->saturation); + break; + case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: + btv->opt_full_luma_range = c->value; + btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); + break; + case V4L2_CID_PRIVATE_CORING: + btv->opt_coring = c->value; + btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); + break; default: return -EINVAL; } @@ -3117,11 +3174,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; memset(v,0,sizeof(*v)); strcpy(v->name, "Radio"); - /* japan: 76.0 MHz - 89.9 MHz - western europe: 87.5 MHz - 108.0 MHz - russia: 65.0 MHz - 108.0 MHz */ - v->rangelow=(int)(65*16); - v->rangehigh=(int)(108*16); bttv_call_i2c_clients(btv,cmd,v); return 0; } @@ -3876,6 +3928,9 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->opt_vcr_hack = vcr_hack; btv->opt_whitecrush_upper = whitecrush_upper; btv->opt_whitecrush_lower = whitecrush_lower; + btv->opt_uv_ratio = uv_ratio; + btv->opt_full_luma_range = full_luma_range; + btv->opt_coring = coring; /* fill struct bttv with some useful defaults */ btv->init.btv = btv; diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index 7b6f1e8..f3293e4 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -1,5 +1,5 @@ /* - $Id: bttvp.h,v 1.17 2005/02/16 12:14:10 kraxel Exp $ + $Id: bttvp.h,v 1.19 2005/06/16 21:38:45 nsh Exp $ bttv - Bt848 frame grabber driver @@ -326,6 +326,9 @@ struct bttv { int opt_vcr_hack; int opt_whitecrush_upper; int opt_whitecrush_lower; + int opt_uv_ratio; + int opt_full_luma_range; + int opt_coring; /* radio data/state */ int has_radio; diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index 95ad17b..9c005cb 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -1,5 +1,5 @@ /* - * $Id: mt20xx.c,v 1.4 2005/03/04 09:24:56 kraxel Exp $ + * $Id: mt20xx.c,v 1.5 2005/06/16 08:29:49 nsh Exp $ * * i2c tv tuner chip device driver * controls microtune tuners, mt2032 + mt2050 at the moment. @@ -295,8 +295,8 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) int if2 = t->radio_if2; // per Manual for FM tuning: first if center freq. 1085 MHz - mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, - 1085*1000*1000,if2,if2,if2); + mt2032_set_if_freq(c, freq * 1000 / 16, + 1085*1000*1000,if2,if2,if2); } // Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index b27cc34..f59d460 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -1,5 +1,5 @@ /* - * $Id: tda8290.c,v 1.7 2005/03/07 12:01:51 kraxel Exp $ + * $Id: tda8290.c,v 1.11 2005/06/18 06:09:06 nsh Exp $ * * i2c tv tuner chip device driver * controls the philips tda8290+75 tuner chip combo. @@ -69,7 +69,7 @@ static __u8 get_freq_entry( struct freq_entry* table, __u16 freq) static unsigned char i2c_enable_bridge[2] = { 0x21, 0xC0 }; static unsigned char i2c_disable_bridge[2] = { 0x21, 0x80 }; static unsigned char i2c_init_tda8275[14] = { 0x00, 0x00, 0x00, 0x00, - 0x7C, 0x04, 0xA3, 0x3F, + 0xfC, 0x04, 0xA3, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; static unsigned char i2c_set_VS[2] = { 0x30, 0x6F }; @@ -138,16 +138,24 @@ static int tda8290_tune(struct i2c_client *c) static void set_frequency(struct tuner *t, u16 ifc) { - u32 N = (((t->freq<<3)+ifc)&0x3fffc); + u32 freq; + u32 N; - N = N >> get_freq_entry(div_table, t->freq); + if (t->mode == V4L2_TUNER_RADIO) + freq = t->freq / 1000; + else + freq = t->freq; + + N = (((freq<<3)+ifc)&0x3fffc); + + N = N >> get_freq_entry(div_table, freq); t->i2c_set_freq[0] = 0; t->i2c_set_freq[1] = (unsigned char)(N>>8); t->i2c_set_freq[2] = (unsigned char) N; t->i2c_set_freq[3] = 0x40; t->i2c_set_freq[4] = 0x52; - t->i2c_set_freq[5] = get_freq_entry(band_table, t->freq); - t->i2c_set_freq[6] = get_freq_entry(agc_table, t->freq); + t->i2c_set_freq[5] = get_freq_entry(band_table, freq); + t->i2c_set_freq[6] = get_freq_entry(agc_table, freq); t->i2c_set_freq[7] = 0x8f; } diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 3977363..ee35562 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -368,7 +368,7 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf) if (t->radio_mode == V4L2_TUNER_MODE_MONO) norm = &radio_mono; else - norm = &radio_stereo; + norm = &radio_stereo; } else { for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { if (tvnorms[i].std & t->std) { @@ -566,7 +566,6 @@ static int tda9887_configure(struct tda9887 *t) if (UNSET != t->pinnacle_id) { tda9887_set_pinnacle(t,buf); } - tda9887_set_config(t,buf); tda9887_set_insmod(t,buf); @@ -615,8 +614,8 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind) t->pinnacle_id = UNSET; t->radio_mode = V4L2_TUNER_MODE_STEREO; - i2c_set_clientdata(&t->client, t); - i2c_attach_client(&t->client); + i2c_set_clientdata(&t->client, t); + i2c_attach_client(&t->client); return 0; } diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c new file mode 100644 index 0000000..a29f08f --- /dev/null +++ b/drivers/media/video/tea5767.c @@ -0,0 +1,334 @@ +/* + * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview + * I2C address is allways 0xC0. + * + * $Id: tea5767.c,v 1.11 2005/06/21 15:40:33 mchehab Exp $ + * + * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) + * This code is placed under the terms of the GNU General Public License + * + * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa + * from their contributions on DScaler. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/videodev.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include <media/tuner.h> + +/* Declared at tuner-core.c */ +extern unsigned int tuner_debug; + +#define PREFIX "TEA5767 " + +/*****************************************************************************/ + +/****************************** + * Write mode register values * + ******************************/ + +/* First register */ +#define TEA5767_MUTE 0x80 /* Mutes output */ +#define TEA5767_SEARCH 0x40 /* Activates station search */ +/* Bits 0-5 for divider MSB */ + +/* Second register */ +/* Bits 0-7 for divider LSB */ + +/* Third register */ + +/* Station search from botton to up */ +#define TEA5767_SEARCH_UP 0x80 + +/* Searches with ADC output = 10 */ +#define TEA5767_SRCH_HIGH_LVL 0x60 + +/* Searches with ADC output = 10 */ +#define TEA5767_SRCH_MID_LVL 0x40 + +/* Searches with ADC output = 5 */ +#define TEA5767_SRCH_LOW_LVL 0x20 + +/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ +#define TEA5767_HIGH_LO_INJECT 0x10 + +/* Disable stereo */ +#define TEA5767_MONO 0x08 + +/* Disable right channel and turns to mono */ +#define TEA5767_MUTE_RIGHT 0x04 + +/* Disable left channel and turns to mono */ +#define TEA5767_MUTE_LEFT 0x02 + +#define TEA5767_PORT1_HIGH 0x01 + +/* Forth register */ +#define TEA5767_PORT2_HIGH 0x80 +/* Chips stops working. Only I2C bus remains on */ +#define TEA5767_STDBY 0x40 + +/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ +#define TEA5767_JAPAN_BAND 0x20 + +/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ +#define TEA5767_XTAL_32768 0x10 + +/* Cuts weak signals */ +#define TEA5767_SOFT_MUTE 0x08 + +/* Activates high cut control */ +#define TEA5767_HIGH_CUT_CTRL 0x04 + +/* Activates stereo noise control */ +#define TEA5767_ST_NOISE_CTL 0x02 + +/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ +#define TEA5767_SRCH_IND 0x01 + +/* Fiveth register */ + +/* By activating, it will use Xtal at 13 MHz as reference for divider */ +#define TEA5767_PLLREF_ENABLE 0x80 + +/* By activating, deemphasis=50, or else, deemphasis of 50us */ +#define TEA5767_DEEMPH_75 0X40 + +/***************************** + * Read mode register values * + *****************************/ + +/* First register */ +#define TEA5767_READY_FLAG_MASK 0x80 +#define TEA5767_BAND_LIMIT_MASK 0X40 +/* Bits 0-5 for divider MSB after search or preset */ + +/* Second register */ +/* Bits 0-7 for divider LSB after search or preset */ + +/* Third register */ +#define TEA5767_STEREO_MASK 0x80 +#define TEA5767_IF_CNTR_MASK 0x7f + +/* Four register */ +#define TEA5767_ADC_LEVEL_MASK 0xf0 + +/* should be 0 */ +#define TEA5767_CHIP_ID_MASK 0x0f + +/* Fiveth register */ +/* Reserved for future extensions */ +#define TEA5767_RESERVED_MASK 0xff + +/*****************************************************************************/ + +static void set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + + tuner_warn("This tuner doesn't support TV freq.\n"); +} + +static void tea5767_status_dump(unsigned char *buffer) +{ + unsigned int div, frq; + + if (TEA5767_READY_FLAG_MASK & buffer[0]) + printk(PREFIX "Ready Flag ON\n"); + else + printk(PREFIX "Ready Flag OFF\n"); + + if (TEA5767_BAND_LIMIT_MASK & buffer[0]) + printk(PREFIX "Tuner at band limit\n"); + else + printk(PREFIX "Tuner not at band limit\n"); + + div=((buffer[0]&0x3f)<<8) | buffer[1]; + + switch (TEA5767_HIGH_LO_32768) { + case TEA5767_HIGH_LO_13MHz: + frq = 1000*(div*50-700-225)/4; /* Freq in KHz */ + break; + case TEA5767_LOW_LO_13MHz: + frq = 1000*(div*50+700+225)/4; /* Freq in KHz */ + break; + case TEA5767_LOW_LO_32768: + frq = 1000*(div*32768/1000+700+225)/4; /* Freq in KHz */ + break; + case TEA5767_HIGH_LO_32768: + default: + frq = 1000*(div*32768/1000-700-225)/4; /* Freq in KHz */ + break; + } + buffer[0] = (div>>8) & 0x3f; + buffer[1] = div & 0xff; + + printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n", + frq/1000,frq%1000,div); + + if (TEA5767_STEREO_MASK & buffer[2]) + printk(PREFIX "Stereo\n"); + else + printk(PREFIX "Mono\n"); + + printk(PREFIX "IF Counter = %d\n",buffer[2] & TEA5767_IF_CNTR_MASK); + + printk(PREFIX "ADC Level = %d\n",(buffer[3] & TEA5767_ADC_LEVEL_MASK)>>4); + + printk(PREFIX "Chip ID = %d\n",(buffer[3] & TEA5767_CHIP_ID_MASK)); + + printk(PREFIX "Reserved = 0x%02x\n",(buffer[4] & TEA5767_RESERVED_MASK)); +} + +/* Freq should be specifyed at 62.5 Hz */ +static void set_radio_freq(struct i2c_client *c, unsigned int frq) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buffer[5]; + unsigned div; + int rc; + + if ( tuner_debug ) + printk(PREFIX "radio freq counter %d\n",frq); + + /* Rounds freq to next decimal value - for 62.5 KHz step */ + /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + + buffer[2] = TEA5767_PORT1_HIGH; + buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; + buffer[4]=0; + + if (t->audmode == V4L2_TUNER_MODE_MONO) { + tuner_dbg("TEA5767 set to mono\n"); + buffer[2] |= TEA5767_MONO; + } else + tuner_dbg("TEA5767 set to stereo\n"); + + switch (t->type) { + case TEA5767_HIGH_LO_13MHz: + tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n"); + buffer[2] |= TEA5767_HIGH_LO_INJECT; + buffer[4] |= TEA5767_PLLREF_ENABLE; + div = (frq*4/16+700+225+25)/50; + break; + case TEA5767_LOW_LO_13MHz: + tuner_dbg("TEA5767 radio LOW LO inject xtal @ 13 MHz\n"); + + buffer[4] |= TEA5767_PLLREF_ENABLE; + div = (frq*4/16-700-225+25)/50; + break; + case TEA5767_LOW_LO_32768: + tuner_dbg("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n"); + buffer[3] |= TEA5767_XTAL_32768; + /* const 700=4000*175 Khz - to adjust freq to right value */ + div = (1000*(frq*4/16-700-225)+16384)>>15; + break; + case TEA5767_HIGH_LO_32768: + default: + tuner_dbg("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n"); + + buffer[2] |= TEA5767_HIGH_LO_INJECT; + buffer[3] |= TEA5767_XTAL_32768; + div = (1000*(frq*4/16+700+225)+16384)>>15; + break; + } + buffer[0] = (div>>8) & 0x3f; + buffer[1] = div & 0xff; + + if ( tuner_debug ) + tea5767_status_dump(buffer); + + if (5 != (rc = i2c_master_send(c,buffer,5))) + tuner_warn("i2c i/o error: rc == %d (should be 5)\n",rc); +} + +static int tea5767_signal(struct i2c_client *c) +{ + unsigned char buffer[5]; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + memset(buffer,0,sizeof(buffer)); + if (5 != (rc = i2c_master_recv(c,buffer,5))) + tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); + + return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) <<(13-4)); +} + +static int tea5767_stereo(struct i2c_client *c) +{ + unsigned char buffer[5]; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + memset(buffer,0,sizeof(buffer)); + if (5 != (rc = i2c_master_recv(c,buffer,5))) + tuner_warn ( "i2c i/o error: rc == %d (should be 5)\n",rc); + + rc = buffer[2] & TEA5767_STEREO_MASK; + + if ( tuner_debug ) + tuner_dbg("TEA5767 radio ST GET = %02x\n", rc); + + return ( (buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO: 0); +} + +int tea_detection(struct i2c_client *c) +{ + unsigned char buffer[5]= { 0xff, 0xff, 0xff, 0xff, 0xff }; + int rc; + struct tuner *t = i2c_get_clientdata(c); + + if (5 != (rc = i2c_master_recv(c,buffer,5))) { + tuner_warn ( "it is not a TEA5767. Received %i chars.\n",rc ); + return EINVAL; + } + + /* If all bytes are the same then it's a TV tuner and not a tea5767 chip. */ + if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && + buffer[0] == buffer[3] && buffer[0] == buffer[4]) { + tuner_warn ( "All bytes are equal. It is not a TEA5767\n" ); + return EINVAL; + } + + /* Status bytes: + * Byte 4: bit 3:1 : CI (Chip Identification) == 0 + * bit 0 : internally set to 0 + * Byte 5: bit 7:0 : == 0 + */ + + if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) { + tuner_warn ( "Chip ID is not zero. It is not a TEA5767\n" ); + return EINVAL; + } + tuner_warn ( "TEA5767 detected.\n" ); + return 0; +} + +int tea5767_tuner_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + + if (tea_detection(c)==EINVAL) return EINVAL; + + tuner_info("type set to %d (%s)\n", + t->type, TEA5767_TUNER_NAME); + strlcpy(c->name, TEA5767_TUNER_NAME, sizeof(c->name)); + + t->tv_freq = set_tv_freq; + t->radio_freq = set_radio_freq; + t->has_signal = tea5767_signal; + t->is_stereo = tea5767_stereo; + + return (0); +} diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index eaabfc8..6f6bf4a 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-core.c,v 1.15 2005/06/12 01:36:14 mchehab Exp $ + * $Id: tuner-core.c,v 1.29 2005/06/21 15:40:33 mchehab Exp $ * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on @@ -26,7 +26,6 @@ /* * comment line bellow to return to old behavor, where only one I2C device is supported */ -#define CONFIG_TUNER_MULTI_I2C /**/ #define UNSET (-1U) @@ -58,9 +57,7 @@ MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); static int this_adap; -#ifdef CONFIG_TUNER_MULTI_I2C static unsigned short first_tuner, tv_tuner, radio_tuner; -#endif static struct i2c_driver driver; static struct i2c_client client_template; @@ -81,26 +78,9 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) return; } if (freq < tv_range[0]*16 || freq > tv_range[1]*16) { - - if (freq >= tv_range[0]*16364 && freq <= tv_range[1]*16384) { - /* V4L2_TUNER_CAP_LOW frequency */ - - tuner_dbg("V4L2_TUNER_CAP_LOW freq selected for TV. Tuners yet doesn't support converting it to valid freq.\n"); - - t->tv_freq(c,freq>>10); - - return; - } else { - /* FIXME: better do that chip-specific, but - right now we don't have that in the config - struct and this way is still better than no - check at all */ tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n", freq/16,freq%16*100/16,tv_range[0],tv_range[1]); - return; - } } - tuner_dbg("62.5 Khz freq step selected for TV.\n"); t->tv_freq(c,freq); } @@ -116,31 +96,18 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_info("no radio tuning for this one, sorry.\n"); return; } - if (freq < radio_range[0]*16 || freq > radio_range[1]*16) { - if (freq >= tv_range[0]*16364 && freq <= tv_range[1]*16384) { - /* V4L2_TUNER_CAP_LOW frequency */ - if (t->type == TUNER_TEA5767) { - tuner_info("radio freq step 62.5Hz (%d.%06d)\n",(freq>>14),freq%(1<<14)*10000); - t->radio_freq(c,freq>>10); - return; - } - - tuner_dbg("V4L2_TUNER_CAP_LOW freq selected for Radio. Tuners yet doesn't support converting it to valid freq.\n"); - - tuner_info("radio freq (%d.%06d)\n",(freq>>14),freq%(1<<14)*10000); - - t->radio_freq(c,freq>>10); - return; - - } else { - tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", - freq/16,freq%16*100/16, - radio_range[0],radio_range[1]); - return; - } + if (freq >= radio_range[0]*16000 && freq <= radio_range[1]*16000) { + if (tuner_debug) + tuner_info("radio freq step 62.5Hz (%d.%06d)\n", + freq/16000,freq%16000*1000/16); + t->radio_freq(c,freq); + } else { + tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n", + freq/16,freq%16*100/16, + radio_range[0],radio_range[1]); } - tuner_dbg("62.5 Khz freq step selected for Radio.\n"); - t->radio_freq(c,freq); + + return; } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -166,8 +133,8 @@ static void set_freq(struct i2c_client *c, unsigned long freq) static void set_type(struct i2c_client *c, unsigned int type) { struct tuner *t = i2c_get_clientdata(c); + unsigned char buffer[4]; - tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type); /* sanity check */ if (type == UNSET || type == TUNER_ABSENT) return; @@ -179,8 +146,8 @@ static void set_type(struct i2c_client *c, unsigned int type) t->type = type; return; } - if (t->initialized) - /* run only once */ + if ((t->initialized) && (t->type == type)) + /* run only once except type change Hac 04/05*/ return; t->initialized = 1; @@ -193,25 +160,42 @@ static void set_type(struct i2c_client *c, unsigned int type) case TUNER_PHILIPS_TDA8290: tda8290_init(c); break; + case TUNER_TEA5767: + if (tea5767_tuner_init(c)==EINVAL) t->type=TUNER_ABSENT; + break; + case TUNER_PHILIPS_FMD1216ME_MK3: + buffer[0] = 0x0b; + buffer[1] = 0xdc; + buffer[2] = 0x9c; + buffer[3] = 0x60; + i2c_master_send(c,buffer,4); + mdelay(1); + buffer[2] = 0x86; + buffer[3] = 0x54; + i2c_master_send(c,buffer,4); + default_tuner_init(c); + break; default: + /* TEA5767 autodetection code */ + if (tea5767_tuner_init(c)!=EINVAL) { + t->type = TUNER_TEA5767; + if (first_tuner == 0x60) + first_tuner++; + break; + } + default_tuner_init(c); break; } + tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type); } -#ifdef CONFIG_TUNER_MULTI_I2C #define CHECK_ADDR(tp,cmd,tun) if (client->addr!=tp) { \ - return 0; } else \ + return 0; } else if (tuner_debug) \ tuner_info ("Cmd %s accepted to "tun"\n",cmd); #define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \ CHECK_ADDR(radio_tuner,cmd,"radio") } else \ { CHECK_ADDR(tv_tuner,cmd,"TV"); } -#else -#define CHECK_ADDR(tp,cmd,tun) tuner_info ("Cmd %s accepted to "tun"\n",cmd); -#define CHECK_MODE(cmd) tuner_info ("Cmd %s accepted\n",cmd); -#endif - -#ifdef CONFIG_TUNER_MULTI_I2C static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) { @@ -242,9 +226,6 @@ static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr) } set_type(c,tun_addr->type); } -#else -#define set_addr(c,tun_addr) set_type(c,(tun_addr)->type) -#endif static char pal[] = "-"; module_param_string(pal, pal, sizeof(pal), 0644); @@ -284,17 +265,12 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) { struct tuner *t; -#ifndef CONFIG_TUNER_MULTI_I2C - if (this_adap > 0) - return -1; -#else /* by default, first I2C card is both tv and radio tuner */ if (this_adap == 0) { first_tuner = addr; tv_tuner = addr; radio_tuner = addr; } -#endif this_adap++; client_template.adapter = adap; @@ -308,6 +284,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) i2c_set_clientdata(&t->i2c, t); t->type = UNSET; t->radio_if2 = 10700*1000; /* 10.7MHz - FM radio */ + t->audmode = V4L2_TUNER_MODE_STEREO; i2c_attach_client(&t->i2c); tuner_info("chip found @ 0x%x (%s)\n", @@ -325,11 +302,9 @@ static int tuner_probe(struct i2c_adapter *adap) } this_adap = 0; -#ifdef CONFIG_TUNER_MULTI_I2C first_tuner = 0; tv_tuner = 0; radio_tuner = 0; -#endif if (adap->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adap, &addr_data, tuner_attach); @@ -392,8 +367,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) t->radio_if2 = 41300 * 1000; break; } - break; - + break; /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -440,11 +414,18 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) vt->signal = t->has_signal(client); if (t->is_stereo) { if (t->is_stereo(client)) - vt-> flags |= VIDEO_TUNER_STEREO_ON; + vt->flags |= VIDEO_TUNER_STEREO_ON; else - vt-> flags &= 0xffff ^ VIDEO_TUNER_STEREO_ON; + vt->flags &= ~VIDEO_TUNER_STEREO_ON; } vt->flags |= V4L2_TUNER_CAP_LOW; /* Allow freqs at 62.5 Hz */ + + vt->rangelow = radio_range[0] * 16000; + vt->rangehigh = radio_range[1] * 16000; + + } else { + vt->rangelow = tv_range[0] * 16; + vt->rangehigh = tv_range[1] * 16; } return 0; @@ -510,20 +491,46 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) tuner -> signal = t->has_signal(client); if (t->is_stereo) { if (t->is_stereo(client)) { - tuner -> capability |= V4L2_TUNER_CAP_STEREO; - tuner -> rxsubchans |= V4L2_TUNER_SUB_STEREO; + tuner -> rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; } else { - tuner -> rxsubchans &= 0xffff ^ V4L2_TUNER_SUB_STEREO; + tuner -> rxsubchans = V4L2_TUNER_SUB_MONO; } } + tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + tuner->audmode = t->audmode; + + tuner->rangelow = radio_range[0] * 16000; + tuner->rangehigh = radio_range[1] * 16000; + } else { + tuner->rangelow = tv_range[0] * 16; + tuner->rangehigh = tv_range[1] * 16; } - /* Wow to deal with V4L2_TUNER_CAP_LOW ? For now, it accepts from low at 62.5KHz step to high at 62.5 Hz */ - tuner->rangelow = tv_range[0] * 16; -// tuner->rangehigh = tv_range[1] * 16; -// tuner->rangelow = tv_range[0] * 16384; - tuner->rangehigh = tv_range[1] * 16384; break; } + case VIDIOC_S_TUNER: /* Allow changing radio range and audio mode */ + { + struct v4l2_tuner *tuner = arg; + + CHECK_ADDR(radio_tuner,"VIDIOC_S_TUNER","radio"); + SWITCH_V4L2; + + /* To switch the audio mode, applications initialize the + index and audmode fields and the reserved array and + call the VIDIOC_S_TUNER ioctl. */ + /* rxsubchannels: V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO, + V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2, + V4L2_TUNER_MODE_SAP */ + + if (tuner->audmode == V4L2_TUNER_MODE_MONO) + t->audmode = V4L2_TUNER_MODE_MONO; + else + t->audmode = V4L2_TUNER_MODE_STEREO; + + set_radio_freq(client, t->freq); + break; + } + case TDA9887_SET_CONFIG: /* Nothing to do on tuner-core */ + break; default: tuner_dbg ("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd); /* nothing */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 539f305..c39ed62 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -1,5 +1,5 @@ /* - * $Id: tuner-simple.c,v 1.21 2005/06/10 19:53:26 nsh Exp $ + * $Id: tuner-simple.c,v 1.31 2005/06/21 16:02:25 mkrufky Exp $ * * i2c tv tuner chip device driver * controls all those simple 4-control-bytes style tuners. @@ -207,28 +207,27 @@ static struct tunertype tuners[] = { { "LG PAL (TAPE series)", LGINNOTEK, PAL, 16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623}, - { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL, - 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, - { "Philips FQ1236A MK4", Philips, NTSC, - 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, + { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL, + 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 }, + { "Philips FQ1236A MK4", Philips, NTSC, + 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 }, /* Should work for TVF8531MF, TVF8831MF, TVF8731MF */ { "Ymec TVision TVF-8531MF", Philips, NTSC, 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732}, { "Ymec TVision TVF-5533MF", Philips, NTSC, 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, - { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, - { "Tena TNF9533-D/IF", LGINNOTEK, PAL, - 16*160.25, 16*464.25, 0x01,0x02,0x08,0x8e,623}, + /* Should work for TNF9533-D/IF, TNF9533-B/DF */ + { "Tena TNF9533-D/IF", Philips, PAL, + 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623}, - /* - * This entry is for TEA5767 FM radio only chip used on several boards - * w/TV tuner - */ + /* This entry is for TEA5767 FM radio only chip used on several boards w/TV tuner */ { TEA5767_TUNER_NAME, Philips, RADIO, - -1, -1, 0, 0, 0, TEA5767_LOW_LO_32768,0}, + -1, -1, 0, 0, 0, TEA5767_LOW_LO_32768,0}, + { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL, + 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); @@ -455,24 +454,24 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) int rc; tun=&tuners[t->type]; - div = freq + (int)(16*10.7); + div = (freq / 1000) + (int)(16*10.7); buffer[2] = tun->config; switch (t->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - /*These values are empirically determinated */ - div = (freq*122)/16 - 20; + div = (freq * 122) / 16000 - 20; buffer[2] = 0x88; /* could be also 0x80 */ buffer[3] = 0x19; /* could be also 0x10, 0x18, 0x99 */ break; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: + case TUNER_PHILIPS_FMD1216ME_MK3: buffer[3] = 0x19; break; case TUNER_PHILIPS_FM1256_IH3: - div = (20 * freq)/16 + 333 * 2; + div = (20 * freq) / 16000 + 333 * 2; buffer[2] = 0x80; buffer[3] = 0x19; break; @@ -505,6 +504,7 @@ int default_tuner_init(struct i2c_client *c) t->radio_freq = default_set_radio_freq; t->has_signal = tuner_signal; t->is_stereo = tuner_stereo; + return 0; } diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index d8d6539..353deb2 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -364,9 +364,7 @@ static struct pci_driver mptfc_driver = { .id_table = mptfc_pci_table, .probe = mptfc_probe, .remove = __devexit_p(mptscsih_remove), - .driver = { - .shutdown = mptscsih_shutdown, - }, + .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume, diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index a0078ae..4f973a4 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -170,7 +170,7 @@ static void mptscsih_fillbuf(char *buffer, int size, int index, int width); #endif void mptscsih_remove(struct pci_dev *); -void mptscsih_shutdown(struct device *); +void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); int mptscsih_resume(struct pci_dev *pdev); @@ -988,7 +988,7 @@ mptscsih_remove(struct pci_dev *pdev) #endif #endif - mptscsih_shutdown(&pdev->dev); + mptscsih_shutdown(pdev); sz1=0; @@ -1026,9 +1026,9 @@ mptscsih_remove(struct pci_dev *pdev) * */ void -mptscsih_shutdown(struct device * dev) +mptscsih_shutdown(struct pci_dev *pdev) { - MPT_ADAPTER *ioc = pci_get_drvdata(to_pci_dev(dev)); + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct Scsi_Host *host = ioc->sh; MPT_SCSI_HOST *hd; @@ -1054,7 +1054,7 @@ mptscsih_shutdown(struct device * dev) int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state) { - mptscsih_shutdown(&pdev->dev); + mptscsih_shutdown(pdev); return mpt_suspend(pdev,state); } diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index d73aec3..5ea89bf 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -82,7 +82,7 @@ #endif extern void mptscsih_remove(struct pci_dev *); -extern void mptscsih_shutdown(struct device *); +extern void mptscsih_shutdown(struct pci_dev *); #ifdef CONFIG_PM extern int mptscsih_suspend(struct pci_dev *pdev, u32 state); extern int mptscsih_resume(struct pci_dev *pdev); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 5f9a61b..e0c0ee5 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -419,9 +419,7 @@ static struct pci_driver mptspi_driver = { .id_table = mptspi_pci_table, .probe = mptspi_probe, .remove = __devexit_p(mptscsih_remove), - .driver = { - .shutdown = mptscsih_shutdown, - }, + .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, .resume = mptscsih_resume, diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index d272ea3..91d1c4c 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -822,7 +822,7 @@ static int corkscrew_open(struct net_device *dev) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = isa_virt_to_bus(skb->tail); + vp->rx_ring[i].addr = isa_virt_to_bus(skb->data); } vp->rx_ring[i - 1].next = isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); @@ -1406,7 +1406,7 @@ static int boomerang_rx(struct net_device *dev) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = isa_virt_to_bus(skb->tail); + vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data); vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 80ec9aa..07746b9 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1802,7 +1802,7 @@ vortex_open(struct net_device *dev) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); + vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } if (i != RX_RING_SIZE) { int j; @@ -2632,7 +2632,7 @@ boomerang_rx(struct net_device *dev) pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), - vp->rx_skbuff[entry]->tail, + vp->rx_skbuff[entry]->data, pkt_len); pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); vp->rx_copy++; @@ -2678,7 +2678,7 @@ boomerang_rx(struct net_device *dev) } skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); + vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index e4b3c5c..7b293f0 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -596,7 +596,7 @@ rx_status_loop: mapping = cp->rx_skb[rx_tail].mapping = - pci_map_single(cp->pdev, new_skb->tail, + pci_map_single(cp->pdev, new_skb->data, buflen, PCI_DMA_FROMDEVICE); cp->rx_skb[rx_tail].skb = new_skb; @@ -1101,7 +1101,7 @@ static int cp_refill_rx (struct cp_private *cp) skb_reserve(skb, RX_OFFSET); cp->rx_skb[i].mapping = pci_map_single(cp->pdev, - skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE); cp->rx_skb[i].skb = skb; cp->rx_ring[i].opts2 = 0; diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 65f97b1..13b745b 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -546,11 +546,11 @@ static inline void init_rx_bufs(struct net_device *dev) rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1)); rbd->b_addr = WSWAPrbd(virt_to_bus(rbd)); rbd->skb = skb; - rbd->v_data = skb->tail; - rbd->b_data = WSWAPchar(virt_to_bus(skb->tail)); + rbd->v_data = skb->data; + rbd->b_data = WSWAPchar(virt_to_bus(skb->data)); rbd->size = PKT_BUF_SZ; #ifdef __mc68000__ - cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ); + cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ); #endif } lp->rbd_head = lp->rbds; @@ -816,10 +816,10 @@ static inline int i596_rx(struct net_device *dev) rx_in_place = 1; rbd->skb = newskb; newskb->dev = dev; - rbd->v_data = newskb->tail; - rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail)); + rbd->v_data = newskb->data; + rbd->b_data = WSWAPchar(virt_to_bus(newskb->data)); #ifdef __mc68000__ - cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ); + cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ); #endif } else @@ -840,7 +840,7 @@ memory_squeeze: skb->protocol=eth_type_trans(skb,dev); skb->len = pkt_len; #ifdef __mc68000__ - cache_clear(virt_to_phys(rbd->skb->tail), + cache_clear(virt_to_phys(rbd->skb->data), pkt_len); #endif netif_rx(skb); diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index b7dd726..8618012 100755 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -87,6 +87,7 @@ Revision History: #include <linux/if_vlan.h> #include <linux/ctype.h> #include <linux/crc32.h> +#include <linux/dma-mapping.h> #include <asm/system.h> #include <asm/io.h> @@ -2006,12 +2007,11 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, } /* Initialize DMA */ - if(!pci_dma_supported(pdev, 0xffffffff)){ + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) < 0) { printk(KERN_ERR "amd8111e: DMA not supported," "exiting.\n"); - goto err_free_reg; - } else - pdev->dma_mask = 0xffffffff; + goto err_free_reg; + } reg_addr = pci_resource_start(pdev, 0); reg_len = pci_resource_len(pdev, 0); diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index b8ab2b6..e613cc2 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -34,10 +34,6 @@ only is it difficult to detect, it also moves around in I/O space in response to inb()s from other device probes! */ -/* - 99/03/03 Allied Telesis RE1000 Plus support by T.Hagawa - 99/12/30 port to 2.3.35 by K.Takai -*/ #include <linux/config.h> #include <linux/errno.h> diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index aa42b7a..430c628 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -547,7 +547,7 @@ rio_timer (unsigned long data) skb_reserve (skb, 2); np->rx_ring[entry].fraginfo = cpu_to_le64 (pci_map_single - (np->pdev, skb->tail, np->rx_buf_sz, + (np->pdev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); } np->rx_ring[entry].fraginfo |= @@ -618,7 +618,7 @@ alloc_list (struct net_device *dev) /* Rubicon now supports 40 bits of addressing space. */ np->rx_ring[i].fraginfo = cpu_to_le64 ( pci_map_single ( - np->pdev, skb->tail, np->rx_buf_sz, + np->pdev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48; } @@ -906,7 +906,7 @@ receive_packet (struct net_device *dev) /* 16 byte align the IP header */ skb_reserve (skb, 2); eth_copy_and_sum (skb, - np->rx_skbuff[entry]->tail, + np->rx_skbuff[entry]->data, pkt_len, 0); skb_put (skb, pkt_len); pci_dma_sync_single_for_device(np->pdev, @@ -950,7 +950,7 @@ receive_packet (struct net_device *dev) skb_reserve (skb, 2); np->rx_ring[entry].fraginfo = cpu_to_le64 (pci_map_single - (np->pdev, skb->tail, np->rx_buf_sz, + (np->pdev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); } np->rx_ring[entry].fraginfo |= diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 1e56c8e..d0fa244 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2447,9 +2447,8 @@ static int e100_resume(struct pci_dev *pdev) #endif -static void e100_shutdown(struct device *dev) +static void e100_shutdown(struct pci_dev *pdev) { - struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct net_device *netdev = pci_get_drvdata(pdev); struct nic *nic = netdev_priv(netdev); @@ -2470,11 +2469,7 @@ static struct pci_driver e100_driver = { .suspend = e100_suspend, .resume = e100_resume, #endif - - .driver = { - .shutdown = e100_shutdown, - } - + .shutdown = e100_shutdown, }; static int __init e100_init_module(void) diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 98b3a2f..1795425 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1269,7 +1269,7 @@ speedo_init_rx_ring(struct net_device *dev) if (skb == NULL) break; /* OK. Just initially short of Rx bufs. */ skb->dev = dev; /* Mark as being used by this device. */ - rxf = (struct RxFD *)skb->tail; + rxf = (struct RxFD *)skb->data; sp->rx_ringp[i] = rxf; sp->rx_ring_dma[i] = pci_map_single(sp->pdev, rxf, @@ -1661,7 +1661,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) sp->rx_ringp[entry] = NULL; return NULL; } - rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail; + rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->data; sp->rx_ring_dma[entry] = pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); @@ -1808,10 +1808,10 @@ speedo_rx(struct net_device *dev) #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ - eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, sp->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); #else - memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail, + memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->data, pkt_len); #endif pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 81ebaed..87f5227 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -1003,7 +1003,7 @@ static void epic_init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev, - skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn); } ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -1274,7 +1274,7 @@ static int epic_rx(struct net_device *dev, int budget) ep->rx_ring[entry].bufaddr, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, ep->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(ep->pci_dev, ep->rx_ring[entry].bufaddr, @@ -1308,7 +1308,7 @@ static int epic_rx(struct net_device *dev, int budget) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev, - skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE); work_done++; } ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn); diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 9e0303f..55dbe9a 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1107,7 +1107,7 @@ static void allocate_rx_buffers(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ np->lack_rxbuf->skbuff = skb; - np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->tail, + np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); np->lack_rxbuf->status = RXOWN; ++np->really_rx_count; @@ -1300,7 +1300,7 @@ static void init_ring(struct net_device *dev) ++np->really_rx_count; np->rx_ring[i].skbuff = skb; skb->dev = dev; /* Mark as being used by this device. */ - np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->tail, + np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); np->rx_ring[i].status = RXOWN; np->rx_ring[i].control |= RXIC; @@ -1737,11 +1737,11 @@ static int netdev_rx(struct net_device *dev) #if ! defined(__alpha__) eth_copy_and_sum(skb, - np->cur_rx->skbuff->tail, pkt_len, 0); + np->cur_rx->skbuff->data, pkt_len, 0); skb_put(skb, pkt_len); #else memcpy(skb_put(skb, pkt_len), - np->cur_rx->skbuff->tail, pkt_len); + np->cur_rx->skbuff->data, pkt_len); #endif pci_dma_sync_single_for_device(np->pci_dev, np->cur_rx->buffer, diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 3d96714..d9df1d9 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1149,7 +1149,7 @@ static void hamachi_tx_timeout(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, - skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); } @@ -1210,7 +1210,7 @@ static void hamachi_init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, - skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); /* -2 because it doesn't REALLY have that first 2 bytes -KDU */ hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz -2)); @@ -1509,7 +1509,7 @@ static int hamachi_rx(struct net_device *dev) desc->addr, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); - buf_addr = (u8 *) hmp->rx_skbuff[entry]->tail; + buf_addr = (u8 *) hmp->rx_skbuff[entry]->data; frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12]))); if (hamachi_debug > 4) printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", @@ -1678,7 +1678,7 @@ static int hamachi_rx(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ desc->addr = cpu_to_leXX(pci_map_single(hmp->pci_dev, - skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE)); } desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz); if (entry >= RX_RING_SIZE-1) @@ -1772,9 +1772,9 @@ static int hamachi_close(struct net_device *dev) readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); if (hamachi_debug > 6) { - if (*(u8*)hmp->rx_skbuff[i]->tail != 0x69) { + if (*(u8*)hmp->rx_skbuff[i]->data != 0x69) { u16 *addr = (u16 *) - hmp->rx_skbuff[i]->tail; + hmp->rx_skbuff[i]->data; int j; for (j = 0; j < 0x50; j++) diff --git a/drivers/net/lance.c b/drivers/net/lance.c index ca90f0d..b4929be 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -862,7 +862,7 @@ lance_init_ring(struct net_device *dev, int gfp) lp->rx_skbuff[i] = skb; if (skb) { skb->dev = dev; - rx_buff = skb->tail; + rx_buff = skb->data; } else rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp); if (rx_buff == NULL) diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index 5e263fc..41bad07 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -553,14 +553,14 @@ static inline void init_rx_bufs(struct net_device *dev) if (skb == NULL) panic("%s: alloc_skb() failed", __FILE__); skb_reserve(skb, 2); - dma_addr = dma_map_single(lp->dev, skb->tail,PKT_BUF_SZ, + dma_addr = dma_map_single(lp->dev, skb->data,PKT_BUF_SZ, DMA_FROM_DEVICE); skb->dev = dev; rbd->v_next = rbd+1; rbd->b_next = WSWAPrbd(virt_to_dma(lp,rbd+1)); rbd->b_addr = WSWAPrbd(virt_to_dma(lp,rbd)); rbd->skb = skb; - rbd->v_data = skb->tail; + rbd->v_data = skb->data; rbd->b_data = WSWAPchar(dma_addr); rbd->size = PKT_BUF_SZ; } @@ -783,8 +783,8 @@ static inline int i596_rx(struct net_device *dev) rx_in_place = 1; rbd->skb = newskb; newskb->dev = dev; - dma_addr = dma_map_single(lp->dev, newskb->tail, PKT_BUF_SZ, DMA_FROM_DEVICE); - rbd->v_data = newskb->tail; + dma_addr = dma_map_single(lp->dev, newskb->data, PKT_BUF_SZ, DMA_FROM_DEVICE); + rbd->v_data = newskb->data; rbd->b_data = WSWAPchar(dma_addr); CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd)); } diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index babb59e..9d6d254 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1926,7 +1926,7 @@ static void refill_rx(struct net_device *dev) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ np->rx_dma[entry] = pci_map_single(np->pci_dev, - skb->tail, buflen, PCI_DMA_FROMDEVICE); + skb->data, buflen, PCI_DMA_FROMDEVICE); np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]); } np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz); @@ -2280,7 +2280,7 @@ static void netdev_rx(struct net_device *dev) buflen, PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, - np->rx_skbuff[entry]->tail, pkt_len, 0); + np->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(np->pci_dev, np->rx_dma[entry], diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index cc796527..e64df4d 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -574,7 +574,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb) dev->rx_info.next_empty = (next_empty + 1) % NR_RX_DESC; cmdsts = REAL_RX_BUF_SIZE | CMDSTS_INTR; - buf = pci_map_single(dev->pci_dev, skb->tail, + buf = pci_map_single(dev->pci_dev, skb->data, REAL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); build_rx_desc(dev, sg, 0, buf, cmdsts, 0); /* update link of previous rx */ @@ -604,7 +604,7 @@ static inline int rx_refill(struct net_device *ndev, int gfp) if (unlikely(!skb)) break; - res = (long)skb->tail & 0xf; + res = (long)skb->data & 0xf; res = 0x10 - res; res &= 0xf; skb_reserve(skb, res); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 3213f3e..113b680 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1602,7 +1602,7 @@ pcnet32_init_ring(struct net_device *dev) rmb(); if (lp->rx_dma_addr[i] == 0) - lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, + lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ); @@ -1983,7 +1983,7 @@ pcnet32_rx(struct net_device *dev) lp->rx_skbuff[entry] = newskb; newskb->dev = dev; lp->rx_dma_addr[entry] = - pci_map_single(lp->pci_dev, newskb->tail, + pci_map_single(lp->pci_dev, newskb->data, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]); rx_in_place = 1; @@ -2020,7 +2020,7 @@ pcnet32_rx(struct net_device *dev) PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, - (unsigned char *)(lp->rx_skbuff[entry]->tail), + (unsigned char *)(lp->rx_skbuff[entry]->data), pkt_len,0); pci_dma_sync_single_for_device(lp->pci_dev, lp->rx_dma_addr[entry], diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index ce449fe..d5afe05 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1876,7 +1876,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, skb_reserve(skb, NET_IP_ALIGN); *sk_buff = skb; - mapping = pci_map_single(pdev, skb->tail, rx_buf_sz, + mapping = pci_map_single(pdev, skb->data, rx_buf_sz, PCI_DMA_FROMDEVICE); rtl8169_map_to_asic(desc, mapping, rx_buf_sz); @@ -2336,7 +2336,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN); if (skb) { skb_reserve(skb, NET_IP_ALIGN); - eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0); + eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0); *sk_buff = skb; rtl8169_mark_to_asic(desc, rx_buf_sz); ret = 0; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index bb639a8..ea638b1 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -1699,11 +1699,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) #else ba = &nic->ba[ring_no][block_no][off]; skb_reserve(skb, BUF0_LEN); - tmp = (unsigned long) skb->data; - tmp += ALIGN_SIZE; - tmp &= ~ALIGN_SIZE; - skb->data = (void *) tmp; - skb->tail = (void *) tmp; + tmp = ((unsigned long) skb->data & ALIGN_SIZE); + if (tmp) + skb_reserve(skb, (ALIGN_SIZE + 1) - tmp); memset(rxdp, 0, sizeof(RxD_t)); rxdp->Buffer2_ptr = pci_map_single diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index fd2e7c3..7abd55a 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -963,11 +963,11 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb) /* * Do not interrupt per DMA transfer. */ - dsc->dscr_a = virt_to_phys(sb_new->tail) | + dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | 0; #else - dsc->dscr_a = virt_to_phys(sb_new->tail) | + dsc->dscr_a = virt_to_phys(sb_new->data) | V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) | M_DMA_DSCRA_INTERRUPT; #endif diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 127324f..23b713c 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1154,7 +1154,7 @@ sis900_init_rx_ring(struct net_device *net_dev) sis_priv->rx_skbuff[i] = skb; sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev, - skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); } sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC); @@ -1776,7 +1776,7 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_skbuff[entry] = skb; sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[entry].bufptr = - pci_map_single(sis_priv->pci_dev, skb->tail, + pci_map_single(sis_priv->pci_dev, skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); sis_priv->dirty_rx++; } @@ -1809,7 +1809,7 @@ static int sis900_rx(struct net_device *net_dev) sis_priv->rx_skbuff[entry] = skb; sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE; sis_priv->rx_ring[entry].bufptr = - pci_map_single(sis_priv->pci_dev, skb->tail, + pci_map_single(sis_priv->pci_dev, skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); } } diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 30e8d58..3dbb1cb 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -7,7 +7,7 @@ * of the original driver such as link fail-over and link management because * those should be done at higher levels. * - * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org> + * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.org> * * 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 @@ -42,19 +42,20 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "0.6" +#define DRV_VERSION "0.7" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 #define DEFAULT_RX_RING_SIZE 512 #define MAX_TX_RING_SIZE 1024 #define MAX_RX_RING_SIZE 4096 +#define RX_COPY_THRESHOLD 128 +#define RX_BUF_SIZE 1536 #define PHY_RETRIES 1000 #define ETH_JUMBO_MTU 9000 #define TX_WATCHDOG (5 * HZ) #define NAPI_WEIGHT 64 #define BLINK_HZ (HZ/4) -#define LINK_POLL_HZ (HZ/10) MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>"); @@ -70,28 +71,17 @@ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); static const struct pci_device_id skge_id_table[] = { - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_SYSKONNECT, 0x9E00, /* SK-9Exx */ - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_MARVELL, 0x4320, /* Gigabit Ethernet Controller */ - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_MARVELL, 0x5005, /* Marvell (11ab), Belkin */ - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064, - PCI_ANY_ID, PCI_ANY_ID }, + { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940) }, + { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) }, + { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, + { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) }, + { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */ + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ + { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, + { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) }, + { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) }, { 0 } }; MODULE_DEVICE_TABLE(pci, skge_id_table); @@ -99,19 +89,22 @@ MODULE_DEVICE_TABLE(pci, skge_id_table); static int skge_up(struct net_device *dev); static int skge_down(struct net_device *dev); static void skge_tx_clean(struct skge_port *skge); -static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); -static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); +static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); +static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); static void genesis_get_stats(struct skge_port *skge, u64 *data); static void yukon_get_stats(struct skge_port *skge, u64 *data); static void yukon_init(struct skge_hw *hw, int port); static void yukon_reset(struct skge_hw *hw, int port); static void genesis_mac_init(struct skge_hw *hw, int port); static void genesis_reset(struct skge_hw *hw, int port); +static void genesis_link_up(struct skge_port *skge); +/* Avoid conditionals by using array */ static const int txqaddr[] = { Q_XA1, Q_XA2 }; static const int rxqaddr[] = { Q_R1, Q_R2 }; static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F }; static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F }; +static const u32 portirqmask[] = { IS_PORT_1, IS_PORT_2 }; /* Don't need to look at whole 16K. * last interesting register is descriptor poll timer. @@ -154,7 +147,7 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs, static int wol_supported(const struct skge_hw *hw) { return !((hw->chip_id == CHIP_ID_GENESIS || - (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0))); + (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0))); } static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) @@ -170,7 +163,7 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; - if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) return -EOPNOTSUPP; if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw)) @@ -190,6 +183,36 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return 0; } +/* Determine supported/adverised modes based on hardware. + * Note: ethtoool ADVERTISED_xxx == SUPPORTED_xxx + */ +static u32 skge_supported_modes(const struct skge_hw *hw) +{ + u32 supported; + + if (iscopper(hw)) { + supported = SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full + | SUPPORTED_Autoneg| SUPPORTED_TP; + + if (hw->chip_id == CHIP_ID_GENESIS) + supported &= ~(SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full); + + else if (hw->chip_id == CHIP_ID_YUKON) + supported &= ~SUPPORTED_1000baseT_Half; + } else + supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE + | SUPPORTED_Autoneg; + + return supported; +} static int skge_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) @@ -198,38 +221,13 @@ static int skge_get_settings(struct net_device *dev, struct skge_hw *hw = skge->hw; ecmd->transceiver = XCVR_INTERNAL; + ecmd->supported = skge_supported_modes(hw); if (iscopper(hw)) { - if (hw->chip_id == CHIP_ID_GENESIS) - ecmd->supported = SUPPORTED_1000baseT_Full - | SUPPORTED_1000baseT_Half - | SUPPORTED_Autoneg | SUPPORTED_TP; - else { - ecmd->supported = SUPPORTED_10baseT_Half - | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half - | SUPPORTED_100baseT_Full - | SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full - | SUPPORTED_Autoneg| SUPPORTED_TP; - - if (hw->chip_id == CHIP_ID_YUKON) - ecmd->supported &= ~SUPPORTED_1000baseT_Half; - - else if (hw->chip_id == CHIP_ID_YUKON_FE) - ecmd->supported &= ~(SUPPORTED_1000baseT_Half - | SUPPORTED_1000baseT_Full); - } - ecmd->port = PORT_TP; ecmd->phy_address = hw->phy_addr; - } else { - ecmd->supported = SUPPORTED_1000baseT_Full - | SUPPORTED_FIBRE - | SUPPORTED_Autoneg; - + } else ecmd->port = PORT_FIBRE; - } ecmd->advertising = skge->advertising; ecmd->autoneg = skge->autoneg; @@ -238,65 +236,57 @@ static int skge_get_settings(struct net_device *dev, return 0; } -static u32 skge_modes(const struct skge_hw *hw) -{ - u32 modes = ADVERTISED_Autoneg - | ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half - | ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half - | ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half; - - if (iscopper(hw)) { - modes |= ADVERTISED_TP; - switch(hw->chip_id) { - case CHIP_ID_GENESIS: - modes &= ~(ADVERTISED_100baseT_Full - | ADVERTISED_100baseT_Half - | ADVERTISED_10baseT_Full - | ADVERTISED_10baseT_Half); - break; - - case CHIP_ID_YUKON: - modes &= ~ADVERTISED_1000baseT_Half; - break; - - case CHIP_ID_YUKON_FE: - modes &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full); - break; - } - } else { - modes |= ADVERTISED_FIBRE; - modes &= ~ADVERTISED_1000baseT_Half; - } - return modes; -} - static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { struct skge_port *skge = netdev_priv(dev); const struct skge_hw *hw = skge->hw; + u32 supported = skge_supported_modes(hw); if (ecmd->autoneg == AUTONEG_ENABLE) { - if (ecmd->advertising & skge_modes(hw)) - return -EINVAL; + ecmd->advertising = supported; + skge->duplex = -1; + skge->speed = -1; } else { + u32 setting; + switch(ecmd->speed) { case SPEED_1000: - if (hw->chip_id == CHIP_ID_YUKON_FE) + if (ecmd->duplex == DUPLEX_FULL) + setting = SUPPORTED_1000baseT_Full; + else if (ecmd->duplex == DUPLEX_HALF) + setting = SUPPORTED_1000baseT_Half; + else return -EINVAL; break; case SPEED_100: + if (ecmd->duplex == DUPLEX_FULL) + setting = SUPPORTED_100baseT_Full; + else if (ecmd->duplex == DUPLEX_HALF) + setting = SUPPORTED_100baseT_Half; + else + return -EINVAL; + break; + case SPEED_10: - if (iscopper(hw) || hw->chip_id == CHIP_ID_GENESIS) + if (ecmd->duplex == DUPLEX_FULL) + setting = SUPPORTED_10baseT_Full; + else if (ecmd->duplex == DUPLEX_HALF) + setting = SUPPORTED_10baseT_Half; + else return -EINVAL; break; default: return -EINVAL; } + + if ((setting & supported) == 0) + return -EINVAL; + + skge->speed = ecmd->speed; + skge->duplex = ecmd->duplex; } skge->autoneg = ecmd->autoneg; - skge->speed = ecmd->speed; - skge->duplex = ecmd->duplex; skge->advertising = ecmd->advertising; if (netif_running(dev)) { @@ -393,7 +383,7 @@ static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data) { int i; - switch(stringset) { + switch (stringset) { case ETH_SS_STATS: for (i = 0; i < ARRAY_SIZE(skge_stats); i++) memcpy(data + i * ETH_GSTRING_LEN, @@ -511,14 +501,6 @@ static int skge_set_rx_csum(struct net_device *dev, u32 data) return 0; } -/* Only Yukon II supports TSO (not implemented yet) */ -static int skge_set_tso(struct net_device *dev, u32 data) -{ - if (data) - return -EOPNOTSUPP; - return 0; -} - static void skge_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd) { @@ -540,9 +522,9 @@ static int skge_set_pauseparam(struct net_device *dev, skge->autoneg = ecmd->autoneg; if (ecmd->rx_pause && ecmd->tx_pause) skge->flow_control = FLOW_MODE_SYMMETRIC; - else if(ecmd->rx_pause && !ecmd->tx_pause) + else if (ecmd->rx_pause && !ecmd->tx_pause) skge->flow_control = FLOW_MODE_REM_SEND; - else if(!ecmd->rx_pause && ecmd->tx_pause) + else if (!ecmd->rx_pause && ecmd->tx_pause) skge->flow_control = FLOW_MODE_LOC_SEND; else skge->flow_control = FLOW_MODE_NONE; @@ -559,8 +541,6 @@ static inline u32 hwkhz(const struct skge_hw *hw) { if (hw->chip_id == CHIP_ID_GENESIS) return 53215; /* or: 53.125 MHz */ - else if (hw->chip_id == CHIP_ID_YUKON_EC) - return 125000; /* or: 125.000 MHz */ else return 78215; /* or: 78.125 MHz */ } @@ -643,30 +623,18 @@ static int skge_set_coalesce(struct net_device *dev, static void skge_led_on(struct skge_hw *hw, int port) { if (hw->chip_id == CHIP_ID_GENESIS) { - skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON); + skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON); skge_write8(hw, B0_LED, LED_STAT_ON); - skge_write8(hw, SKGEMAC_REG(port, RX_LED_TST), LED_T_ON); - skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 100); - skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START); + skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON); + skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); + skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); - switch (hw->phy_type) { - case SK_PHY_BCOM: - skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, - PHY_B_PEC_LED_ON); - break; - case SK_PHY_LONE: - skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG, - 0x0800); - break; - default: - skge_write8(hw, SKGEMAC_REG(port, TX_LED_TST), LED_T_ON); - skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 100); - skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START); - } + /* For Broadcom Phy only */ + xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); } else { - skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); - skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, + gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); + gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_DUP(MO_LED_ON) | PHY_M_LED_MO_10(MO_LED_ON) | PHY_M_LED_MO_100(MO_LED_ON) | @@ -678,28 +646,17 @@ static void skge_led_on(struct skge_hw *hw, int port) static void skge_led_off(struct skge_hw *hw, int port) { if (hw->chip_id == CHIP_ID_GENESIS) { - skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_OFF); + skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); skge_write8(hw, B0_LED, LED_STAT_OFF); - skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 0); - skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_T_OFF); + skge_write32(hw, SK_REG(port, RX_LED_VAL), 0); + skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF); - switch (hw->phy_type) { - case SK_PHY_BCOM: - skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, - PHY_B_PEC_LED_OFF); - break; - case SK_PHY_LONE: - skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG, - PHY_L_LC_LEDT); - break; - default: - skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 0); - skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_T_OFF); - } + /* Broadcom only */ + xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); } else { - skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); - skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, + gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); + gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_DUP(MO_LED_OFF) | PHY_M_LED_MO_10(MO_LED_OFF) | PHY_M_LED_MO_100(MO_LED_OFF) | @@ -730,7 +687,7 @@ static int skge_phys_id(struct net_device *dev, u32 data) { struct skge_port *skge = netdev_priv(dev); - if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); /* start blinking */ @@ -763,8 +720,6 @@ static struct ethtool_ops skge_ethtool_ops = { .set_pauseparam = skge_set_pauseparam, .get_coalesce = skge_get_coalesce, .set_coalesce = skge_set_coalesce, - .get_tso = ethtool_op_get_tso, - .set_tso = skge_set_tso, .get_sg = ethtool_op_get_sg, .set_sg = skge_set_sg, .get_tx_csum = ethtool_op_get_tx_csum, @@ -793,6 +748,7 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base) for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) { e->desc = d; + e->skb = NULL; if (i == ring->count - 1) { e->next = ring->start; d->next_offset = base; @@ -806,24 +762,23 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base) return 0; } -/* Setup buffer for receiving */ -static inline int skge_rx_alloc(struct skge_port *skge, - struct skge_element *e) +static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size) { - unsigned long bufsize = skge->netdev->mtu + ETH_HLEN; /* VLAN? */ - struct skge_rx_desc *rd = e->desc; - struct sk_buff *skb; - u64 map; + struct sk_buff *skb = dev_alloc_skb(size); - skb = dev_alloc_skb(bufsize + NET_IP_ALIGN); - if (unlikely(!skb)) { - printk(KERN_DEBUG PFX "%s: out of memory for receive\n", - skge->netdev->name); - return -ENOMEM; + if (likely(skb)) { + skb->dev = dev; + skb_reserve(skb, NET_IP_ALIGN); } + return skb; +} - skb->dev = skge->netdev; - skb_reserve(skb, NET_IP_ALIGN); +/* Allocate and setup a new buffer for receiving */ +static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, + struct sk_buff *skb, unsigned int bufsize) +{ + struct skge_rx_desc *rd = e->desc; + u64 map; map = pci_map_single(skge->hw->pdev, skb->data, bufsize, PCI_DMA_FROMDEVICE); @@ -841,55 +796,69 @@ static inline int skge_rx_alloc(struct skge_port *skge, rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize; pci_unmap_addr_set(e, mapaddr, map); pci_unmap_len_set(e, maplen, bufsize); - return 0; } -/* Free all unused buffers in receive ring, assumes receiver stopped */ +/* Resume receiving using existing skb, + * Note: DMA address is not changed by chip. + * MTU not changed while receiver active. + */ +static void skge_rx_reuse(struct skge_element *e, unsigned int size) +{ + struct skge_rx_desc *rd = e->desc; + + rd->csum2 = 0; + rd->csum2_start = ETH_HLEN; + + wmb(); + + rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size; +} + + +/* Free all buffers in receive ring, assumes receiver stopped */ static void skge_rx_clean(struct skge_port *skge) { struct skge_hw *hw = skge->hw; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - for (e = ring->to_clean; e != ring->to_use; e = e->next) { + e = ring->start; + do { struct skge_rx_desc *rd = e->desc; rd->control = 0; - - pci_unmap_single(hw->pdev, - pci_unmap_addr(e, mapaddr), - pci_unmap_len(e, maplen), - PCI_DMA_FROMDEVICE); - dev_kfree_skb(e->skb); - e->skb = NULL; - } - ring->to_clean = e; + if (e->skb) { + pci_unmap_single(hw->pdev, + pci_unmap_addr(e, mapaddr), + pci_unmap_len(e, maplen), + PCI_DMA_FROMDEVICE); + dev_kfree_skb(e->skb); + e->skb = NULL; + } + } while ((e = e->next) != ring->start); } + /* Allocate buffers for receive ring - * For receive: to_use is refill location - * to_clean is next received frame. - * - * if (to_use == to_clean) - * then ring all frames in ring need buffers - * if (to_use->next == to_clean) - * then ring all frames in ring have buffers + * For receive: to_clean is next received frame. */ static int skge_rx_fill(struct skge_port *skge) { struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - int ret = 0; + unsigned int bufsize = skge->rx_buf_size; - for (e = ring->to_use; e->next != ring->to_clean; e = e->next) { - if (skge_rx_alloc(skge, e)) { - ret = 1; - break; - } + e = ring->start; + do { + struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize); - } - ring->to_use = e; + if (!skb) + return -ENOMEM; + + skge_rx_setup(skge, e, skb, bufsize); + } while ( (e = e->next) != ring->start); - return ret; + ring->to_clean = ring->start; + return 0; } static void skge_link_up(struct skge_port *skge) @@ -919,50 +888,50 @@ static void skge_link_down(struct skge_port *skge) printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); } -static u16 skge_xm_phy_read(struct skge_hw *hw, int port, u16 reg) +static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg) { int i; u16 v; - skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); - v = skge_xm_read16(hw, port, XM_PHY_DATA); - if (hw->phy_type != SK_PHY_XMAC) { - for (i = 0; i < PHY_RETRIES; i++) { - udelay(1); - if (skge_xm_read16(hw, port, XM_MMU_CMD) - & XM_MMU_PHY_RDY) - goto ready; - } + xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); + v = xm_read16(hw, port, XM_PHY_DATA); - printk(KERN_WARNING PFX "%s: phy read timed out\n", - hw->dev[port]->name); - return 0; - ready: - v = skge_xm_read16(hw, port, XM_PHY_DATA); + /* Need to wait for external PHY */ + for (i = 0; i < PHY_RETRIES; i++) { + udelay(1); + if (xm_read16(hw, port, XM_MMU_CMD) + & XM_MMU_PHY_RDY) + goto ready; } + printk(KERN_WARNING PFX "%s: phy read timed out\n", + hw->dev[port]->name); + return 0; + ready: + v = xm_read16(hw, port, XM_PHY_DATA); + return v; } -static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) +static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) { int i; - skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); + xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); for (i = 0; i < PHY_RETRIES; i++) { - if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) + if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) goto ready; - cpu_relax(); + udelay(1); } printk(KERN_WARNING PFX "%s: phy write failed to come ready\n", hw->dev[port]->name); ready: - skge_xm_write16(hw, port, XM_PHY_DATA, val); + xm_write16(hw, port, XM_PHY_DATA, val); for (i = 0; i < PHY_RETRIES; i++) { udelay(1); - if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) + if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) return; } printk(KERN_WARNING PFX "%s: phy write timed out\n", @@ -999,34 +968,112 @@ static void genesis_init(struct skge_hw *hw) static void genesis_reset(struct skge_hw *hw, int port) { - int i; - u64 zero = 0; + const u8 zero[8] = { 0 }; /* reset the statistics module */ - skge_xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); - skge_xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ - skge_xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ - skge_xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ - skge_xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ + xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); + xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ + xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ + xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ + xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ - /* disable all PHY IRQs */ - if (hw->phy_type == SK_PHY_BCOM) - skge_xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); + /* disable Broadcom PHY IRQ */ + xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); - skge_xm_outhash(hw, port, XM_HSM, (u8 *) &zero); - for (i = 0; i < 15; i++) - skge_xm_outaddr(hw, port, XM_EXM(i), (u8 *) &zero); - skge_xm_outhash(hw, port, XM_SRC_CHK, (u8 *) &zero); + xm_outhash(hw, port, XM_HSM, zero); } -static void genesis_mac_init(struct skge_hw *hw, int port) +/* Convert mode to MII values */ +static const u16 phy_pause_map[] = { + [FLOW_MODE_NONE] = 0, + [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, + [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, + [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, +}; + + +/* Check status of Broadcom phy link */ +static void bcom_check_link(struct skge_hw *hw, int port) { - struct skge_port *skge = netdev_priv(hw->dev[port]); + struct net_device *dev = hw->dev[port]; + struct skge_port *skge = netdev_priv(dev); + u16 status; + + /* read twice because of latch */ + (void) xm_phy_read(hw, port, PHY_BCOM_STAT); + status = xm_phy_read(hw, port, PHY_BCOM_STAT); + + pr_debug("bcom_check_link status=0x%x\n", status); + + if ((status & PHY_ST_LSYNC) == 0) { + u16 cmd = xm_read16(hw, port, XM_MMU_CMD); + cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); + xm_write16(hw, port, XM_MMU_CMD, cmd); + /* dummy read to ensure writing */ + (void) xm_read16(hw, port, XM_MMU_CMD); + + if (netif_carrier_ok(dev)) + skge_link_down(skge); + } else { + if (skge->autoneg == AUTONEG_ENABLE && + (status & PHY_ST_AN_OVER)) { + u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP); + u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); + + if (lpa & PHY_B_AN_RF) { + printk(KERN_NOTICE PFX "%s: remote fault\n", + dev->name); + return; + } + + /* Check Duplex mismatch */ + switch(aux & PHY_B_AS_AN_RES_MSK) { + case PHY_B_RES_1000FD: + skge->duplex = DUPLEX_FULL; + break; + case PHY_B_RES_1000HD: + skge->duplex = DUPLEX_HALF; + break; + default: + printk(KERN_NOTICE PFX "%s: duplex mismatch\n", + dev->name); + return; + } + + + /* We are using IEEE 802.3z/D5.0 Table 37-4 */ + switch (aux & PHY_B_AS_PAUSE_MSK) { + case PHY_B_AS_PAUSE_MSK: + skge->flow_control = FLOW_MODE_SYMMETRIC; + break; + case PHY_B_AS_PRR: + skge->flow_control = FLOW_MODE_REM_SEND; + break; + case PHY_B_AS_PRT: + skge->flow_control = FLOW_MODE_LOC_SEND; + break; + default: + skge->flow_control = FLOW_MODE_NONE; + } + + skge->speed = SPEED_1000; + } + + if (!netif_carrier_ok(dev)) + genesis_link_up(skge); + } +} + +/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional + * Phy on for 100 or 10Mbit operation + */ +static void bcom_phy_init(struct skge_port *skge, int jumbo) +{ + struct skge_hw *hw = skge->hw; + int port = skge->port; int i; - u32 r; - u16 id1; - u16 ctrl1, ctrl2, ctrl3, ctrl4, ctrl5; + u16 id1, r, ext, ctl; /* magic workaround patterns for Broadcom */ static const struct { @@ -1042,16 +1089,120 @@ static void genesis_mac_init(struct skge_hw *hw, int port) { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 }, }; + pr_debug("bcom_phy_init\n"); + + /* read Id from external PHY (all have the same address) */ + id1 = xm_phy_read(hw, port, PHY_XMAC_ID1); + + /* Optimize MDIO transfer by suppressing preamble. */ + r = xm_read16(hw, port, XM_MMU_CMD); + r |= XM_MMU_NO_PRE; + xm_write16(hw, port, XM_MMU_CMD,r); + + switch(id1) { + case PHY_BCOM_ID1_C0: + /* + * Workaround BCOM Errata for the C0 type. + * Write magic patterns to reserved registers. + */ + for (i = 0; i < ARRAY_SIZE(C0hack); i++) + xm_phy_write(hw, port, + C0hack[i].reg, C0hack[i].val); + + break; + case PHY_BCOM_ID1_A1: + /* + * Workaround BCOM Errata for the A1 type. + * Write magic patterns to reserved registers. + */ + for (i = 0; i < ARRAY_SIZE(A1hack); i++) + xm_phy_write(hw, port, + A1hack[i].reg, A1hack[i].val); + break; + } + + /* + * Workaround BCOM Errata (#10523) for all BCom PHYs. + * Disable Power Management after reset. + */ + r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL); + r |= PHY_B_AC_DIS_PM; + xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r); + + /* Dummy read */ + xm_read16(hw, port, XM_ISRC); + + ext = PHY_B_PEC_EN_LTR; /* enable tx led */ + ctl = PHY_CT_SP1000; /* always 1000mbit */ + + if (skge->autoneg == AUTONEG_ENABLE) { + /* + * Workaround BCOM Errata #1 for the C5 type. + * 1000Base-T Link Acquisition Failure in Slave Mode + * Set Repeater/DTE bit 10 of the 1000Base-T Control Register + */ + u16 adv = PHY_B_1000C_RD; + if (skge->advertising & ADVERTISED_1000baseT_Half) + adv |= PHY_B_1000C_AHD; + if (skge->advertising & ADVERTISED_1000baseT_Full) + adv |= PHY_B_1000C_AFD; + xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, adv); + + ctl |= PHY_CT_ANE | PHY_CT_RE_CFG; + } else { + if (skge->duplex == DUPLEX_FULL) + ctl |= PHY_CT_DUP_MD; + /* Force to slave */ + xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, PHY_B_1000C_MSE); + } + + /* Set autonegotiation pause parameters */ + xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, + phy_pause_map[skge->flow_control] | PHY_AN_CSMA); + + /* Handle Jumbo frames */ + if (jumbo) { + xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, + PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK); + + ext |= PHY_B_PEC_HIGH_LA; + + } + + xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext); + xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl); + + /* Use link status change interrrupt */ + xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); + + bcom_check_link(hw, port); +} + +static void genesis_mac_init(struct skge_hw *hw, int port) +{ + struct net_device *dev = hw->dev[port]; + struct skge_port *skge = netdev_priv(dev); + int jumbo = hw->dev[port]->mtu > ETH_DATA_LEN; + int i; + u32 r; + const u8 zero[6] = { 0 }; + + /* Clear MIB counters */ + xm_write16(hw, port, XM_STAT_CMD, + XM_SC_CLR_RXC | XM_SC_CLR_TXC); + /* Clear two times according to Errata #3 */ + xm_write16(hw, port, XM_STAT_CMD, + XM_SC_CLR_RXC | XM_SC_CLR_TXC); /* initialize Rx, Tx and Link LED */ - skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON); - skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON); + skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON); + skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON); - skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START); - skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START); + skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); + skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); /* Unreset the XMAC. */ - skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); + skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); /* * Perform additional initialization for external PHYs, @@ -1059,67 +1210,56 @@ static void genesis_mac_init(struct skge_hw *hw, int port) * GMII mode. */ spin_lock_bh(&hw->phy_lock); - if (hw->phy_type != SK_PHY_XMAC) { - /* Take PHY out of reset. */ - r = skge_read32(hw, B2_GP_IO); - if (port == 0) - r |= GP_DIR_0|GP_IO_0; - else - r |= GP_DIR_2|GP_IO_2; - - skge_write32(hw, B2_GP_IO, r); - skge_read32(hw, B2_GP_IO); - - /* Enable GMII mode on the XMAC. */ - skge_xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); - - id1 = skge_xm_phy_read(hw, port, PHY_XMAC_ID1); - - /* Optimize MDIO transfer by suppressing preamble. */ - skge_xm_write16(hw, port, XM_MMU_CMD, - skge_xm_read16(hw, port, XM_MMU_CMD) - | XM_MMU_NO_PRE); - - if (id1 == PHY_BCOM_ID1_C0) { - /* - * Workaround BCOM Errata for the C0 type. - * Write magic patterns to reserved registers. - */ - for (i = 0; i < ARRAY_SIZE(C0hack); i++) - skge_xm_phy_write(hw, port, - C0hack[i].reg, C0hack[i].val); - - } else if (id1 == PHY_BCOM_ID1_A1) { - /* - * Workaround BCOM Errata for the A1 type. - * Write magic patterns to reserved registers. - */ - for (i = 0; i < ARRAY_SIZE(A1hack); i++) - skge_xm_phy_write(hw, port, - A1hack[i].reg, A1hack[i].val); - } + /* Take external Phy out of reset */ + r = skge_read32(hw, B2_GP_IO); + if (port == 0) + r |= GP_DIR_0|GP_IO_0; + else + r |= GP_DIR_2|GP_IO_2; - /* - * Workaround BCOM Errata (#10523) for all BCom PHYs. - * Disable Power Management after reset. - */ - r = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL); - skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r | PHY_B_AC_DIS_PM); - } + skge_write32(hw, B2_GP_IO, r); + skge_read32(hw, B2_GP_IO); + spin_unlock_bh(&hw->phy_lock); - /* Dummy read */ - skge_xm_read16(hw, port, XM_ISRC); + /* Enable GMII interfac */ + xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); + + bcom_phy_init(skge, jumbo); + + /* Set Station Address */ + xm_outaddr(hw, port, XM_SA, dev->dev_addr); + + /* We don't use match addresses so clear */ + for (i = 1; i < 16; i++) + xm_outaddr(hw, port, XM_EXM(i), zero); - r = skge_xm_read32(hw, port, XM_MODE); - skge_xm_write32(hw, port, XM_MODE, r|XM_MD_CSA); + /* configure Rx High Water Mark (XM_RX_HI_WM) */ + xm_write16(hw, port, XM_RX_HI_WM, 1450); /* We don't need the FCS appended to the packet. */ - r = skge_xm_read16(hw, port, XM_RX_CMD); - skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_STRIP_FCS); + r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS; + if (jumbo) + r |= XM_RX_BIG_PK_OK; + + if (skge->duplex == DUPLEX_HALF) { + /* + * If in manual half duplex mode the other side might be in + * full duplex mode, so ignore if a carrier extension is not seen + * on frames received + */ + r |= XM_RX_DIS_CEXT; + } + xm_write16(hw, port, XM_RX_CMD, r); + /* We want short frames padded to 60 bytes. */ - r = skge_xm_read16(hw, port, XM_TX_CMD); - skge_xm_write16(hw, port, XM_TX_CMD, r | XM_TX_AUTO_PAD); + xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD); + + /* + * Bump up the transmit threshold. This helps hold off transmit + * underruns when we're blasting traffic from both ports at once. + */ + xm_write16(hw, port, XM_TX_THR, 512); /* * Enable the reception of all error frames. This is is @@ -1135,19 +1275,22 @@ static void genesis_mac_init(struct skge_hw *hw, int port) * case the XMAC will start transfering frames out of the * RX FIFO as soon as the FIFO threshold is reached. */ - r = skge_xm_read32(hw, port, XM_MODE); - skge_xm_write32(hw, port, XM_MODE, - XM_MD_RX_CRCE|XM_MD_RX_LONG|XM_MD_RX_RUNT| - XM_MD_RX_ERR|XM_MD_RX_IRLE); + xm_write32(hw, port, XM_MODE, XM_DEF_MODE); - skge_xm_outaddr(hw, port, XM_SA, hw->dev[port]->dev_addr); - skge_xm_outaddr(hw, port, XM_EXM(0), hw->dev[port]->dev_addr); /* - * Bump up the transmit threshold. This helps hold off transmit - * underruns when we're blasting traffic from both ports at once. + * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK) + * - Enable all bits excepting 'Octets Rx OK Low CntOv' + * and 'Octets Rx OK Hi Cnt Ov'. */ - skge_xm_write16(hw, port, XM_TX_THR, 512); + xm_write32(hw, port, XM_RX_EV_MSK, XMR_DEF_MSK); + + /* + * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK) + * - Enable all bits excepting 'Octets Tx OK Low CntOv' + * and 'Octets Tx OK Hi Cnt Ov'. + */ + xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK); /* Configure MAC arbiter */ skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR); @@ -1164,137 +1307,30 @@ static void genesis_mac_init(struct skge_hw *hw, int port) skge_write8(hw, B3_MA_RCINI_TX2, 0); /* Configure Rx MAC FIFO */ - skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_CLR); - skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT); - skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD); + skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_CLR); + skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT); + skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD); /* Configure Tx MAC FIFO */ - skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_CLR); - skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF); - skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD); + skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_CLR); + skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF); + skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD); - if (hw->dev[port]->mtu > ETH_DATA_LEN) { + if (jumbo) { /* Enable frame flushing if jumbo frames used */ - skge_write16(hw, SKGEMAC_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH); + skge_write16(hw, SK_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH); } else { /* enable timeout timers if normal frames */ skge_write16(hw, B3_PA_CTRL, - port == 0 ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2); + (port == 0) ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2); } - - - r = skge_xm_read16(hw, port, XM_RX_CMD); - if (hw->dev[port]->mtu > ETH_DATA_LEN) - skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_BIG_PK_OK); - else - skge_xm_write16(hw, port, XM_RX_CMD, r & ~(XM_RX_BIG_PK_OK)); - - switch (hw->phy_type) { - case SK_PHY_XMAC: - if (skge->autoneg == AUTONEG_ENABLE) { - ctrl1 = PHY_X_AN_FD | PHY_X_AN_HD; - - switch (skge->flow_control) { - case FLOW_MODE_NONE: - ctrl1 |= PHY_X_P_NO_PAUSE; - break; - case FLOW_MODE_LOC_SEND: - ctrl1 |= PHY_X_P_ASYM_MD; - break; - case FLOW_MODE_SYMMETRIC: - ctrl1 |= PHY_X_P_SYM_MD; - break; - case FLOW_MODE_REM_SEND: - ctrl1 |= PHY_X_P_BOTH_MD; - break; - } - - skge_xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl1); - ctrl2 = PHY_CT_ANE | PHY_CT_RE_CFG; - } else { - ctrl2 = 0; - if (skge->duplex == DUPLEX_FULL) - ctrl2 |= PHY_CT_DUP_MD; - } - - skge_xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl2); - break; - - case SK_PHY_BCOM: - ctrl1 = PHY_CT_SP1000; - ctrl2 = 0; - ctrl3 = PHY_SEL_TYPE; - ctrl4 = PHY_B_PEC_EN_LTR; - ctrl5 = PHY_B_AC_TX_TST; - - if (skge->autoneg == AUTONEG_ENABLE) { - /* - * Workaround BCOM Errata #1 for the C5 type. - * 1000Base-T Link Acquisition Failure in Slave Mode - * Set Repeater/DTE bit 10 of the 1000Base-T Control Register - */ - ctrl2 |= PHY_B_1000C_RD; - if (skge->advertising & ADVERTISED_1000baseT_Half) - ctrl2 |= PHY_B_1000C_AHD; - if (skge->advertising & ADVERTISED_1000baseT_Full) - ctrl2 |= PHY_B_1000C_AFD; - - /* Set Flow-control capabilities */ - switch (skge->flow_control) { - case FLOW_MODE_NONE: - ctrl3 |= PHY_B_P_NO_PAUSE; - break; - case FLOW_MODE_LOC_SEND: - ctrl3 |= PHY_B_P_ASYM_MD; - break; - case FLOW_MODE_SYMMETRIC: - ctrl3 |= PHY_B_P_SYM_MD; - break; - case FLOW_MODE_REM_SEND: - ctrl3 |= PHY_B_P_BOTH_MD; - break; - } - - /* Restart Auto-negotiation */ - ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG; - } else { - if (skge->duplex == DUPLEX_FULL) - ctrl1 |= PHY_CT_DUP_MD; - - ctrl2 |= PHY_B_1000C_MSE; /* set it to Slave */ - } - - skge_xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, ctrl2); - skge_xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, ctrl3); - - if (skge->netdev->mtu > ETH_DATA_LEN) { - ctrl4 |= PHY_B_PEC_HIGH_LA; - ctrl5 |= PHY_B_AC_LONG_PACK; - - skge_xm_phy_write(hw, port,PHY_BCOM_AUX_CTRL, ctrl5); - } - - skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ctrl4); - skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl1); - break; - } - spin_unlock_bh(&hw->phy_lock); - - /* Clear MIB counters */ - skge_xm_write16(hw, port, XM_STAT_CMD, - XM_SC_CLR_RXC | XM_SC_CLR_TXC); - /* Clear two times according to Errata #3 */ - skge_xm_write16(hw, port, XM_STAT_CMD, - XM_SC_CLR_RXC | XM_SC_CLR_TXC); - - /* Start polling for link status */ - mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); } static void genesis_stop(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; + u32 reg; /* Clear Tx packet arbiter timeout IRQ */ skge_write16(hw, B3_PA_CTRL, @@ -1304,33 +1340,30 @@ static void genesis_stop(struct skge_port *skge) * If the transfer stucks at the MAC the STOP command will not * terminate if we don't flush the XMAC's transmit FIFO ! */ - skge_xm_write32(hw, port, XM_MODE, - skge_xm_read32(hw, port, XM_MODE)|XM_MD_FTF); + xm_write32(hw, port, XM_MODE, + xm_read32(hw, port, XM_MODE)|XM_MD_FTF); /* Reset the MAC */ - skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); + skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); /* For external PHYs there must be special handling */ - if (hw->phy_type != SK_PHY_XMAC) { - u32 reg = skge_read32(hw, B2_GP_IO); - - if (port == 0) { - reg |= GP_DIR_0; - reg &= ~GP_IO_0; - } else { - reg |= GP_DIR_2; - reg &= ~GP_IO_2; - } - skge_write32(hw, B2_GP_IO, reg); - skge_read32(hw, B2_GP_IO); + reg = skge_read32(hw, B2_GP_IO); + if (port == 0) { + reg |= GP_DIR_0; + reg &= ~GP_IO_0; + } else { + reg |= GP_DIR_2; + reg &= ~GP_IO_2; } + skge_write32(hw, B2_GP_IO, reg); + skge_read32(hw, B2_GP_IO); - skge_xm_write16(hw, port, XM_MMU_CMD, - skge_xm_read16(hw, port, XM_MMU_CMD) + xm_write16(hw, port, XM_MMU_CMD, + xm_read16(hw, port, XM_MMU_CMD) & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); - skge_xm_read16(hw, port, XM_MMU_CMD); + xm_read16(hw, port, XM_MMU_CMD); } @@ -1341,11 +1374,11 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data) int i; unsigned long timeout = jiffies + HZ; - skge_xm_write16(hw, port, + xm_write16(hw, port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC); /* wait for update to complete */ - while (skge_xm_read16(hw, port, XM_STAT_CMD) + while (xm_read16(hw, port, XM_STAT_CMD) & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) { if (time_after(jiffies, timeout)) break; @@ -1353,68 +1386,60 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data) } /* special case for 64 bit octet counter */ - data[0] = (u64) skge_xm_read32(hw, port, XM_TXO_OK_HI) << 32 - | skge_xm_read32(hw, port, XM_TXO_OK_LO); - data[1] = (u64) skge_xm_read32(hw, port, XM_RXO_OK_HI) << 32 - | skge_xm_read32(hw, port, XM_RXO_OK_LO); + data[0] = (u64) xm_read32(hw, port, XM_TXO_OK_HI) << 32 + | xm_read32(hw, port, XM_TXO_OK_LO); + data[1] = (u64) xm_read32(hw, port, XM_RXO_OK_HI) << 32 + | xm_read32(hw, port, XM_RXO_OK_LO); for (i = 2; i < ARRAY_SIZE(skge_stats); i++) - data[i] = skge_xm_read32(hw, port, skge_stats[i].xmac_offset); + data[i] = xm_read32(hw, port, skge_stats[i].xmac_offset); } static void genesis_mac_intr(struct skge_hw *hw, int port) { struct skge_port *skge = netdev_priv(hw->dev[port]); - u16 status = skge_xm_read16(hw, port, XM_ISRC); - - pr_debug("genesis_intr status %x\n", status); - if (hw->phy_type == SK_PHY_XMAC) { - /* LInk down, start polling for state change */ - if (status & XM_IS_INP_ASS) { - skge_xm_write16(hw, port, XM_IMSK, - skge_xm_read16(hw, port, XM_IMSK) | XM_IS_INP_ASS); - mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); - } - else if (status & XM_IS_AND) - mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); - } + u16 status = xm_read16(hw, port, XM_ISRC); + + if (netif_msg_intr(skge)) + printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", + skge->netdev->name, status); if (status & XM_IS_TXF_UR) { - skge_xm_write32(hw, port, XM_MODE, XM_MD_FTF); + xm_write32(hw, port, XM_MODE, XM_MD_FTF); ++skge->net_stats.tx_fifo_errors; } if (status & XM_IS_RXF_OV) { - skge_xm_write32(hw, port, XM_MODE, XM_MD_FRF); + xm_write32(hw, port, XM_MODE, XM_MD_FRF); ++skge->net_stats.rx_fifo_errors; } } -static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) +static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) { int i; - skge_gma_write16(hw, port, GM_SMI_DATA, val); - skge_gma_write16(hw, port, GM_SMI_CTRL, + gma_write16(hw, port, GM_SMI_DATA, val); + gma_write16(hw, port, GM_SMI_CTRL, GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg)); for (i = 0; i < PHY_RETRIES; i++) { udelay(1); - if (!(skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) + if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) break; } } -static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg) +static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg) { int i; - skge_gma_write16(hw, port, GM_SMI_CTRL, + gma_write16(hw, port, GM_SMI_CTRL, GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); for (i = 0; i < PHY_RETRIES; i++) { udelay(1); - if (skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) + if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) goto ready; } @@ -1422,24 +1447,7 @@ static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg) hw->dev[port]->name); return 0; ready: - return skge_gma_read16(hw, port, GM_SMI_DATA); -} - -static void genesis_link_down(struct skge_port *skge) -{ - struct skge_hw *hw = skge->hw; - int port = skge->port; - - pr_debug("genesis_link_down\n"); - - skge_xm_write16(hw, port, XM_MMU_CMD, - skge_xm_read16(hw, port, XM_MMU_CMD) - & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); - - /* dummy read to ensure writing */ - (void) skge_xm_read16(hw, port, XM_MMU_CMD); - - skge_link_down(skge); + return gma_read16(hw, port, GM_SMI_DATA); } static void genesis_link_up(struct skge_port *skge) @@ -1450,7 +1458,7 @@ static void genesis_link_up(struct skge_port *skge) u32 mode, msk; pr_debug("genesis_link_up\n"); - cmd = skge_xm_read16(hw, port, XM_MMU_CMD); + cmd = xm_read16(hw, port, XM_MMU_CMD); /* * enabling pause frame reception is required for 1000BT @@ -1458,14 +1466,15 @@ static void genesis_link_up(struct skge_port *skge) */ if (skge->flow_control == FLOW_MODE_NONE || skge->flow_control == FLOW_MODE_LOC_SEND) + /* Disable Pause Frame Reception */ cmd |= XM_MMU_IGN_PF; else /* Enable Pause Frame Reception */ cmd &= ~XM_MMU_IGN_PF; - skge_xm_write16(hw, port, XM_MMU_CMD, cmd); + xm_write16(hw, port, XM_MMU_CMD, cmd); - mode = skge_xm_read32(hw, port, XM_MODE); + mode = xm_read32(hw, port, XM_MODE); if (skge->flow_control == FLOW_MODE_SYMMETRIC || skge->flow_control == FLOW_MODE_LOC_SEND) { /* @@ -1479,10 +1488,10 @@ static void genesis_link_up(struct skge_port *skge) /* XM_PAUSE_DA = '010000C28001' (default) */ /* XM_MAC_PTIME = 0xffff (maximum) */ /* remember this value is defined in big endian (!) */ - skge_xm_write16(hw, port, XM_MAC_PTIME, 0xffff); + xm_write16(hw, port, XM_MAC_PTIME, 0xffff); mode |= XM_PAUSE_MODE; - skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE); + skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE); } else { /* * disable pause frame generation is required for 1000BT @@ -1491,125 +1500,68 @@ static void genesis_link_up(struct skge_port *skge) /* Disable Pause Mode in Mode Register */ mode &= ~XM_PAUSE_MODE; - skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE); + skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE); } - skge_xm_write32(hw, port, XM_MODE, mode); + xm_write32(hw, port, XM_MODE, mode); msk = XM_DEF_MSK; - if (hw->phy_type != SK_PHY_XMAC) - msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ + /* disable GP0 interrupt bit for external Phy */ + msk |= XM_IS_INP_ASS; - skge_xm_write16(hw, port, XM_IMSK, msk); - skge_xm_read16(hw, port, XM_ISRC); + xm_write16(hw, port, XM_IMSK, msk); + xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ - cmd = skge_xm_read16(hw, port, XM_MMU_CMD); - if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL) + cmd = xm_read16(hw, port, XM_MMU_CMD); + if (skge->duplex == DUPLEX_FULL) cmd |= XM_MMU_GMII_FD; - if (hw->phy_type == SK_PHY_BCOM) { - /* - * Workaround BCOM Errata (#10523) for all BCom Phys - * Enable Power Management after link up - */ - skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, - skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) - & ~PHY_B_AC_DIS_PM); - skge_xm_phy_write(hw, port, PHY_BCOM_INT_MASK, - PHY_B_DEF_MSK); - } + /* + * Workaround BCOM Errata (#10523) for all BCom Phys + * Enable Power Management after link up + */ + xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, + xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) + & ~PHY_B_AC_DIS_PM); + xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); /* enable Rx/Tx */ - skge_xm_write16(hw, port, XM_MMU_CMD, + xm_write16(hw, port, XM_MMU_CMD, cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX); skge_link_up(skge); } -static void genesis_bcom_intr(struct skge_port *skge) +static inline void bcom_phy_intr(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; - u16 stat = skge_xm_phy_read(hw, port, PHY_BCOM_INT_STAT); + u16 isrc; + + isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT); + if (netif_msg_intr(skge)) + printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x\n", + skge->netdev->name, isrc); - pr_debug("genesis_bcom intr stat=%x\n", stat); + if (isrc & PHY_B_IS_PSE) + printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n", + hw->dev[port]->name); /* Workaround BCom Errata: * enable and disable loopback mode if "NO HCD" occurs. */ - if (stat & PHY_B_IS_NO_HDCL) { - u16 ctrl = skge_xm_phy_read(hw, port, PHY_BCOM_CTRL); - skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, + if (isrc & PHY_B_IS_NO_HDCL) { + u16 ctrl = xm_phy_read(hw, port, PHY_BCOM_CTRL); + xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl | PHY_CT_LOOP); - skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, + xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl & ~PHY_CT_LOOP); } - stat = skge_xm_phy_read(hw, port, PHY_BCOM_STAT); - if (stat & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) { - u16 aux = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); - if ( !(aux & PHY_B_AS_LS) && netif_carrier_ok(skge->netdev)) - genesis_link_down(skge); - - else if (stat & PHY_B_IS_LST_CHANGE) { - if (aux & PHY_B_AS_AN_C) { - switch (aux & PHY_B_AS_AN_RES_MSK) { - case PHY_B_RES_1000FD: - skge->duplex = DUPLEX_FULL; - break; - case PHY_B_RES_1000HD: - skge->duplex = DUPLEX_HALF; - break; - } - - switch (aux & PHY_B_AS_PAUSE_MSK) { - case PHY_B_AS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; - break; - case PHY_B_AS_PRR: - skge->flow_control = FLOW_MODE_REM_SEND; - break; - case PHY_B_AS_PRT: - skge->flow_control = FLOW_MODE_LOC_SEND; - break; - default: - skge->flow_control = FLOW_MODE_NONE; - } - skge->speed = SPEED_1000; - } - genesis_link_up(skge); - } - else - mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); - } -} + if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) + bcom_check_link(hw, port); -/* Perodic poll of phy status to check for link transistion */ -static void skge_link_timer(unsigned long __arg) -{ - struct skge_port *skge = (struct skge_port *) __arg; - struct skge_hw *hw = skge->hw; - int port = skge->port; - - if (hw->chip_id != CHIP_ID_GENESIS || !netif_running(skge->netdev)) - return; - - spin_lock_bh(&hw->phy_lock); - if (hw->phy_type == SK_PHY_BCOM) - genesis_bcom_intr(skge); - else { - int i; - for (i = 0; i < 3; i++) - if (skge_xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS) - break; - - if (i == 3) - mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ); - else - genesis_link_up(skge); - } - spin_unlock_bh(&hw->phy_lock); } /* Marvell Phy Initailization */ @@ -1621,31 +1573,27 @@ static void yukon_init(struct skge_hw *hw, int port) pr_debug("yukon_init\n"); if (skge->autoneg == AUTONEG_ENABLE) { - u16 ectrl = skge_gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); + u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | PHY_M_EC_MAC_S_MSK); ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ); - /* on PHY 88E1111 there is a change for downshift control */ - if (hw->chip_id == CHIP_ID_YUKON_EC) - ectrl |= PHY_M_EC_M_DSC_2(0) | PHY_M_EC_DOWN_S_ENA; - else - ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1); + ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1); - skge_gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl); + gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl); } - ctrl = skge_gm_phy_read(hw, port, PHY_MARV_CTRL); + ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL); if (skge->autoneg == AUTONEG_DISABLE) ctrl &= ~PHY_CT_ANE; ctrl |= PHY_CT_RESET; - skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); + gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); ctrl = 0; ct1000 = 0; - adv = PHY_SEL_TYPE; + adv = PHY_AN_CSMA; if (skge->autoneg == AUTONEG_ENABLE) { if (iscopper(hw)) { @@ -1661,41 +1609,12 @@ static void yukon_init(struct skge_hw *hw, int port) adv |= PHY_M_AN_10_FD; if (skge->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - - /* Set Flow-control capabilities */ - switch (skge->flow_control) { - case FLOW_MODE_NONE: - adv |= PHY_B_P_NO_PAUSE; - break; - case FLOW_MODE_LOC_SEND: - adv |= PHY_B_P_ASYM_MD; - break; - case FLOW_MODE_SYMMETRIC: - adv |= PHY_B_P_SYM_MD; - break; - case FLOW_MODE_REM_SEND: - adv |= PHY_B_P_BOTH_MD; - break; - } - } else { /* special defines for FIBER (88E1011S only) */ + } else /* special defines for FIBER (88E1011S only) */ adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; - /* Set Flow-control capabilities */ - switch (skge->flow_control) { - case FLOW_MODE_NONE: - adv |= PHY_M_P_NO_PAUSE_X; - break; - case FLOW_MODE_LOC_SEND: - adv |= PHY_M_P_ASYM_MD_X; - break; - case FLOW_MODE_SYMMETRIC: - adv |= PHY_M_P_SYM_MD_X; - break; - case FLOW_MODE_REM_SEND: - adv |= PHY_M_P_BOTH_MD_X; - break; - } - } + /* Set Flow-control capabilities */ + adv |= phy_pause_map[skge->flow_control]; + /* Restart Auto-negotiation */ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; } else { @@ -1717,36 +1636,23 @@ static void yukon_init(struct skge_hw *hw, int port) ctrl |= PHY_CT_RESET; } - if (hw->chip_id != CHIP_ID_YUKON_FE) - skge_gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); + gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); - skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv); - skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); + gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv); + gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); /* Setup Phy LED's */ ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS); ledover = 0; - if (hw->chip_id == CHIP_ID_YUKON_FE) { - /* on 88E3082 these bits are at 11..9 (shifted left) */ - ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1; - - skge_gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, - ((skge_gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR) - - & ~PHY_M_FELP_LED1_MSK) - | PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL))); - } else { - /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */ - ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; + ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL; - /* turn off the Rx LED (LED_RX) */ - ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); - } + /* turn off the Rx LED (LED_RX) */ + ledover |= PHY_M_LED_MO_RX(MO_LED_OFF); /* disable blink mode (LED_DUPLEX) on collisions */ ctrl |= PHY_M_LEDC_DP_CTRL; - skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); + gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); if (skge->autoneg == AUTONEG_DISABLE || skge->speed == SPEED_100) { /* turn on 100 Mbps LED (LED_LINK100) */ @@ -1754,25 +1660,25 @@ static void yukon_init(struct skge_hw *hw, int port) } if (ledover) - skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); + gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); /* Enable phy interrupt on autonegotiation complete (or link up) */ if (skge->autoneg == AUTONEG_ENABLE) - skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); + gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL); else - skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); + gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); } static void yukon_reset(struct skge_hw *hw, int port) { - skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */ - skge_gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */ - skge_gma_write16(hw, port, GM_MC_ADDR_H2, 0); - skge_gma_write16(hw, port, GM_MC_ADDR_H3, 0); - skge_gma_write16(hw, port, GM_MC_ADDR_H4, 0); + gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */ + gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */ + gma_write16(hw, port, GM_MC_ADDR_H2, 0); + gma_write16(hw, port, GM_MC_ADDR_H3, 0); + gma_write16(hw, port, GM_MC_ADDR_H4, 0); - skge_gma_write16(hw, port, GM_RX_CTRL, - skge_gma_read16(hw, port, GM_RX_CTRL) + gma_write16(hw, port, GM_RX_CTRL, + gma_read16(hw, port, GM_RX_CTRL) | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); } @@ -1785,17 +1691,17 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* WA code for COMA mode -- set PHY reset */ if (hw->chip_id == CHIP_ID_YUKON_LITE && - chip_rev(hw) == CHIP_REV_YU_LITE_A3) + hw->chip_rev == CHIP_REV_YU_LITE_A3) skge_write32(hw, B2_GP_IO, (skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9)); /* hard reset */ - skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), GPC_RST_SET); - skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_RST_SET); + skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); + skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); /* WA code for COMA mode -- clear PHY reset */ if (hw->chip_id == CHIP_ID_YUKON_LITE && - chip_rev(hw) == CHIP_REV_YU_LITE_A3) + hw->chip_rev == CHIP_REV_YU_LITE_A3) skge_write32(hw, B2_GP_IO, (skge_read32(hw, B2_GP_IO) | GP_DIR_9) & ~GP_IO_9); @@ -1806,13 +1712,13 @@ static void yukon_mac_init(struct skge_hw *hw, int port) reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB; /* Clear GMC reset */ - skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_SET); - skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_CLR); - skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); + skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET); + skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_CLR); + skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); if (skge->autoneg == AUTONEG_DISABLE) { reg = GM_GPCR_AU_ALL_DIS; - skge_gma_write16(hw, port, GM_GP_CTRL, - skge_gma_read16(hw, port, GM_GP_CTRL) | reg); + gma_write16(hw, port, GM_GP_CTRL, + gma_read16(hw, port, GM_GP_CTRL) | reg); switch (skge->speed) { case SPEED_1000: @@ -1828,7 +1734,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port) reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL; switch (skge->flow_control) { case FLOW_MODE_NONE: - skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); + skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); reg |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; break; case FLOW_MODE_LOC_SEND: @@ -1836,7 +1742,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port) reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; } - skge_gma_write16(hw, port, GM_GP_CTRL, reg); + gma_write16(hw, port, GM_GP_CTRL, reg); skge_read16(hw, GMAC_IRQ_SRC); spin_lock_bh(&hw->phy_lock); @@ -1844,25 +1750,25 @@ static void yukon_mac_init(struct skge_hw *hw, int port) spin_unlock_bh(&hw->phy_lock); /* MIB clear */ - reg = skge_gma_read16(hw, port, GM_PHY_ADDR); - skge_gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); + reg = gma_read16(hw, port, GM_PHY_ADDR); + gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); for (i = 0; i < GM_MIB_CNT_SIZE; i++) - skge_gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i); - skge_gma_write16(hw, port, GM_PHY_ADDR, reg); + gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i); + gma_write16(hw, port, GM_PHY_ADDR, reg); /* transmit control */ - skge_gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF)); + gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF)); /* receive control reg: unicast + multicast + no FCS */ - skge_gma_write16(hw, port, GM_RX_CTRL, + gma_write16(hw, port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA); /* transmit flow control */ - skge_gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff); + gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff); /* transmit parameter */ - skge_gma_write16(hw, port, GM_TX_PARAM, + gma_write16(hw, port, GM_TX_PARAM, TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) | TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) | TX_IPG_JAM_DATA(TX_IPG_JAM_DEF)); @@ -1872,33 +1778,33 @@ static void yukon_mac_init(struct skge_hw *hw, int port) if (hw->dev[port]->mtu > 1500) reg |= GM_SMOD_JUMBO_ENA; - skge_gma_write16(hw, port, GM_SERIAL_MODE, reg); + gma_write16(hw, port, GM_SERIAL_MODE, reg); /* physical address: used for pause frames */ - skge_gm_set_addr(hw, port, GM_SRC_ADDR_1L, addr); + gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr); /* virtual address for data */ - skge_gm_set_addr(hw, port, GM_SRC_ADDR_2L, addr); + gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr); /* enable interrupt mask for counter overflows */ - skge_gma_write16(hw, port, GM_TX_IRQ_MSK, 0); - skge_gma_write16(hw, port, GM_RX_IRQ_MSK, 0); - skge_gma_write16(hw, port, GM_TR_IRQ_MSK, 0); + gma_write16(hw, port, GM_TX_IRQ_MSK, 0); + gma_write16(hw, port, GM_RX_IRQ_MSK, 0); + gma_write16(hw, port, GM_TR_IRQ_MSK, 0); /* Initialize Mac Fifo */ /* Configure Rx MAC FIFO */ - skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK); + skge_write16(hw, SK_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK); reg = GMF_OPER_ON | GMF_RX_F_FL_ON; if (hw->chip_id == CHIP_ID_YUKON_LITE && - chip_rev(hw) == CHIP_REV_YU_LITE_A3) + hw->chip_rev == CHIP_REV_YU_LITE_A3) reg &= ~GMF_RX_F_FL_ON; - skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); - skge_write16(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), reg); - skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF); + skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); + skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg); + skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF); /* Configure Tx MAC FIFO */ - skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); - skge_write16(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); + skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); + skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); } static void yukon_stop(struct skge_port *skge) @@ -1907,19 +1813,19 @@ static void yukon_stop(struct skge_port *skge) int port = skge->port; if (hw->chip_id == CHIP_ID_YUKON_LITE && - chip_rev(hw) == CHIP_REV_YU_LITE_A3) { + hw->chip_rev == CHIP_REV_YU_LITE_A3) { skge_write32(hw, B2_GP_IO, skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9); } - skge_gma_write16(hw, port, GM_GP_CTRL, - skge_gma_read16(hw, port, GM_GP_CTRL) + gma_write16(hw, port, GM_GP_CTRL, + gma_read16(hw, port, GM_GP_CTRL) & ~(GM_GPCR_RX_ENA|GM_GPCR_RX_ENA)); - skge_gma_read16(hw, port, GM_GP_CTRL); + gma_read16(hw, port, GM_GP_CTRL); /* set GPHY Control reset */ - skge_gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET); - skge_gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET); + gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET); + gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET); } static void yukon_get_stats(struct skge_port *skge, u64 *data) @@ -1928,39 +1834,40 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data) int port = skge->port; int i; - data[0] = (u64) skge_gma_read32(hw, port, GM_TXO_OK_HI) << 32 - | skge_gma_read32(hw, port, GM_TXO_OK_LO); - data[1] = (u64) skge_gma_read32(hw, port, GM_RXO_OK_HI) << 32 - | skge_gma_read32(hw, port, GM_RXO_OK_LO); + data[0] = (u64) gma_read32(hw, port, GM_TXO_OK_HI) << 32 + | gma_read32(hw, port, GM_TXO_OK_LO); + data[1] = (u64) gma_read32(hw, port, GM_RXO_OK_HI) << 32 + | gma_read32(hw, port, GM_RXO_OK_LO); for (i = 2; i < ARRAY_SIZE(skge_stats); i++) - data[i] = skge_gma_read32(hw, port, + data[i] = gma_read32(hw, port, skge_stats[i].gma_offset); } static void yukon_mac_intr(struct skge_hw *hw, int port) { - struct skge_port *skge = netdev_priv(hw->dev[port]); - u8 status = skge_read8(hw, SKGEMAC_REG(port, GMAC_IRQ_SRC)); + struct net_device *dev = hw->dev[port]; + struct skge_port *skge = netdev_priv(dev); + u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC)); + + if (netif_msg_intr(skge)) + printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", + dev->name, status); - pr_debug("yukon_intr status %x\n", status); if (status & GM_IS_RX_FF_OR) { ++skge->net_stats.rx_fifo_errors; - skge_gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO); + gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO); } if (status & GM_IS_TX_FF_UR) { ++skge->net_stats.tx_fifo_errors; - skge_gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU); + gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU); } } static u16 yukon_speed(const struct skge_hw *hw, u16 aux) { - if (hw->chip_id == CHIP_ID_YUKON_FE) - return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10; - - switch(aux & PHY_M_PS_SPEED_MSK) { + switch (aux & PHY_M_PS_SPEED_MSK) { case PHY_M_PS_SPEED_1000: return SPEED_1000; case PHY_M_PS_SPEED_100: @@ -1981,15 +1888,15 @@ static void yukon_link_up(struct skge_port *skge) /* Enable Transmit FIFO Underrun */ skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK); - reg = skge_gma_read16(hw, port, GM_GP_CTRL); + reg = gma_read16(hw, port, GM_GP_CTRL); if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE) reg |= GM_GPCR_DUP_FULL; /* enable Rx/Tx */ reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; - skge_gma_write16(hw, port, GM_GP_CTRL, reg); + gma_write16(hw, port, GM_GP_CTRL, reg); - skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); + gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK); skge_link_up(skge); } @@ -1999,16 +1906,15 @@ static void yukon_link_down(struct skge_port *skge) int port = skge->port; pr_debug("yukon_link_down\n"); - skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0); - skge_gm_phy_write(hw, port, GM_GP_CTRL, - skge_gm_phy_read(hw, port, GM_GP_CTRL) + gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0); + gm_phy_write(hw, port, GM_GP_CTRL, + gm_phy_read(hw, port, GM_GP_CTRL) & ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA)); - if (hw->chip_id != CHIP_ID_YUKON_FE && - skge->flow_control == FLOW_MODE_REM_SEND) { + if (skge->flow_control == FLOW_MODE_REM_SEND) { /* restore Asymmetric Pause bit */ - skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - skge_gm_phy_read(hw, port, + gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, + gm_phy_read(hw, port, PHY_MARV_AUNE_ADV) | PHY_M_AN_ASP); @@ -2027,20 +1933,21 @@ static void yukon_phy_intr(struct skge_port *skge) const char *reason = NULL; u16 istatus, phystat; - istatus = skge_gm_phy_read(hw, port, PHY_MARV_INT_STAT); - phystat = skge_gm_phy_read(hw, port, PHY_MARV_PHY_STAT); - pr_debug("yukon phy intr istat=%x phy_stat=%x\n", istatus, phystat); + istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT); + phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT); + + if (netif_msg_intr(skge)) + printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x 0x%x\n", + skge->netdev->name, istatus, phystat); if (istatus & PHY_M_IS_AN_COMPL) { - if (skge_gm_phy_read(hw, port, PHY_MARV_AUNE_LP) + if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP) & PHY_M_AN_RF) { reason = "remote fault"; goto failed; } - if (!(hw->chip_id == CHIP_ID_YUKON_FE || hw->chip_id == CHIP_ID_YUKON_EC) - && (skge_gm_phy_read(hw, port, PHY_MARV_1000T_STAT) - & PHY_B_1000S_MSF)) { + if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) { reason = "master/slave fault"; goto failed; } @@ -2054,10 +1961,6 @@ static void yukon_phy_intr(struct skge_port *skge) ? DUPLEX_FULL : DUPLEX_HALF; skge->speed = yukon_speed(hw, phystat); - /* Tx & Rx Pause Enabled bits are at 9..8 */ - if (hw->chip_id == CHIP_ID_YUKON_XL) - phystat >>= 6; - /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (phystat & PHY_M_PS_PAUSE_MSK) { case PHY_M_PS_PAUSE_MSK: @@ -2075,9 +1978,9 @@ static void yukon_phy_intr(struct skge_port *skge) if (skge->flow_control == FLOW_MODE_NONE || (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) - skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); + skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); else - skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON); + skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); yukon_link_up(skge); return; } @@ -2161,6 +2064,12 @@ static int skge_up(struct net_device *dev) if (netif_msg_ifup(skge)) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); + if (dev->mtu > RX_BUF_SIZE) + skge->rx_buf_size = dev->mtu + ETH_HLEN + NET_IP_ALIGN; + else + skge->rx_buf_size = RX_BUF_SIZE; + + rx_size = skge->rx_ring.count * sizeof(struct skge_rx_desc); tx_size = skge->tx_ring.count * sizeof(struct skge_tx_desc); skge->mem_size = tx_size + rx_size; @@ -2173,7 +2082,8 @@ static int skge_up(struct net_device *dev) if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma))) goto free_pci_mem; - if (skge_rx_fill(skge)) + err = skge_rx_fill(skge); + if (err) goto free_rx_ring; if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size, @@ -2182,6 +2092,10 @@ static int skge_up(struct net_device *dev) skge->tx_avail = skge->tx_ring.count - 1; + /* Enable IRQ from port */ + hw->intr_mask |= portirqmask[port]; + skge_write32(hw, B0_IMSK, hw->intr_mask); + /* Initialze MAC */ if (hw->chip_id == CHIP_ID_GENESIS) genesis_mac_init(hw, port); @@ -2189,7 +2103,7 @@ static int skge_up(struct net_device *dev) yukon_mac_init(hw, port); /* Configure RAMbuffers */ - chunk = hw->ram_size / (isdualport(hw) ? 4 : 2); + chunk = hw->ram_size / ((hw->ports + 1)*2); ram_addr = hw->ram_offset + 2 * chunk * port; skge_ramset(hw, rxqaddr[port], ram_addr, chunk); @@ -2227,7 +2141,6 @@ static int skge_down(struct net_device *dev) netif_stop_queue(dev); del_timer_sync(&skge->led_blink); - del_timer_sync(&skge->link_check); /* Stop transmitter */ skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP); @@ -2240,12 +2153,12 @@ static int skge_down(struct net_device *dev) yukon_stop(skge); /* Disable Force Sync bit and Enable Alloc bit */ - skge_write8(hw, SKGEMAC_REG(port, TXA_CTRL), + skge_write8(hw, SK_REG(port, TXA_CTRL), TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); /* Stop Interval Timer and Limit Counter of Tx Arbiter */ - skge_write32(hw, SKGEMAC_REG(port, TXA_ITI_INI), 0L); - skge_write32(hw, SKGEMAC_REG(port, TXA_LIM_INI), 0L); + skge_write32(hw, SK_REG(port, TXA_ITI_INI), 0L); + skge_write32(hw, SK_REG(port, TXA_LIM_INI), 0L); /* Reset PCI FIFO */ skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET); @@ -2260,13 +2173,13 @@ static int skge_down(struct net_device *dev) skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET); if (hw->chip_id == CHIP_ID_GENESIS) { - skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_SET); - skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_SET); - skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_STOP); - skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_STOP); + skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET); + skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_SET); + skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_STOP); + skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_STOP); } else { - skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); - skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); + skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); + skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); } /* turn off led's */ @@ -2299,10 +2212,10 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) local_irq_save(flags); if (!spin_trylock(&skge->tx_lock)) { - /* Collision - tell upper layer to requeue */ - local_irq_restore(flags); - return NETDEV_TX_LOCKED; - } + /* Collision - tell upper layer to requeue */ + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) { netif_stop_queue(dev); @@ -2333,7 +2246,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) * does. Looks like hardware is wrong? */ if (ip->protocol == IPPROTO_UDP - && chip_rev(hw) == 0 && hw->chip_id == CHIP_ID_YUKON) + && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON) control = BMU_TCP_CHECK; else control = BMU_UDP_CHECK; @@ -2394,6 +2307,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e) { + /* This ring element can be skb or fragment */ if (e->skb) { pci_unmap_single(hw->pdev, pci_unmap_addr(e, mapaddr), @@ -2438,16 +2352,17 @@ static void skge_tx_timeout(struct net_device *dev) static int skge_change_mtu(struct net_device *dev, int new_mtu) { int err = 0; + int running = netif_running(dev); - if(new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) + if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; - dev->mtu = new_mtu; - if (netif_running(dev)) { + if (running) skge_down(dev); + dev->mtu = new_mtu; + if (running) skge_up(dev); - } return err; } @@ -2462,7 +2377,9 @@ static void genesis_set_multicast(struct net_device *dev) u32 mode; u8 filter[8]; - mode = skge_xm_read32(hw, port, XM_MODE); + pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count); + + mode = xm_read32(hw, port, XM_MODE); mode |= XM_MD_ENA_HASH; if (dev->flags & IFF_PROMISC) mode |= XM_MD_ENA_PROM; @@ -2473,17 +2390,16 @@ static void genesis_set_multicast(struct net_device *dev) memset(filter, 0xff, sizeof(filter)); else { memset(filter, 0, sizeof(filter)); - for(i = 0; list && i < count; i++, list = list->next) { - u32 crc = crc32_le(~0, list->dmi_addr, ETH_ALEN); - u8 bit = 63 - (crc & 63); - + for (i = 0; list && i < count; i++, list = list->next) { + u32 crc, bit; + crc = ether_crc_le(ETH_ALEN, list->dmi_addr); + bit = ~crc & 0x3f; filter[bit/8] |= 1 << (bit%8); } } - skge_xm_outhash(hw, port, XM_HSM, filter); - - skge_xm_write32(hw, port, XM_MODE, mode); + xm_write32(hw, port, XM_MODE, mode); + xm_outhash(hw, port, XM_HSM, filter); } static void yukon_set_multicast(struct net_device *dev) @@ -2497,7 +2413,7 @@ static void yukon_set_multicast(struct net_device *dev) memset(filter, 0, sizeof(filter)); - reg = skge_gma_read16(hw, port, GM_RX_CTRL); + reg = gma_read16(hw, port, GM_RX_CTRL); reg |= GM_RXCR_UCF_ENA; if (dev->flags & IFF_PROMISC) /* promiscious */ @@ -2510,23 +2426,23 @@ static void yukon_set_multicast(struct net_device *dev) int i; reg |= GM_RXCR_MCF_ENA; - for(i = 0; list && i < dev->mc_count; i++, list = list->next) { + for (i = 0; list && i < dev->mc_count; i++, list = list->next) { u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; filter[bit/8] |= 1 << (bit%8); } } - skge_gma_write16(hw, port, GM_MC_ADDR_H1, + gma_write16(hw, port, GM_MC_ADDR_H1, (u16)filter[0] | ((u16)filter[1] << 8)); - skge_gma_write16(hw, port, GM_MC_ADDR_H2, + gma_write16(hw, port, GM_MC_ADDR_H2, (u16)filter[2] | ((u16)filter[3] << 8)); - skge_gma_write16(hw, port, GM_MC_ADDR_H3, + gma_write16(hw, port, GM_MC_ADDR_H3, (u16)filter[4] | ((u16)filter[5] << 8)); - skge_gma_write16(hw, port, GM_MC_ADDR_H4, + gma_write16(hw, port, GM_MC_ADDR_H4, (u16)filter[6] | ((u16)filter[7] << 8)); - skge_gma_write16(hw, port, GM_RX_CTRL, reg); + gma_write16(hw, port, GM_RX_CTRL, reg); } static inline int bad_phy_status(const struct skge_hw *hw, u32 status) @@ -2545,28 +2461,76 @@ static void skge_rx_error(struct skge_port *skge, int slot, printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n", skge->netdev->name, slot, control, status); - if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF) - || (control & BMU_BBC) > skge->netdev->mtu + VLAN_ETH_HLEN) + if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)) skge->net_stats.rx_length_errors++; - else { - if (skge->hw->chip_id == CHIP_ID_GENESIS) { - if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR)) - skge->net_stats.rx_length_errors++; - if (status & XMR_FS_FRA_ERR) - skge->net_stats.rx_frame_errors++; - if (status & XMR_FS_FCS_ERR) - skge->net_stats.rx_crc_errors++; - } else { - if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE)) - skge->net_stats.rx_length_errors++; - if (status & GMR_FS_FRAGMENT) - skge->net_stats.rx_frame_errors++; - if (status & GMR_FS_CRC_ERR) - skge->net_stats.rx_crc_errors++; + else if (skge->hw->chip_id == CHIP_ID_GENESIS) { + if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR)) + skge->net_stats.rx_length_errors++; + if (status & XMR_FS_FRA_ERR) + skge->net_stats.rx_frame_errors++; + if (status & XMR_FS_FCS_ERR) + skge->net_stats.rx_crc_errors++; + } else { + if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE)) + skge->net_stats.rx_length_errors++; + if (status & GMR_FS_FRAGMENT) + skge->net_stats.rx_frame_errors++; + if (status & GMR_FS_CRC_ERR) + skge->net_stats.rx_crc_errors++; + } +} + +/* Get receive buffer from descriptor. + * Handles copy of small buffers and reallocation failures + */ +static inline struct sk_buff *skge_rx_get(struct skge_port *skge, + struct skge_element *e, + unsigned int len) +{ + struct sk_buff *nskb, *skb; + + if (len < RX_COPY_THRESHOLD) { + nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN); + if (unlikely(!nskb)) + return NULL; + + pci_dma_sync_single_for_cpu(skge->hw->pdev, + pci_unmap_addr(e, mapaddr), + len, PCI_DMA_FROMDEVICE); + memcpy(nskb->data, e->skb->data, len); + pci_dma_sync_single_for_device(skge->hw->pdev, + pci_unmap_addr(e, mapaddr), + len, PCI_DMA_FROMDEVICE); + + if (skge->rx_csum) { + struct skge_rx_desc *rd = e->desc; + nskb->csum = le16_to_cpu(rd->csum2); + nskb->ip_summed = CHECKSUM_HW; } + skge_rx_reuse(e, skge->rx_buf_size); + return nskb; + } else { + nskb = skge_rx_alloc(skge->netdev, skge->rx_buf_size); + if (unlikely(!nskb)) + return NULL; + + pci_unmap_single(skge->hw->pdev, + pci_unmap_addr(e, mapaddr), + pci_unmap_len(e, maplen), + PCI_DMA_FROMDEVICE); + skb = e->skb; + if (skge->rx_csum) { + struct skge_rx_desc *rd = e->desc; + skb->csum = le16_to_cpu(rd->csum2); + skb->ip_summed = CHECKSUM_HW; + } + + skge_rx_setup(skge, e, nskb, skge->rx_buf_size); + return skb; } } + static int skge_poll(struct net_device *dev, int *budget) { struct skge_port *skge = netdev_priv(dev); @@ -2575,13 +2539,12 @@ static int skge_poll(struct net_device *dev, int *budget) struct skge_element *e; unsigned int to_do = min(dev->quota, *budget); unsigned int work_done = 0; - int done; - static const u32 irqmask[] = { IS_PORT_1, IS_PORT_2 }; - for (e = ring->to_clean; e != ring->to_use && work_done < to_do; - e = e->next) { + pr_debug("skge_poll\n"); + + for (e = ring->to_clean; work_done < to_do; e = e->next) { struct skge_rx_desc *rd = e->desc; - struct sk_buff *skb = e->skb; + struct sk_buff *skb; u32 control, len, status; rmb(); @@ -2590,19 +2553,12 @@ static int skge_poll(struct net_device *dev, int *budget) break; len = control & BMU_BBC; - e->skb = NULL; - - pci_unmap_single(hw->pdev, - pci_unmap_addr(e, mapaddr), - pci_unmap_len(e, maplen), - PCI_DMA_FROMDEVICE); - status = rd->status; - if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF) - || len > dev->mtu + VLAN_ETH_HLEN - || bad_phy_status(hw, status)) { + + if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF) + || bad_phy_status(hw, status))) { skge_rx_error(skge, e - ring->start, control, status); - dev_kfree_skb(skb); + skge_rx_reuse(e, skge->rx_buf_size); continue; } @@ -2610,43 +2566,37 @@ static int skge_poll(struct net_device *dev, int *budget) printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n", dev->name, e - ring->start, rd->status, len); - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, dev); - - if (skge->rx_csum) { - skb->csum = le16_to_cpu(rd->csum2); - skb->ip_summed = CHECKSUM_HW; - } + skb = skge_rx_get(skge, e, len); + if (likely(skb)) { + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; - netif_receive_skb(skb); + dev->last_rx = jiffies; + netif_receive_skb(skb); - ++work_done; + ++work_done; + } else + skge_rx_reuse(e, skge->rx_buf_size); } ring->to_clean = e; - *budget -= work_done; - dev->quota -= work_done; - done = work_done < to_do; - - if (skge_rx_fill(skge)) - done = 0; - /* restart receiver */ wmb(); skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START | CSR_IRQ_CL_F); - if (done) { - local_irq_disable(); - hw->intr_mask |= irqmask[skge->port]; - /* Order is important since data can get interrupted */ - skge_write32(hw, B0_IMSK, hw->intr_mask); - __netif_rx_complete(dev); - local_irq_enable(); - } + *budget -= work_done; + dev->quota -= work_done; - return !done; + if (work_done >= to_do) + return 1; /* not done */ + + local_irq_disable(); + __netif_rx_complete(dev); + hw->intr_mask |= portirqmask[skge->port]; + skge_write32(hw, B0_IMSK, hw->intr_mask); + local_irq_enable(); + return 0; } static inline void skge_tx_intr(struct net_device *dev) @@ -2657,7 +2607,7 @@ static inline void skge_tx_intr(struct net_device *dev) struct skge_element *e; spin_lock(&skge->tx_lock); - for(e = ring->to_clean; e != ring->to_use; e = e->next) { + for (e = ring->to_clean; e != ring->to_use; e = e->next) { struct skge_tx_desc *td = e->desc; u32 control; @@ -2690,12 +2640,12 @@ static void skge_mac_parity(struct skge_hw *hw, int port) : (port == 0 ? "(port A)": "(port B")); if (hw->chip_id == CHIP_ID_GENESIS) - skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), + skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_PERR); else /* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */ - skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), - (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0) + skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), + (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE); } @@ -2703,16 +2653,16 @@ static void skge_pci_clear(struct skge_hw *hw) { u16 status; - status = skge_read16(hw, SKGEPCI_REG(PCI_STATUS)); + pci_read_config_word(hw->pdev, PCI_STATUS, &status); skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - skge_write16(hw, SKGEPCI_REG(PCI_STATUS), - status | PCI_STATUS_ERROR_BITS); + pci_write_config_word(hw->pdev, PCI_STATUS, + status | PCI_STATUS_ERROR_BITS); skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); } static void skge_mac_intr(struct skge_hw *hw, int port) { - if (hw->chip_id == CHIP_ID_GENESIS) + if (hw->chip_id == CHIP_ID_GENESIS) genesis_mac_intr(hw, port); else yukon_mac_intr(hw, port); @@ -2726,9 +2676,9 @@ static void skge_error_irq(struct skge_hw *hw) if (hw->chip_id == CHIP_ID_GENESIS) { /* clear xmac errors */ if (hwstatus & (IS_NO_STAT_M1|IS_NO_TIST_M1)) - skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT); + skge_write16(hw, SK_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT); if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2)) - skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT); + skge_write16(hw, SK_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT); } else { /* Timestamp (unused) overflow */ if (hwstatus & IS_IRQ_TIST_OV) @@ -2803,8 +2753,8 @@ static void skge_extirq(unsigned long data) if (hw->chip_id != CHIP_ID_GENESIS) yukon_phy_intr(skge); - else if (hw->phy_type == SK_PHY_BCOM) - genesis_bcom_intr(skge); + else + bcom_phy_intr(skge); } } spin_unlock(&hw->phy_lock); @@ -2824,19 +2774,14 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; status &= hw->intr_mask; - - if ((status & IS_R1_F) && netif_rx_schedule_prep(hw->dev[0])) { - status &= ~IS_R1_F; + if (status & IS_R1_F) { hw->intr_mask &= ~IS_R1_F; - skge_write32(hw, B0_IMSK, hw->intr_mask); - __netif_rx_schedule(hw->dev[0]); + netif_rx_schedule(hw->dev[0]); } - if ((status & IS_R2_F) && netif_rx_schedule_prep(hw->dev[1])) { - status &= ~IS_R2_F; + if (status & IS_R2_F) { hw->intr_mask &= ~IS_R2_F; - skge_write32(hw, B0_IMSK, hw->intr_mask); - __netif_rx_schedule(hw->dev[1]); + netif_rx_schedule(hw->dev[1]); } if (status & IS_XA1_F) @@ -2845,9 +2790,27 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) if (status & IS_XA2_F) skge_tx_intr(hw->dev[1]); + if (status & IS_PA_TO_RX1) { + struct skge_port *skge = netdev_priv(hw->dev[0]); + ++skge->net_stats.rx_over_errors; + skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1); + } + + if (status & IS_PA_TO_RX2) { + struct skge_port *skge = netdev_priv(hw->dev[1]); + ++skge->net_stats.rx_over_errors; + skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2); + } + + if (status & IS_PA_TO_TX1) + skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1); + + if (status & IS_PA_TO_TX2) + skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX2); + if (status & IS_MAC1) skge_mac_intr(hw, 0); - + if (status & IS_MAC2) skge_mac_intr(hw, 1); @@ -2859,8 +2822,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) tasklet_schedule(&hw->ext_tasklet); } - if (status) - skge_write32(hw, B0_IMSK, hw->intr_mask); + skge_write32(hw, B0_IMSK, hw->intr_mask); return IRQ_HANDLED; } @@ -2904,9 +2866,6 @@ static const struct { { CHIP_ID_YUKON, "Yukon" }, { CHIP_ID_YUKON_LITE, "Yukon-Lite"}, { CHIP_ID_YUKON_LP, "Yukon-LP"}, - { CHIP_ID_YUKON_XL, "Yukon-2 XL"}, - { CHIP_ID_YUKON_EC, "YUKON-2 EC"}, - { CHIP_ID_YUKON_FE, "YUKON-2 FE"}, }; static const char *skge_board_name(const struct skge_hw *hw) @@ -2930,8 +2889,8 @@ static const char *skge_board_name(const struct skge_hw *hw) static int skge_reset(struct skge_hw *hw) { u16 ctst; - u8 t8; - int i, ports; + u8 t8, mac_cfg; + int i; ctst = skge_read16(hw, B0_CTST); @@ -2952,12 +2911,9 @@ static int skge_reset(struct skge_hw *hw) hw->phy_type = skge_read8(hw, B2_E_1) & 0xf; hw->pmd_type = skge_read8(hw, B2_PMD_TYP); - switch(hw->chip_id) { + switch (hw->chip_id) { case CHIP_ID_GENESIS: switch (hw->phy_type) { - case SK_PHY_XMAC: - hw->phy_addr = PHY_ADDR_XMAC; - break; case SK_PHY_BCOM: hw->phy_addr = PHY_ADDR_BCOM; break; @@ -2986,8 +2942,9 @@ static int skge_reset(struct skge_hw *hw) return -EOPNOTSUPP; } - hw->mac_cfg = skge_read8(hw, B2_MAC_CFG); - ports = isdualport(hw) ? 2 : 1; + mac_cfg = skge_read8(hw, B2_MAC_CFG); + hw->ports = (mac_cfg & CFG_SNG_MAC) ? 1 : 2; + hw->chip_rev = (mac_cfg & CFG_CHIP_R_MSK) >> 4; /* read the adapters RAM size */ t8 = skge_read8(hw, B2_E_0); @@ -3010,9 +2967,9 @@ static int skge_reset(struct skge_hw *hw) /* switch power to VCC (WA for VAUX problem) */ skge_write8(hw, B0_POWER_CTRL, PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); - for (i = 0; i < ports; i++) { - skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); - skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); + for (i = 0; i < hw->ports; i++) { + skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); + skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); } } @@ -3022,8 +2979,8 @@ static int skge_reset(struct skge_hw *hw) skge_write8(hw, B0_LED, LED_STAT_ON); /* enable the Tx Arbiters */ - for (i = 0; i < ports; i++) - skge_write8(hw, SKGEMAC_REG(i, TXA_CTRL), TXA_ENA_ARB); + for (i = 0; i < hw->ports; i++) + skge_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB); /* Initialize ram interface */ skge_write16(hw, B3_RI_CTRL, RI_RST_CLR); @@ -3050,16 +3007,14 @@ static int skge_reset(struct skge_hw *hw) skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100)); skge_write32(hw, B2_IRQM_CTRL, TIM_START); - hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1; - if (isdualport(hw)) - hw->intr_mask |= IS_PORT_2; + hw->intr_mask = IS_HW_ERR | IS_EXT_REG; skge_write32(hw, B0_IMSK, hw->intr_mask); if (hw->chip_id != CHIP_ID_GENESIS) skge_write8(hw, GMAC_IRQ_MSK, 0); spin_lock_bh(&hw->phy_lock); - for (i = 0; i < ports; i++) { + for (i = 0; i < hw->ports; i++) { if (hw->chip_id == CHIP_ID_GENESIS) genesis_reset(hw, i); else @@ -3071,7 +3026,8 @@ static int skge_reset(struct skge_hw *hw) } /* Initialize network device */ -static struct net_device *skge_devinit(struct skge_hw *hw, int port) +static struct net_device *skge_devinit(struct skge_hw *hw, int port, + int highmem) { struct skge_port *skge; struct net_device *dev = alloc_etherdev(sizeof(*skge)); @@ -3104,6 +3060,8 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port) #endif dev->irq = hw->pdev->irq; dev->features = NETIF_F_LLTX; + if (highmem) + dev->features |= NETIF_F_HIGHDMA; skge = netdev_priv(dev); skge->netdev = dev; @@ -3117,7 +3075,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port) skge->flow_control = FLOW_MODE_SYMMETRIC; skge->duplex = -1; skge->speed = -1; - skge->advertising = skge_modes(hw); + skge->advertising = skge_supported_modes(hw); hw->dev[port] = dev; @@ -3125,10 +3083,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port) spin_lock_init(&skge->tx_lock); - init_timer(&skge->link_check); - skge->link_check.function = skge_link_timer; - skge->link_check.data = (unsigned long) skge; - init_timer(&skge->led_blink); skge->led_blink.function = skge_blink_timer; skge->led_blink.data = (unsigned long) skge; @@ -3232,14 +3186,11 @@ static int __devinit skge_probe(struct pci_dev *pdev, printk(KERN_INFO PFX "addr 0x%lx irq %d chip %s rev %d\n", pci_resource_start(pdev, 0), pdev->irq, - skge_board_name(hw), chip_rev(hw)); + skge_board_name(hw), hw->chip_rev); - if ((dev = skge_devinit(hw, 0)) == NULL) + if ((dev = skge_devinit(hw, 0, using_dac)) == NULL) goto err_out_led_off; - if (using_dac) - dev->features |= NETIF_F_HIGHDMA; - if ((err = register_netdev(dev))) { printk(KERN_ERR PFX "%s: cannot register net device\n", pci_name(pdev)); @@ -3248,10 +3199,7 @@ static int __devinit skge_probe(struct pci_dev *pdev, skge_show_addr(dev); - if (isdualport(hw) && (dev1 = skge_devinit(hw, 1))) { - if (using_dac) - dev1->features |= NETIF_F_HIGHDMA; - + if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) { if (register_netdev(dev1) == 0) skge_show_addr(dev1); else { @@ -3288,7 +3236,7 @@ static void __devexit skge_remove(struct pci_dev *pdev) struct skge_hw *hw = pci_get_drvdata(pdev); struct net_device *dev0, *dev1; - if(!hw) + if (!hw) return; if ((dev1 = hw->dev[1])) @@ -3316,7 +3264,7 @@ static int skge_suspend(struct pci_dev *pdev, u32 state) struct skge_hw *hw = pci_get_drvdata(pdev); int i, wol = 0; - for(i = 0; i < 2; i++) { + for (i = 0; i < 2; i++) { struct net_device *dev = hw->dev[i]; if (dev) { @@ -3349,11 +3297,11 @@ static int skge_resume(struct pci_dev *pdev) skge_reset(hw); - for(i = 0; i < 2; i++) { + for (i = 0; i < 2; i++) { struct net_device *dev = hw->dev[i]; if (dev) { netif_device_attach(dev); - if(netif_running(dev)) + if (netif_running(dev)) skge_up(dev); } } diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 36c62b6..14d0cc0 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -7,31 +7,6 @@ /* PCI config registers */ #define PCI_DEV_REG1 0x40 #define PCI_DEV_REG2 0x44 -#ifndef PCI_VPD -#define PCI_VPD 0x50 -#endif - -/* PCI_OUR_REG_2 32 bit Our Register 2 */ -enum { - PCI_VPD_WR_THR = 0xff<<24, /* Bit 31..24: VPD Write Threshold */ - PCI_DEV_SEL = 0x7f<<17, /* Bit 23..17: EEPROM Device Select */ - PCI_VPD_ROM_SZ = 7 <<14, /* Bit 16..14: VPD ROM Size */ - /* Bit 13..12: reserved */ - PCI_EN_DUMMY_RD = 1<<3, /* Enable Dummy Read */ - PCI_REV_DESC = 1<<2, /* Reverse Desc. Bytes */ - PCI_USEDATA64 = 1<<0, /* Use 64Bit Data bus ext */ -}; - -/* PCI_VPD_ADR_REG 16 bit VPD Address Register */ -enum { - PCI_VPD_FLAG = 1<<15, /* starts VPD rd/wr cycle */ - PCI_VPD_ADR_MSK =0x7fffL, /* Bit 14.. 0: VPD Address Mask */ - VPD_RES_ID = 0x82, - VPD_RES_READ = 0x90, - VPD_RES_WRITE = 0x81, - VPD_RES_END = 0x78, -}; - #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \ PCI_STATUS_SIG_SYSTEM_ERROR | \ @@ -39,7 +14,6 @@ enum { PCI_STATUS_REC_TARGET_ABORT | \ PCI_STATUS_PARITY) - enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, @@ -229,8 +203,11 @@ enum { IS_XA2_F = 1<<1, /* Q_XA2 End of Frame */ IS_XA2_C = 1<<0, /* Q_XA2 Encoding Error */ - IS_PORT_1 = IS_XA1_F| IS_R1_F| IS_MAC1, - IS_PORT_2 = IS_XA2_F| IS_R2_F| IS_MAC2, + IS_TO_PORT1 = IS_PA_TO_RX1 | IS_PA_TO_TX1, + IS_TO_PORT2 = IS_PA_TO_RX2 | IS_PA_TO_TX2, + + IS_PORT_1 = IS_XA1_F| IS_R1_F | IS_TO_PORT1 | IS_MAC1, + IS_PORT_2 = IS_XA2_F| IS_R2_F | IS_TO_PORT2 | IS_MAC2, }; @@ -288,14 +265,6 @@ enum { CHIP_REV_YU_LITE_A3 = 7, /* Chip Rev. for YUKON-Lite A3 */ }; -/* B2_LD_TEST 8 bit EPROM loader test register */ -enum { - LD_T_ON = 1<<3, /* Loader Test mode on */ - LD_T_OFF = 1<<2, /* Loader Test mode off */ - LD_T_STEP = 1<<1, /* Decrement FPROM addr. Counter */ - LD_START = 1<<0, /* Start loading FPROM */ -}; - /* B2_TI_CTRL 8 bit Timer control */ /* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */ enum { @@ -313,16 +282,6 @@ enum { TIM_T_STEP = 1<<0, /* Test step */ }; -/* B28_DPT_INI 32 bit Descriptor Poll Timer Init Val */ -/* B28_DPT_VAL 32 bit Descriptor Poll Timer Curr Val */ -/* B28_DPT_CTRL 8 bit Descriptor Poll Timer Ctrl Reg */ -enum { - DPT_MSK = 0x00ffffffL, /* Bit 23.. 0: Desc Poll Timer Bits */ - - DPT_START = 1<<1, /* Start Descriptor Poll Timer */ - DPT_STOP = 1<<0, /* Stop Descriptor Poll Timer */ -}; - /* B2_GP_IO 32 bit General Purpose I/O Register */ enum { GP_DIR_9 = 1<<25, /* IO_9 direct, 0=In/1=Out */ @@ -348,30 +307,6 @@ enum { GP_IO_0 = 1<<0, /* IO_0 pin */ }; -/* Rx/Tx Path related Arbiter Test Registers */ -/* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */ -/* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */ -/* B3_PA_TEST 16 bit Packet Arbiter Test Register */ -/* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */ -enum { - TX2_T_EV = 1<<15,/* TX2 Timeout/Recv Event occured */ - TX2_T_ON = 1<<14,/* TX2 Timeout/Recv Timer Test On */ - TX2_T_OFF = 1<<13,/* TX2 Timeout/Recv Timer Tst Off */ - TX2_T_STEP = 1<<12,/* TX2 Timeout/Recv Timer Step */ - TX1_T_EV = 1<<11,/* TX1 Timeout/Recv Event occured */ - TX1_T_ON = 1<<10,/* TX1 Timeout/Recv Timer Test On */ - TX1_T_OFF = 1<<9, /* TX1 Timeout/Recv Timer Tst Off */ - TX1_T_STEP = 1<<8, /* TX1 Timeout/Recv Timer Step */ - RX2_T_EV = 1<<7, /* RX2 Timeout/Recv Event occured */ - RX2_T_ON = 1<<6, /* RX2 Timeout/Recv Timer Test On */ - RX2_T_OFF = 1<<5, /* RX2 Timeout/Recv Timer Tst Off */ - RX2_T_STEP = 1<<4, /* RX2 Timeout/Recv Timer Step */ - RX1_T_EV = 1<<3, /* RX1 Timeout/Recv Event occured */ - RX1_T_ON = 1<<2, /* RX1 Timeout/Recv Timer Test On */ - RX1_T_OFF = 1<<1, /* RX1 Timeout/Recv Timer Tst Off */ - RX1_T_STEP = 1<<0, /* RX1 Timeout/Recv Timer Step */ -}; - /* Descriptor Bit Definition */ /* TxCtrl Transmit Buffer Control Field */ /* RxCtrl Receive Buffer Control Field */ @@ -428,14 +363,6 @@ enum { RI_RST_SET = 1<<0, /* Set RAM Interface Reset */ }; -/* B3_RI_TEST 8 bit RAM Iface Test Register */ -enum { - RI_T_EV = 1<<3, /* Timeout Event occured */ - RI_T_ON = 1<<2, /* Timeout Timer Test On */ - RI_T_OFF = 1<<1, /* Timeout Timer Test Off */ - RI_T_STEP = 1<<0, /* Timeout Timer Step */ -}; - /* MAC Arbiter Registers */ /* B3_MA_TO_CTRL 16 bit MAC Arbiter Timeout Ctrl Reg */ enum { @@ -452,19 +379,6 @@ enum { #define SK_PKT_TO_MAX 0xffff /* Maximum value */ #define SK_RI_TO_53 36 /* RAM interface timeout */ - -/* B3_MA_RC_CTRL 16 bit MAC Arbiter Recovery Ctrl Reg */ -enum { - MA_ENA_REC_TX2 = 1<<7, /* Enable Recovery Timer TX2 */ - MA_DIS_REC_TX2 = 1<<6, /* Disable Recovery Timer TX2 */ - MA_ENA_REC_TX1 = 1<<5, /* Enable Recovery Timer TX1 */ - MA_DIS_REC_TX1 = 1<<4, /* Disable Recovery Timer TX1 */ - MA_ENA_REC_RX2 = 1<<3, /* Enable Recovery Timer RX2 */ - MA_DIS_REC_RX2 = 1<<2, /* Disable Recovery Timer RX2 */ - MA_ENA_REC_RX1 = 1<<1, /* Enable Recovery Timer RX1 */ - MA_DIS_REC_RX1 = 1<<0, /* Disable Recovery Timer RX1 */ -}; - /* Packet Arbiter Registers */ /* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */ enum { @@ -488,7 +402,7 @@ enum { PA_ENA_TO_TX1 | PA_ENA_TO_TX2) -/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */ +/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */ /* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */ /* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */ /* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */ @@ -511,7 +425,7 @@ enum { /* * Bank 4 - 5 */ -/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */ +/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */ enum { TXA_ITI_INI = 0x0200,/* 32 bit Tx Arb Interval Timer Init Val*/ TXA_ITI_VAL = 0x0204,/* 32 bit Tx Arb Interval Timer Value */ @@ -537,7 +451,7 @@ enum { /* Queue Register Offsets, use Q_ADDR() to access */ enum { - B8_Q_REGS = 0x0400, /* base of Queue registers */ + B8_Q_REGS = 0x0400, /* base of Queue registers */ Q_D = 0x00, /* 8*32 bit Current Descriptor */ Q_DA_L = 0x20, /* 32 bit Current Descriptor Address Low dWord */ Q_DA_H = 0x24, /* 32 bit Current Descriptor Address High dWord */ @@ -618,8 +532,7 @@ enum { enum { PHY_ADDR_XMAC = 0<<8, PHY_ADDR_BCOM = 1<<8, - PHY_ADDR_LONE = 3<<8, - PHY_ADDR_NAT = 0<<8, + /* GPHY address (bits 15..11 of SMI control reg) */ PHY_ADDR_MARV = 0, }; @@ -986,7 +899,7 @@ enum { LINKLED_BLINK_OFF = 0x10, LINKLED_BLINK_ON = 0x20, }; - + /* GMAC and GPHY Control Registers (YUKON only) */ enum { GMAC_CTRL = 0x0f00,/* 32 bit GMAC Control Reg */ @@ -1151,54 +1064,6 @@ enum { PHY_MARV_FE_SPEC_2 = 0x1c,/* 16 bit r/w Specific Control Reg. 2 */ }; -/* Level One-PHY Registers, indirect addressed over XMAC */ -enum { - PHY_LONE_CTRL = 0x00,/* 16 bit r/w PHY Control Register */ - PHY_LONE_STAT = 0x01,/* 16 bit r/o PHY Status Register */ - PHY_LONE_ID0 = 0x02,/* 16 bit r/o PHY ID0 Register */ - PHY_LONE_ID1 = 0x03,/* 16 bit r/o PHY ID1 Register */ - PHY_LONE_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */ - PHY_LONE_AUNE_LP = 0x05,/* 16 bit r/o Link Part Ability Reg */ - PHY_LONE_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */ - PHY_LONE_NEPG = 0x07,/* 16 bit r/w Next Page Register */ - PHY_LONE_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */ - /* Level One-specific registers */ - PHY_LONE_1000T_CTRL = 0x09,/* 16 bit r/w 1000Base-T Control Reg */ - PHY_LONE_1000T_STAT = 0x0a,/* 16 bit r/o 1000Base-T Status Reg */ - PHY_LONE_EXT_STAT = 0x0f,/* 16 bit r/o Extended Status Reg */ - PHY_LONE_PORT_CFG = 0x10,/* 16 bit r/w Port Configuration Reg*/ - PHY_LONE_Q_STAT = 0x11,/* 16 bit r/o Quick Status Reg */ - PHY_LONE_INT_ENAB = 0x12,/* 16 bit r/w Interrupt Enable Reg */ - PHY_LONE_INT_STAT = 0x13,/* 16 bit r/o Interrupt Status Reg */ - PHY_LONE_LED_CFG = 0x14,/* 16 bit r/w LED Configuration Reg */ - PHY_LONE_PORT_CTRL = 0x15,/* 16 bit r/w Port Control Reg */ - PHY_LONE_CIM = 0x16,/* 16 bit r/o CIM Reg */ -}; - -/* National-PHY Registers, indirect addressed over XMAC */ -enum { - PHY_NAT_CTRL = 0x00,/* 16 bit r/w PHY Control Register */ - PHY_NAT_STAT = 0x01,/* 16 bit r/w PHY Status Register */ - PHY_NAT_ID0 = 0x02,/* 16 bit r/o PHY ID0 Register */ - PHY_NAT_ID1 = 0x03,/* 16 bit r/o PHY ID1 Register */ - PHY_NAT_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */ - PHY_NAT_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Ability Reg */ - PHY_NAT_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */ - PHY_NAT_NEPG = 0x07,/* 16 bit r/w Next Page Register */ - PHY_NAT_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner Reg */ - /* National-specific registers */ - PHY_NAT_1000T_CTRL = 0x09,/* 16 bit r/w 1000Base-T Control Reg */ - PHY_NAT_1000T_STAT = 0x0a,/* 16 bit r/o 1000Base-T Status Reg */ - PHY_NAT_EXT_STAT = 0x0f,/* 16 bit r/o Extended Status Register */ - PHY_NAT_EXT_CTRL1 = 0x10,/* 16 bit r/o Extended Control Reg1 */ - PHY_NAT_Q_STAT1 = 0x11,/* 16 bit r/o Quick Status Reg1 */ - PHY_NAT_10B_OP = 0x12,/* 16 bit r/o 10Base-T Operations Reg */ - PHY_NAT_EXT_CTRL2 = 0x13,/* 16 bit r/o Extended Control Reg1 */ - PHY_NAT_Q_STAT2 = 0x14,/* 16 bit r/o Quick Status Reg2 */ - - PHY_NAT_PHY_ADDR = 0x19,/* 16 bit r/o PHY Address Register */ -}; - enum { PHY_CT_RESET = 1<<15, /* Bit 15: (sc) clear all PHY related regs */ PHY_CT_LOOP = 1<<14, /* Bit 14: enable Loopback over PHY */ @@ -1253,8 +1118,29 @@ enum { PHY_MARV_ID1_Y2 = 0x0C91, /* Yukon-2 (PHY 88E1112) */ }; +/* Advertisement register bits */ enum { PHY_AN_NXT_PG = 1<<15, /* Bit 15: Request Next Page */ + PHY_AN_ACK = 1<<14, /* Bit 14: (ro) Acknowledge Received */ + PHY_AN_RF = 1<<13, /* Bit 13: Remote Fault Bits */ + + PHY_AN_PAUSE_ASYM = 1<<11,/* Bit 11: Try for asymmetric */ + PHY_AN_PAUSE_CAP = 1<<10, /* Bit 10: Try for pause */ + PHY_AN_100BASE4 = 1<<9, /* Bit 9: Try for 100mbps 4k packets */ + PHY_AN_100FULL = 1<<8, /* Bit 8: Try for 100mbps full-duplex */ + PHY_AN_100HALF = 1<<7, /* Bit 7: Try for 100mbps half-duplex */ + PHY_AN_10FULL = 1<<6, /* Bit 6: Try for 10mbps full-duplex */ + PHY_AN_10HALF = 1<<5, /* Bit 5: Try for 10mbps half-duplex */ + PHY_AN_CSMA = 1<<0, /* Bit 0: Only selector supported */ + PHY_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/ + PHY_AN_FULL = PHY_AN_100FULL | PHY_AN_10FULL | PHY_AN_CSMA, + PHY_AN_ALL = PHY_AN_10HALF | PHY_AN_10FULL | + PHY_AN_100HALF | PHY_AN_100FULL, +}; + +/* Xmac Specific */ +enum { + PHY_X_AN_NXT_PG = 1<<15, /* Bit 15: Request Next Page */ PHY_X_AN_ACK = 1<<14, /* Bit 14: (ro) Acknowledge Received */ PHY_X_AN_RFB = 3<<12,/* Bit 13..12: Remote Fault Bits */ @@ -1263,82 +1149,6 @@ enum { PHY_X_AN_FD = 1<<5, /* Bit 5: Full Duplex */ }; -enum { - PHY_B_AN_RF = 1<<13, /* Bit 13: Remote Fault */ - - PHY_B_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */ - PHY_B_AN_PC = 1<<10, /* Bit 10: Pause Capable */ - PHY_B_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/ -}; - -enum { - PHY_L_AN_RF = 1<<13, /* Bit 13: Remote Fault */ - /* Bit 12: reserved */ - PHY_L_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */ - PHY_L_AN_PC = 1<<10, /* Bit 10: Pause Capable */ - - PHY_L_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/ -}; - -/* PHY_NAT_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement */ -/* PHY_NAT_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/ -/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */ -enum { - PHY_N_AN_RF = 1<<13, /* Bit 13: Remote Fault */ - - PHY_N_AN_100F = 1<<11, /* Bit 11: 100Base-T2 FD Support */ - PHY_N_AN_100H = 1<<10, /* Bit 10: 100Base-T2 HD Support */ - - PHY_N_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/ -}; - -/* field type definition for PHY_x_AN_SEL */ -enum { - PHY_SEL_TYPE = 1, /* 00001 = Ethernet */ -}; - -enum { - PHY_ANE_LP_NP = 1<<3, /* Bit 3: Link Partner can Next Page */ - PHY_ANE_LOC_NP = 1<<2, /* Bit 2: Local PHY can Next Page */ - PHY_ANE_RX_PG = 1<<1, /* Bit 1: Page Received */ -}; - -enum { - PHY_ANE_PAR_DF = 1<<4, /* Bit 4: Parallel Detection Fault */ - - PHY_ANE_LP_CAP = 1<<0, /* Bit 0: Link Partner Auto-Neg. Cap. */ -}; - -enum { - PHY_NP_MORE = 1<<15, /* Bit 15: More, Next Pages to follow */ - PHY_NP_ACK1 = 1<<14, /* Bit 14: (ro) Ack1, for receiving a message */ - PHY_NP_MSG_VAL = 1<<13, /* Bit 13: Message Page valid */ - PHY_NP_ACK2 = 1<<12, /* Bit 12: Ack2, comply with msg content */ - PHY_NP_TOG = 1<<11, /* Bit 11: Toggle Bit, ensure sync */ - PHY_NP_MSG = 0x07ff, /* Bit 10..0: Message from/to Link Partner */ -}; - -enum { - PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */ - PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */ -}; - -enum { - PHY_X_RS_PAUSE = 3<<7,/* Bit 8..7: selected Pause Mode */ - PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */ - PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */ - PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */ - PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */ -}; - -/** Remote Fault Bits (PHY_X_AN_RFB) encoding */ -enum { - X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */ - X_RFB_LF = 1<<12, /* Bit 13..12 Link Failure */ - X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */ - X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */ -}; - /* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */ enum { PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */ @@ -1418,6 +1228,16 @@ enum { PHY_B_PES_MLT3_ER = 1<<0, /* Bit 0: MLT3 code Error */ }; +/* PHY_BCOM_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/ +/* PHY_BCOM_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/ +enum { + PHY_B_AN_RF = 1<<13, /* Bit 13: Remote Fault */ + + PHY_B_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */ + PHY_B_AN_PC = 1<<10, /* Bit 10: Pause Capable */ +}; + + /***** PHY_BCOM_FC_CTR 16 bit r/w False Carrier Counter *****/ enum { PHY_B_FC_CTR = 0xff, /* Bit 7..0: False Carrier Counter */ @@ -1478,7 +1298,9 @@ enum { PHY_B_IS_LST_CHANGE = 1<<1, /* Bit 1: Link Status Changed */ PHY_B_IS_CRC_ER = 1<<0, /* Bit 0: CRC Error */ }; -#define PHY_B_DEF_MSK (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) +#define PHY_B_DEF_MSK \ + (~(PHY_B_IS_PSE | PHY_B_IS_AN_PR | PHY_B_IS_DUP_CHANGE | \ + PHY_B_IS_LSP_CHANGE | PHY_B_IS_LST_CHANGE)) /* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */ enum { @@ -1495,166 +1317,6 @@ enum { PHY_B_RES_1000HD = 6<<8,/* Bit 10..8: 1000Base-T Half Dup. */ }; -/* - * Level One-Specific - */ -/***** PHY_LONE_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ -enum { - PHY_L_1000C_TEST = 7<<13,/* Bit 15..13: Test Modes */ - PHY_L_1000C_MSE = 1<<12, /* Bit 12: Master/Slave Enable */ - PHY_L_1000C_MSC = 1<<11, /* Bit 11: M/S Configuration */ - PHY_L_1000C_RD = 1<<10, /* Bit 10: Repeater/DTE */ - PHY_L_1000C_AFD = 1<<9, /* Bit 9: Advertise Full Duplex */ - PHY_L_1000C_AHD = 1<<8, /* Bit 8: Advertise Half Duplex */ -}; - -/***** PHY_LONE_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ -enum { - PHY_L_1000S_MSF = 1<<15, /* Bit 15: Master/Slave Fault */ - PHY_L_1000S_MSR = 1<<14, /* Bit 14: Master/Slave Result */ - PHY_L_1000S_LRS = 1<<13, /* Bit 13: Local Receiver Status */ - PHY_L_1000S_RRS = 1<<12, /* Bit 12: Remote Receiver Status */ - PHY_L_1000S_LP_FD = 1<<11, /* Bit 11: Link Partner can FD */ - PHY_L_1000S_LP_HD = 1<<10, /* Bit 10: Link Partner can HD */ - - PHY_L_1000S_IEC = 0xff, /* Bit 7..0: Idle Error Count */ - -/***** PHY_LONE_EXT_STAT 16 bit r/o Extended Status Register *****/ - PHY_L_ES_X_FD_CAP = 1<<15, /* Bit 15: 1000Base-X FD capable */ - PHY_L_ES_X_HD_CAP = 1<<14, /* Bit 14: 1000Base-X HD capable */ - PHY_L_ES_T_FD_CAP = 1<<13, /* Bit 13: 1000Base-T FD capable */ - PHY_L_ES_T_HD_CAP = 1<<12, /* Bit 12: 1000Base-T HD capable */ -}; - -/***** PHY_LONE_PORT_CFG 16 bit r/w Port Configuration Reg *****/ -enum { - PHY_L_PC_REP_MODE = 1<<15, /* Bit 15: Repeater Mode */ - - PHY_L_PC_TX_DIS = 1<<13, /* Bit 13: Tx output Disabled */ - PHY_L_PC_BY_SCR = 1<<12, /* Bit 12: Bypass Scrambler */ - PHY_L_PC_BY_45 = 1<<11, /* Bit 11: Bypass 4B5B-Decoder */ - PHY_L_PC_JAB_DIS = 1<<10, /* Bit 10: Jabber Disabled */ - PHY_L_PC_SQE = 1<<9, /* Bit 9: Enable Heartbeat */ - PHY_L_PC_TP_LOOP = 1<<8, /* Bit 8: TP Loopback */ - PHY_L_PC_SSS = 1<<7, /* Bit 7: Smart Speed Selection */ - PHY_L_PC_FIFO_SIZE = 1<<6, /* Bit 6: FIFO Size */ - PHY_L_PC_PRE_EN = 1<<5, /* Bit 5: Preamble Enable */ - PHY_L_PC_CIM = 1<<4, /* Bit 4: Carrier Integrity Mon */ - PHY_L_PC_10_SER = 1<<3, /* Bit 3: Use Serial Output */ - PHY_L_PC_ANISOL = 1<<2, /* Bit 2: Unisolate Port */ - PHY_L_PC_TEN_BIT = 1<<1, /* Bit 1: 10bit iface mode on */ - PHY_L_PC_ALTCLOCK = 1<<0, /* Bit 0: (ro) ALTCLOCK Mode on */ -}; - -/***** PHY_LONE_Q_STAT 16 bit r/o Quick Status Reg *****/ -enum { - PHY_L_QS_D_RATE = 3<<14,/* Bit 15..14: Data Rate */ - PHY_L_QS_TX_STAT = 1<<13, /* Bit 13: Transmitting */ - PHY_L_QS_RX_STAT = 1<<12, /* Bit 12: Receiving */ - PHY_L_QS_COL_STAT = 1<<11, /* Bit 11: Collision */ - PHY_L_QS_L_STAT = 1<<10, /* Bit 10: Link is up */ - PHY_L_QS_DUP_MOD = 1<<9, /* Bit 9: Full/Half Duplex */ - PHY_L_QS_AN = 1<<8, /* Bit 8: AutoNeg is On */ - PHY_L_QS_AN_C = 1<<7, /* Bit 7: AN is Complete */ - PHY_L_QS_LLE = 7<<4,/* Bit 6..4: Line Length Estim. */ - PHY_L_QS_PAUSE = 1<<3, /* Bit 3: LP advertised Pause */ - PHY_L_QS_AS_PAUSE = 1<<2, /* Bit 2: LP adv. asym. Pause */ - PHY_L_QS_ISOLATE = 1<<1, /* Bit 1: CIM Isolated */ - PHY_L_QS_EVENT = 1<<0, /* Bit 0: Event has occurred */ -}; - -/***** PHY_LONE_INT_ENAB 16 bit r/w Interrupt Enable Reg *****/ -/***** PHY_LONE_INT_STAT 16 bit r/o Interrupt Status Reg *****/ -enum { - PHY_L_IS_AN_F = 1<<13, /* Bit 13: Auto-Negotiation fault */ - PHY_L_IS_CROSS = 1<<11, /* Bit 11: Crossover used */ - PHY_L_IS_POL = 1<<10, /* Bit 10: Polarity correct. used */ - PHY_L_IS_SS = 1<<9, /* Bit 9: Smart Speed Downgrade */ - PHY_L_IS_CFULL = 1<<8, /* Bit 8: Counter Full */ - PHY_L_IS_AN_C = 1<<7, /* Bit 7: AutoNeg Complete */ - PHY_L_IS_SPEED = 1<<6, /* Bit 6: Speed Changed */ - PHY_L_IS_DUP = 1<<5, /* Bit 5: Duplex Changed */ - PHY_L_IS_LS = 1<<4, /* Bit 4: Link Status Changed */ - PHY_L_IS_ISOL = 1<<3, /* Bit 3: Isolate Occured */ - PHY_L_IS_MDINT = 1<<2, /* Bit 2: (ro) STAT: MII Int Pending */ - PHY_L_IS_INTEN = 1<<1, /* Bit 1: ENAB: Enable IRQs */ - PHY_L_IS_FORCE = 1<<0, /* Bit 0: ENAB: Force Interrupt */ -}; - -/* int. mask */ -#define PHY_L_DEF_MSK (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN) - -/***** PHY_LONE_LED_CFG 16 bit r/w LED Configuration Reg *****/ -enum { - PHY_L_LC_LEDC = 3<<14,/* Bit 15..14: Col/Blink/On/Off */ - PHY_L_LC_LEDR = 3<<12,/* Bit 13..12: Rx/Blink/On/Off */ - PHY_L_LC_LEDT = 3<<10,/* Bit 11..10: Tx/Blink/On/Off */ - PHY_L_LC_LEDG = 3<<8,/* Bit 9..8: Giga/Blink/On/Off */ - PHY_L_LC_LEDS = 3<<6,/* Bit 7..6: 10-100/Blink/On/Off */ - PHY_L_LC_LEDL = 3<<4,/* Bit 5..4: Link/Blink/On/Off */ - PHY_L_LC_LEDF = 3<<2,/* Bit 3..2: Duplex/Blink/On/Off */ - PHY_L_LC_PSTRECH= 1<<1, /* Bit 1: Strech LED Pulses */ - PHY_L_LC_FREQ = 1<<0, /* Bit 0: 30/100 ms */ -}; - -/***** PHY_LONE_PORT_CTRL 16 bit r/w Port Control Reg *****/ -enum { - PHY_L_PC_TX_TCLK = 1<<15, /* Bit 15: Enable TX_TCLK */ - PHY_L_PC_ALT_NP = 1<<13, /* Bit 14: Alternate Next Page */ - PHY_L_PC_GMII_ALT= 1<<12, /* Bit 13: Alternate GMII driver */ - PHY_L_PC_TEN_CRS = 1<<10, /* Bit 10: Extend CRS*/ -}; - -/***** PHY_LONE_CIM 16 bit r/o CIM Reg *****/ -enum { - PHY_L_CIM_ISOL = 0xff<<8,/* Bit 15..8: Isolate Count */ - PHY_L_CIM_FALSE_CAR = 0xff, /* Bit 7..0: False Carrier Count */ -}; - -/* - * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding - */ -enum { - PHY_L_P_NO_PAUSE= 0<<10,/* Bit 11..10: no Pause Mode */ - PHY_L_P_SYM_MD = 1<<10, /* Bit 11..10: symmetric Pause Mode */ - PHY_L_P_ASYM_MD = 2<<10,/* Bit 11..10: asymmetric Pause Mode */ - PHY_L_P_BOTH_MD = 3<<10,/* Bit 11..10: both Pause Mode */ -}; - -/* - * National-Specific - */ -/***** PHY_NAT_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/ -enum { - PHY_N_1000C_TEST= 7<<13,/* Bit 15..13: Test Modes */ - PHY_N_1000C_MSE = 1<<12, /* Bit 12: Master/Slave Enable */ - PHY_N_1000C_MSC = 1<<11, /* Bit 11: M/S Configuration */ - PHY_N_1000C_RD = 1<<10, /* Bit 10: Repeater/DTE */ - PHY_N_1000C_AFD = 1<<9, /* Bit 9: Advertise Full Duplex */ - PHY_N_1000C_AHD = 1<<8, /* Bit 8: Advertise Half Duplex */ - PHY_N_1000C_APC = 1<<7, /* Bit 7: Asymmetric Pause Cap. */}; - - -/***** PHY_NAT_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/ -enum { - PHY_N_1000S_MSF = 1<<15, /* Bit 15: Master/Slave Fault */ - PHY_N_1000S_MSR = 1<<14, /* Bit 14: Master/Slave Result */ - PHY_N_1000S_LRS = 1<<13, /* Bit 13: Local Receiver Status */ - PHY_N_1000S_RRS = 1<<12, /* Bit 12: Remote Receiver Status*/ - PHY_N_1000S_LP_FD= 1<<11, /* Bit 11: Link Partner can FD */ - PHY_N_1000S_LP_HD= 1<<10, /* Bit 10: Link Partner can HD */ - PHY_N_1000C_LP_APC= 1<<9, /* Bit 9: LP Asym. Pause Cap. */ - PHY_N_1000S_IEC = 0xff, /* Bit 7..0: Idle Error Count */ -}; - -/***** PHY_NAT_EXT_STAT 16 bit r/o Extended Status Register *****/ -enum { - PHY_N_ES_X_FD_CAP= 1<<15, /* Bit 15: 1000Base-X FD capable */ - PHY_N_ES_X_HD_CAP= 1<<14, /* Bit 14: 1000Base-X HD capable */ - PHY_N_ES_T_FD_CAP= 1<<13, /* Bit 13: 1000Base-T FD capable */ - PHY_N_ES_T_HD_CAP= 1<<12, /* Bit 12: 1000Base-T HD capable */ -}; - /** Marvell-Specific */ enum { PHY_M_AN_NXT_PG = 1<<15, /* Request Next Page */ @@ -1718,7 +1380,7 @@ enum { PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */ }; -#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK) +#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK) enum { PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */ @@ -2105,7 +1767,7 @@ enum { GM_GPSR_FC_RX_DIS = 1<<2, /* Bit 2: Rx Flow-Control Mode Disabled */ GM_GPSR_PROM_EN = 1<<1, /* Bit 1: Promiscuous Mode Enabled */ }; - + /* GM_GP_CTRL 16 bit r/w General Purpose Control Register */ enum { GM_GPCR_PROM_ENA = 1<<14, /* Bit 14: Enable Promiscuous Mode */ @@ -2127,7 +1789,7 @@ enum { #define GM_GPCR_SPEED_1000 (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100) #define GM_GPCR_AU_ALL_DIS (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS) - + /* GM_TX_CTRL 16 bit r/w Transmit Control Register */ enum { GM_TXCR_FORCE_JAM = 1<<15, /* Bit 15: Force Jam / Flow-Control */ @@ -2138,7 +1800,7 @@ enum { #define TX_COL_THR(x) (((x)<<10) & GM_TXCR_COL_THR_MSK) #define TX_COL_DEF 0x04 - + /* GM_RX_CTRL 16 bit r/w Receive Control Register */ enum { GM_RXCR_UCF_ENA = 1<<15, /* Bit 15: Enable Unicast filtering */ @@ -2146,7 +1808,7 @@ enum { GM_RXCR_CRC_DIS = 1<<13, /* Bit 13: Remove 4-byte CRC */ GM_RXCR_PASS_FC = 1<<12, /* Bit 12: Pass FC packets to FIFO */ }; - + /* GM_TX_PARAM 16 bit r/w Transmit Parameter Register */ enum { GM_TXPA_JAMLEN_MSK = 0x03<<14, /* Bit 15..14: Jam Length */ @@ -2171,7 +1833,7 @@ enum { GM_SMOD_JUMBO_ENA = 1<<8, /* Bit 8: Enable Jumbo (Max. Frame Len) */ GM_SMOD_IPG_MSK = 0x1f /* Bit 4..0: Inter-Packet Gap (IPG) */ }; - + #define DATA_BLIND_VAL(x) (((x)<<11) & GM_SMOD_DATABL_MSK) #define DATA_BLIND_DEF 0x04 @@ -2186,7 +1848,7 @@ enum { GM_SMI_CT_RD_VAL = 1<<4, /* Bit 4: Read Valid (Read completed) */ GM_SMI_CT_BUSY = 1<<3, /* Bit 3: Busy (Operation in progress) */ }; - + #define GM_SMI_CT_PHY_AD(x) (((x)<<11) & GM_SMI_CT_PHY_A_MSK) #define GM_SMI_CT_REG_AD(x) (((x)<<6) & GM_SMI_CT_REG_A_MSK) @@ -2195,7 +1857,7 @@ enum { GM_PAR_MIB_CLR = 1<<5, /* Bit 5: Set MIB Clear Counter Mode */ GM_PAR_MIB_TST = 1<<4, /* Bit 4: MIB Load Counter (Test Mode) */ }; - + /* Receive Frame Status Encoding */ enum { GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */ @@ -2217,12 +1879,12 @@ enum { /* * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR) */ - GMR_FS_ANY_ERR = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR | - GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC | + GMR_FS_ANY_ERR = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR | + GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_JABBER, /* Rx GMAC FIFO Flush Mask (default) */ RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR | - GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE | + GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER, }; @@ -2540,10 +2202,6 @@ enum { }; -/* XM_PHY_ADDR 16 bit r/w PHY Address Register */ -#define XM_PHY_ADDR_SZ 0x1f /* Bit 4..0: PHY Address bits */ - - /* XM_GP_PORT 32 bit r/w General Purpose Port Register */ enum { XM_GP_ANIP = 1<<6, /* Bit 6: (ro) Auto-Neg. in progress */ @@ -2662,8 +2320,8 @@ enum { }; #define XM_PAUSE_MODE (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I) -#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\ - XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA) +#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\ + XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA) /* XM_STAT_CMD 16 bit r/w Statistics Command Register */ enum { @@ -2793,28 +2451,20 @@ struct skge_hw { u32 intr_mask; struct net_device *dev[2]; - u8 mac_cfg; u8 chip_id; + u8 chip_rev; u8 phy_type; u8 pmd_type; u16 phy_addr; + u8 ports; u32 ram_size; u32 ram_offset; - + struct tasklet_struct ext_tasklet; spinlock_t phy_lock; }; -static inline int isdualport(const struct skge_hw *hw) -{ - return !(hw->mac_cfg & CFG_SNG_MAC); -} - -static inline u8 chip_rev(const struct skge_hw *hw) -{ - return (hw->mac_cfg & CFG_CHIP_R_MSK) >> 4; -} static inline int iscopper(const struct skge_hw *hw) { @@ -2827,7 +2477,7 @@ enum { FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */ FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */ }; - + struct skge_port { u32 msg_enable; struct skge_hw *hw; @@ -2853,8 +2503,8 @@ struct skge_port { void *mem; /* PCI memory for rings */ dma_addr_t dma; unsigned long mem_size; + unsigned int rx_buf_size; - struct timer_list link_check; struct timer_list led_blink; }; @@ -2863,7 +2513,6 @@ struct skge_port { static inline u32 skge_read32(const struct skge_hw *hw, int reg) { return readl(hw->regs + reg); - } static inline u16 skge_read16(const struct skge_hw *hw, int reg) @@ -2892,114 +2541,87 @@ static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val) } /* MAC Related Registers inside the device. */ -#define SKGEMAC_REG(port,reg) (((port)<<7)+(reg)) - -/* PCI config space can be accessed via memory mapped space */ -#define SKGEPCI_REG(reg) ((reg)+ 0x380) - -#define SKGEXM_REG(port, reg) \ +#define SK_REG(port,reg) (((port)<<7)+(reg)) +#define SK_XMAC_REG(port, reg) \ ((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1) -static inline u32 skge_xm_read32(const struct skge_hw *hw, int port, int reg) -{ - return skge_read32(hw, SKGEXM_REG(port,reg)); -} - -static inline u16 skge_xm_read16(const struct skge_hw *hw, int port, int reg) +static inline u32 xm_read32(const struct skge_hw *hw, int port, int reg) { - return skge_read16(hw, SKGEXM_REG(port,reg)); + u32 v; + v = skge_read16(hw, SK_XMAC_REG(port, reg)); + v |= (u32)skge_read16(hw, SK_XMAC_REG(port, reg+2)) << 16; + return v; } -static inline u8 skge_xm_read8(const struct skge_hw *hw, int port, int reg) +static inline u16 xm_read16(const struct skge_hw *hw, int port, int reg) { - return skge_read8(hw, SKGEXM_REG(port,reg)); + return skge_read16(hw, SK_XMAC_REG(port,reg)); } -static inline void skge_xm_write32(const struct skge_hw *hw, int port, int r, u32 v) +static inline void xm_write32(const struct skge_hw *hw, int port, int r, u32 v) { - skge_write32(hw, SKGEXM_REG(port,r), v); + skge_write16(hw, SK_XMAC_REG(port,r), v & 0xffff); + skge_write16(hw, SK_XMAC_REG(port,r+2), v >> 16); } -static inline void skge_xm_write16(const struct skge_hw *hw, int port, int r, u16 v) +static inline void xm_write16(const struct skge_hw *hw, int port, int r, u16 v) { - skge_write16(hw, SKGEXM_REG(port,r), v); + skge_write16(hw, SK_XMAC_REG(port,r), v); } -static inline void skge_xm_write8(const struct skge_hw *hw, int port, int r, u8 v) -{ - skge_write8(hw, SKGEXM_REG(port,r), v); -} - -static inline void skge_xm_outhash(const struct skge_hw *hw, int port, int reg, +static inline void xm_outhash(const struct skge_hw *hw, int port, int reg, const u8 *hash) { - skge_xm_write16(hw, port, reg, - (u16)hash[0] | ((u16)hash[1] << 8)); - skge_xm_write16(hw, port, reg+2, - (u16)hash[2] | ((u16)hash[3] << 8)); - skge_xm_write16(hw, port, reg+4, - (u16)hash[4] | ((u16)hash[5] << 8)); - skge_xm_write16(hw, port, reg+6, - (u16)hash[6] | ((u16)hash[7] << 8)); + xm_write16(hw, port, reg, (u16)hash[0] | ((u16)hash[1] << 8)); + xm_write16(hw, port, reg+2, (u16)hash[2] | ((u16)hash[3] << 8)); + xm_write16(hw, port, reg+4, (u16)hash[4] | ((u16)hash[5] << 8)); + xm_write16(hw, port, reg+6, (u16)hash[6] | ((u16)hash[7] << 8)); } -static inline void skge_xm_outaddr(const struct skge_hw *hw, int port, int reg, +static inline void xm_outaddr(const struct skge_hw *hw, int port, int reg, const u8 *addr) { - skge_xm_write16(hw, port, reg, - (u16)addr[0] | ((u16)addr[1] << 8)); - skge_xm_write16(hw, port, reg, - (u16)addr[2] | ((u16)addr[3] << 8)); - skge_xm_write16(hw, port, reg, - (u16)addr[4] | ((u16)addr[5] << 8)); + xm_write16(hw, port, reg, (u16)addr[0] | ((u16)addr[1] << 8)); + xm_write16(hw, port, reg+2, (u16)addr[2] | ((u16)addr[3] << 8)); + xm_write16(hw, port, reg+4, (u16)addr[4] | ((u16)addr[5] << 8)); } +#define SK_GMAC_REG(port,reg) \ + (BASE_GMAC_1 + (port) * (BASE_GMAC_2-BASE_GMAC_1) + (reg)) -#define SKGEGMA_REG(port,reg) \ - ((reg) + BASE_GMAC_1 + \ - (port) * (BASE_GMAC_2-BASE_GMAC_1)) - -static inline u16 skge_gma_read16(const struct skge_hw *hw, int port, int reg) +static inline u16 gma_read16(const struct skge_hw *hw, int port, int reg) { - return skge_read16(hw, SKGEGMA_REG(port,reg)); + return skge_read16(hw, SK_GMAC_REG(port,reg)); } -static inline u32 skge_gma_read32(const struct skge_hw *hw, int port, int reg) +static inline u32 gma_read32(const struct skge_hw *hw, int port, int reg) { - return (u32) skge_read16(hw, SKGEGMA_REG(port,reg)) - | ((u32)skge_read16(hw, SKGEGMA_REG(port,reg+4)) << 16); + return (u32) skge_read16(hw, SK_GMAC_REG(port,reg)) + | ((u32)skge_read16(hw, SK_GMAC_REG(port,reg+4)) << 16); } -static inline u8 skge_gma_read8(const struct skge_hw *hw, int port, int reg) +static inline void gma_write16(const struct skge_hw *hw, int port, int r, u16 v) { - return skge_read8(hw, SKGEGMA_REG(port,reg)); + skge_write16(hw, SK_GMAC_REG(port,r), v); } -static inline void skge_gma_write16(const struct skge_hw *hw, int port, int r, u16 v) +static inline void gma_write32(const struct skge_hw *hw, int port, int r, u32 v) { - skge_write16(hw, SKGEGMA_REG(port,r), v); + skge_write16(hw, SK_GMAC_REG(port, r), (u16) v); + skge_write32(hw, SK_GMAC_REG(port, r+4), (u16)(v >> 16)); } -static inline void skge_gma_write32(const struct skge_hw *hw, int port, int r, u32 v) +static inline void gma_write8(const struct skge_hw *hw, int port, int r, u8 v) { - skge_write16(hw, SKGEGMA_REG(port, r), (u16) v); - skge_write32(hw, SKGEGMA_REG(port, r+4), (u16)(v >> 16)); + skge_write8(hw, SK_GMAC_REG(port,r), v); } -static inline void skge_gma_write8(const struct skge_hw *hw, int port, int r, u8 v) -{ - skge_write8(hw, SKGEGMA_REG(port,r), v); -} - -static inline void skge_gm_set_addr(struct skge_hw *hw, int port, int reg, +static inline void gma_set_addr(struct skge_hw *hw, int port, int reg, const u8 *addr) { - skge_gma_write16(hw, port, reg, - (u16) addr[0] | ((u16) addr[1] << 8)); - skge_gma_write16(hw, port, reg+4, - (u16) addr[2] | ((u16) addr[3] << 8)); - skge_gma_write16(hw, port, reg+8, - (u16) addr[4] | ((u16) addr[5] << 8)); + gma_write16(hw, port, reg, (u16) addr[0] | ((u16) addr[1] << 8)); + gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8)); + gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8)); } - + #endif diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 16363b5..404ea42 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -74,6 +74,7 @@ #include <linux/rtnetlink.h> #include <linux/if_arp.h> #include <linux/if_slip.h> +#include <linux/delay.h> #include <linux/init.h> #include "slip.h" #ifdef CONFIG_INET diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index cfb9d3c..1438fdd 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1998,7 +1998,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) if (retval) goto err_out; - set_irq_type(dev->irq, IRQT_RISING); + set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE); #ifdef SMC_USE_PXA_DMA { diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 946528e..7089d86 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -182,6 +182,16 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) #define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) +#include <asm/mach-types.h> +#include <asm/arch/cpu.h> + +#define SMC_IRQ_TRIGGER_TYPE (( \ + machine_is_omap_h2() \ + || machine_is_omap_h3() \ + || (machine_is_omap_innovator() && !cpu_is_omap150()) \ + ) ? IRQT_FALLING : IRQT_RISING) + + #elif defined(CONFIG_SH_SH4202_MICRODEV) #define SMC_CAN_USE_8BIT 0 @@ -300,6 +310,9 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) #endif +#ifndef SMC_IRQ_TRIGGER_TYPE +#define SMC_IRQ_TRIGGER_TYPE IRQT_RISING +#endif #ifdef SMC_USE_PXA_DMA /* diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 12e2b68..88b89dc 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1286,7 +1286,7 @@ static void init_ring(struct net_device *dev) np->rx_info[i].skb = skb; if (skb == NULL) break; - np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb->dev = dev; /* Mark as being used by this device. */ /* Grrr, we cannot offset to correctly align the IP header. */ np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid); @@ -1572,7 +1572,7 @@ static int __netdev_rx(struct net_device *dev, int *quota) pci_dma_sync_single_for_cpu(np->pci_dev, np->rx_info[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0); + eth_copy_and_sum(skb, np->rx_info[entry].skb->data, pkt_len, 0); pci_dma_sync_single_for_device(np->pci_dev, np->rx_info[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); @@ -1696,7 +1696,7 @@ static void refill_rx_ring(struct net_device *dev) if (skb == NULL) break; /* Better luck next round. */ np->rx_info[entry].mapping = - pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb->dev = dev; /* Mark as being used by this device. */ np->rx_ring[entry].rxaddr = cpu_to_dma(np->rx_info[entry].mapping | RxDescValid); diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 08cb717..d500a57 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1028,7 +1028,7 @@ static void init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ np->rx_ring[i].frag[0].addr = cpu_to_le32( - pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, + pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag); } @@ -1341,7 +1341,7 @@ static void rx_poll(unsigned long data) np->rx_buf_sz, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0); pci_dma_sync_single_for_device(np->pci_dev, desc->frag[0].addr, np->rx_buf_sz, @@ -1400,7 +1400,7 @@ static void refill_rx (struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ np->rx_ring[entry].frag[0].addr = cpu_to_le32( - pci_map_single(np->pci_dev, skb->tail, + pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE)); } /* Perhaps we need not reset this field. */ diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index dd357dd..fc353e3 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -446,13 +446,13 @@ static void de_rx (struct de_private *de) mapping = de->rx_skb[rx_tail].mapping = - pci_map_single(de->pdev, copy_skb->tail, + pci_map_single(de->pdev, copy_skb->data, buflen, PCI_DMA_FROMDEVICE); de->rx_skb[rx_tail].skb = copy_skb; } else { pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); skb_reserve(copy_skb, RX_OFFSET); - memcpy(skb_put(copy_skb, len), skb->tail, len); + memcpy(skb_put(copy_skb, len), skb->data, len); pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); @@ -1269,7 +1269,7 @@ static int de_refill_rx (struct de_private *de) skb->dev = de->dev; de->rx_skb[i].mapping = pci_map_single(de->pdev, - skb->tail, de->rx_buf_sz, PCI_DMA_FROMDEVICE); + skb->data, de->rx_buf_sz, PCI_DMA_FROMDEVICE); de->rx_skb[i].skb = skb; de->rx_ring[i].opts1 = cpu_to_le32(DescOwn); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 7b89970..74e9075 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -945,8 +945,8 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) /* Received Packet CRC check need or not */ if ( (db->dm910x_chk_mode & 1) && - (cal_CRC(skb->tail, rxlen, 1) != - (*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */ + (cal_CRC(skb->data, rxlen, 1) != + (*(u32 *) (skb->data+rxlen) ))) { /* FIXME (?) */ /* Found a error received packet */ dmfe_reuse_skb(db, rxptr->rx_skb_ptr); db->dm910x_chk_mode = 3; @@ -959,7 +959,7 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) /* size less than COPY_SIZE, allocate a rxlen SKB */ skb->dev = dev; skb_reserve(skb, 2); /* 16byte align */ - memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen); + memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->data, rxlen); dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } else { skb->dev = dev; @@ -1252,7 +1252,7 @@ static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb) if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) { rxptr->rx_skb_ptr = skb; - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); db->rx_avail_cnt++; @@ -1463,7 +1463,7 @@ static void allocate_rx_buffer(struct dmfe_board_info *db) if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) break; rxptr->rx_skb_ptr = skb; /* FIXME (?) */ - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); rxptr = rxptr->next_rx_desc; diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index afb5cda..bb35581 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -78,7 +78,7 @@ int tulip_refill_rx(struct net_device *dev) if (skb == NULL) break; - mapping = pci_map_single(tp->pdev, skb->tail, PKT_BUF_SZ, + mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); tp->rx_buffers[entry].mapping = mapping; @@ -199,12 +199,12 @@ int tulip_poll(struct net_device *dev, int *budget) tp->rx_buffers[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) - eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, + eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data, pkt_len, 0); skb_put(skb, pkt_len); #else memcpy(skb_put(skb, pkt_len), - tp->rx_buffers[entry].skb->tail, + tp->rx_buffers[entry].skb->data, pkt_len); #endif pci_dma_sync_single_for_device(tp->pdev, @@ -423,12 +423,12 @@ static int tulip_rx(struct net_device *dev) tp->rx_buffers[entry].mapping, pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) - eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, + eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data, pkt_len, 0); skb_put(skb, pkt_len); #else memcpy(skb_put(skb, pkt_len), - tp->rx_buffers[entry].skb->tail, + tp->rx_buffers[entry].skb->data, pkt_len); #endif pci_dma_sync_single_for_device(tp->pdev, diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 08e0f80..d45d8f5 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -625,7 +625,7 @@ static void tulip_init_ring(struct net_device *dev) tp->rx_buffers[i].skb = skb; if (skb == NULL) break; - mapping = pci_map_single(tp->pdev, skb->tail, + mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); tp->rx_buffers[i].mapping = mapping; skb->dev = dev; /* Mark as being used by this device. */ diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index db4b32c..5b1af39 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -849,7 +849,7 @@ static void init_rxtx_rings(struct net_device *dev) if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ - np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail, + np->rx_addr[i] = pci_map_single(np->pci_dev,skb->data, skb->len,PCI_DMA_FROMDEVICE); np->rx_ring[i].buffer1 = np->rx_addr[i]; @@ -1269,7 +1269,7 @@ static int netdev_rx(struct net_device *dev) pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, @@ -1315,7 +1315,7 @@ static int netdev_rx(struct net_device *dev) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ np->rx_addr[entry] = pci_map_single(np->pci_dev, - skb->tail, + skb->data, skb->len, PCI_DMA_FROMDEVICE); np->rx_ring[entry].buffer1 = np->rx_addr[entry]; } diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c index b8a9b39..887d724 100644 --- a/drivers/net/tulip/xircom_tulip_cb.c +++ b/drivers/net/tulip/xircom_tulip_cb.c @@ -899,7 +899,7 @@ static void xircom_init_ring(struct net_device *dev) break; skb->dev = dev; /* Mark as being used by this device. */ tp->rx_ring[i].status = Rx0DescOwned; /* Owned by Xircom chip */ - tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail); + tp->rx_ring[i].buffer1 = virt_to_bus(skb->data); } tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -1291,7 +1291,7 @@ xircom_rx(struct net_device *dev) if (skb == NULL) break; skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail); + tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data); work_done++; } tp->rx_ring[entry].status = Rx0DescOwned; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 8f33929..0b5ca25 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1661,7 +1661,7 @@ typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx) #endif skb->dev = tp->dev; - dma_addr = pci_map_single(tp->pdev, skb->tail, + dma_addr = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* Since no card does 64 bit DAC, the high bits will never @@ -1721,7 +1721,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready, pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); - eth_copy_and_sum(new_skb, skb->tail, pkt_len, 0); + eth_copy_and_sum(new_skb, skb->data, pkt_len, 0); pci_dma_sync_single_for_device(tp->pdev, dma_addr, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index be1c104..fc7738f 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -507,7 +507,7 @@ static struct net_device_stats *rhine_get_stats(struct net_device *dev); static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct ethtool_ops netdev_ethtool_ops; static int rhine_close(struct net_device *dev); -static void rhine_shutdown (struct device *gdev); +static void rhine_shutdown (struct pci_dev *pdev); #define RHINE_WAIT_FOR(condition) do { \ int i=1024; \ @@ -990,7 +990,7 @@ static void alloc_rbufs(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ rp->rx_skbuff_dma[i] = - pci_map_single(rp->pdev, skb->tail, rp->rx_buf_sz, + pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz, PCI_DMA_FROMDEVICE); rp->rx_ring[i].addr = cpu_to_le32(rp->rx_skbuff_dma[i]); @@ -1518,7 +1518,7 @@ static void rhine_rx(struct net_device *dev) PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, - rp->rx_skbuff[entry]->tail, + rp->rx_skbuff[entry]->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(rp->pdev, @@ -1561,7 +1561,7 @@ static void rhine_rx(struct net_device *dev) break; /* Better luck next round. */ skb->dev = dev; /* Mark as being used by this device. */ rp->rx_skbuff_dma[entry] = - pci_map_single(rp->pdev, skb->tail, + pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz, PCI_DMA_FROMDEVICE); rp->rx_ring[entry].addr = cpu_to_le32(rp->rx_skbuff_dma[entry]); @@ -1895,9 +1895,8 @@ static void __devexit rhine_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } -static void rhine_shutdown (struct device *gendev) +static void rhine_shutdown (struct pci_dev *pdev) { - struct pci_dev *pdev = to_pci_dev(gendev); struct net_device *dev = pci_get_drvdata(pdev); struct rhine_private *rp = netdev_priv(dev); void __iomem *ioaddr = rp->base; @@ -1956,7 +1955,7 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); spin_lock_irqsave(&rp->lock, flags); - rhine_shutdown(&pdev->dev); + rhine_shutdown(pdev); spin_unlock_irqrestore(&rp->lock, flags); free_irq(dev->irq, dev); @@ -2010,9 +2009,7 @@ static struct pci_driver rhine_driver = { .suspend = rhine_suspend, .resume = rhine_resume, #endif /* CONFIG_PM */ - .driver = { - .shutdown = rhine_shutdown, - } + .shutdown = rhine_shutdown, }; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 15e7102..abc5cee 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1335,7 +1335,7 @@ static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size, if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN) skb_reserve(new_skb, 2); - memcpy(new_skb->data, rx_skb[0]->tail, pkt_size); + memcpy(new_skb->data, rx_skb[0]->data, pkt_size); *rx_skb = new_skb; ret = 0; } @@ -1456,9 +1456,9 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) * Do the gymnastics to get the buffer head for data at * 64byte alignment. */ - skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->tail & 63); + skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63); rd_info->skb->dev = vptr->dev; - rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->tail, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); + rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE); /* * Fill in the descriptor to match diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index c1b6896..8749684 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -72,7 +72,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, } skb_reserve(skb, 4); cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); - data = (cisco_packet*)skb->tail; + data = (cisco_packet*)skb->data; data->type = htonl(type); data->par1 = htonl(par1); diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 9da9254..1c25065 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -786,7 +786,7 @@ static void yellowfin_init_ring(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* 16 byte align the IP header. */ yp->rx_ring[i].addr = cpu_to_le32(pci_map_single(yp->pci_dev, - skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); } yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP); yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); @@ -1111,7 +1111,7 @@ static int yellowfin_rx(struct net_device *dev) pci_dma_sync_single_for_cpu(yp->pci_dev, desc->addr, yp->rx_buf_sz, PCI_DMA_FROMDEVICE); desc_status = le32_to_cpu(desc->result_status) >> 16; - buf_addr = rx_skb->tail; + buf_addr = rx_skb->data; data_size = (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status)) & 0xffff; frame_status = le16_to_cpu(get_unaligned((s16*)&(buf_addr[data_size - 2]))); @@ -1185,7 +1185,7 @@ static int yellowfin_rx(struct net_device *dev) break; skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - eth_copy_and_sum(skb, rx_skb->tail, pkt_len, 0); + eth_copy_and_sum(skb, rx_skb->data, pkt_len, 0); skb_put(skb, pkt_len); pci_dma_sync_single_for_device(yp->pci_dev, desc->addr, yp->rx_buf_sz, @@ -1211,7 +1211,7 @@ static int yellowfin_rx(struct net_device *dev) skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ yp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev, - skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); + skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE)); } yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP); yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */ diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index b0d2a73..2f2dbef2 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -993,6 +993,7 @@ dino_driver_callback(struct parisc_device *dev) bus = pci_scan_bus_parented(&dev->dev, dino_current_bus, &dino_cfg_ops, NULL); if(bus) { + pci_bus_add_devices(bus); /* This code *depends* on scanning being single threaded * if it isn't, this global bus number count will fail */ diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index dc83880..7fdd80b 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1570,6 +1570,8 @@ lba_driver_probe(struct parisc_device *dev) lba_bus = lba_dev->hba.hba_bus = pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start, cfg_ops, NULL); + if (lba_bus) + pci_bus_add_devices(lba_bus); /* This is in lieu of calling pci_assign_unassigned_resources() */ if (is_pdc_pat()) { diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index dbd3360..fedae89 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -121,10 +121,13 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) * If there is an unattached subordinate bus, attach * it and then scan for unattached PCI devices. */ - if (dev->subordinate && list_empty(&dev->subordinate->node)) { - spin_lock(&pci_bus_lock); - list_add_tail(&dev->subordinate->node, &dev->bus->children); - spin_unlock(&pci_bus_lock); + if (dev->subordinate) { + if (list_empty(&dev->subordinate->node)) { + spin_lock(&pci_bus_lock); + list_add_tail(&dev->subordinate->node, + &dev->bus->children); + spin_unlock(&pci_bus_lock); + } pci_bus_add_devices(dev->subordinate); sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge"); diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile index 93c120d..3e632ff 100644 --- a/drivers/pci/hotplug/Makefile +++ b/drivers/pci/hotplug/Makefile @@ -36,9 +36,7 @@ ibmphp-objs := ibmphp_core.o \ ibmphp_hpc.o acpiphp-objs := acpiphp_core.o \ - acpiphp_glue.o \ - acpiphp_pci.o \ - acpiphp_res.o + acpiphp_glue.o rpaphp-objs := rpaphp_core.o \ rpaphp_pci.o \ diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index d949987..293603e 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -7,6 +7,8 @@ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation + * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) + * Copyright (C) 2003-2005 Hewlett Packard * * All rights reserved. * @@ -52,7 +54,6 @@ struct acpiphp_bridge; struct acpiphp_slot; -struct pci_resource; /* * struct slot - slot information for each *physical* slot @@ -65,15 +66,6 @@ struct slot { struct acpiphp_slot *acpi_slot; }; -/* - * struct pci_resource - describes pci resource (mem, pfmem, io, bus) - */ -struct pci_resource { - struct pci_resource * next; - u64 base; - u32 length; -}; - /** * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters * @cache_line_size in DWORD @@ -101,10 +93,6 @@ struct acpiphp_bridge { int type; int nr_slots; - u8 seg; - u8 bus; - u8 sub; - u32 flags; /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ @@ -117,12 +105,6 @@ struct acpiphp_bridge { struct hpp_param hpp; spinlock_t res_lock; - - /* available resources on this bus */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; }; @@ -163,12 +145,6 @@ struct acpiphp_func { u8 function; /* pci function# */ u32 flags; /* see below */ - - /* resources used for this function */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; }; /** @@ -243,25 +219,6 @@ extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); extern u32 acpiphp_get_address (struct acpiphp_slot *slot); -/* acpiphp_pci.c */ -extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); -extern int acpiphp_configure_slot (struct acpiphp_slot *slot); -extern int acpiphp_configure_function (struct acpiphp_func *func); -extern void acpiphp_unconfigure_function (struct acpiphp_func *func); -extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge); -extern int acpiphp_init_func_resource (struct acpiphp_func *func); - -/* acpiphp_res.c */ -extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size); -extern int acpiphp_resource_sort_and_combine (struct pci_resource **head); -extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length); -extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to); -extern void acpiphp_free_resource (struct pci_resource **res); -extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */ -extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */ - /* variables */ extern int acpiphp_debug; diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 4539e61..60c4c38 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -7,6 +7,8 @@ * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation + * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) + * Copyright (C) 2003-2005 Hewlett Packard * * All rights reserved. * @@ -53,8 +55,8 @@ int acpiphp_debug; static int num_slots; static struct acpiphp_attention_info *attention_info; -#define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>" +#define DRIVER_VERSION "0.5" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@hp.com>" #define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" MODULE_AUTHOR(DRIVER_AUTHOR); @@ -281,8 +283,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) /** * get_address - get pci address of a slot * @hotplug_slot: slot to get status - * @busdev: pointer to struct pci_busdev (seg, bus, dev) - * + * @value: pointer to struct pci_busdev (seg, bus, dev) */ static int get_address(struct hotplug_slot *hotplug_slot, u32 *value) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e7f4129..424e7de 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -4,6 +4,10 @@ * Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com) * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) * Copyright (C) 2002,2003 NEC Corporation + * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) + * Copyright (C) 2003-2005 Hewlett Packard + * Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com) + * Copyright (C) 2005 Intel Corporation * * All rights reserved. * @@ -26,6 +30,16 @@ * */ +/* + * Lifetime rules for pci_dev: + * - The one in acpiphp_func has its refcount elevated by pci_get_slot() + * when the driver is loaded or when an insertion event occurs. It loses + * a refcount when its ejected or the driver unloads. + * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot() + * when the bridge is scanned and it loses a refcount when the bridge + * is removed. + */ + #include <linux/init.h> #include <linux/module.h> @@ -178,21 +192,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) bridge->nr_slots++; - dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n", - slot->bridge->bus, slot->device, slot->sun); + dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n", + slot->sun, pci_domain_nr(bridge->pci_bus), + bridge->pci_bus->number, slot->device); } newfunc->slot = slot; list_add_tail(&newfunc->sibling, &slot->funcs); /* associate corresponding pci_dev */ - newfunc->pci_dev = pci_find_slot(bridge->bus, + newfunc->pci_dev = pci_get_slot(bridge->pci_bus, PCI_DEVFN(device, function)); if (newfunc->pci_dev) { - if (acpiphp_init_func_resource(newfunc) < 0) { - kfree(newfunc); - return AE_ERROR; - } slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); } @@ -227,62 +238,6 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle) } -/* decode ACPI _CRS data and convert into our internal resource list - * TBD: _TRA, etc. - */ -static acpi_status -decode_acpi_resource(struct acpi_resource *resource, void *context) -{ - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context; - struct acpi_resource_address64 address; - struct pci_resource *res; - - if (resource->id != ACPI_RSTYPE_ADDRESS16 && - resource->id != ACPI_RSTYPE_ADDRESS32 && - resource->id != ACPI_RSTYPE_ADDRESS64) - return AE_OK; - - acpi_resource_to_address64(resource, &address); - - if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) { - dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type, - (unsigned long long)address.min_address_range, - (unsigned long long)address.max_address_range); - res = acpiphp_make_resource(address.min_address_range, - address.address_length); - if (!res) { - err("out of memory\n"); - return AE_OK; - } - - switch (address.resource_type) { - case ACPI_MEMORY_RANGE: - if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) { - res->next = bridge->p_mem_head; - bridge->p_mem_head = res; - } else { - res->next = bridge->mem_head; - bridge->mem_head = res; - } - break; - case ACPI_IO_RANGE: - res->next = bridge->io_head; - bridge->io_head = res; - break; - case ACPI_BUS_NUMBER_RANGE: - res->next = bridge->bus_head; - bridge->bus_head = res; - break; - default: - /* invalid type */ - kfree(res); - break; - } - } - - return AE_OK; -} - /* decode ACPI 2.0 _HPP hot plug parameters */ static void decode_hpp(struct acpiphp_bridge *bridge) { @@ -346,34 +301,29 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) /* decode ACPI 2.0 _HPP (hot plug parameters) */ decode_hpp(bridge); - /* subtract all resources already allocated */ - acpiphp_detect_pci_resource(bridge); - /* register all slot objects under this bridge */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, register_slot, bridge, NULL); /* install notify handler */ - status = acpi_install_notify_handler(bridge->handle, + if (bridge->type != BRIDGE_TYPE_HOST) { + status = acpi_install_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge, bridge); - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler\n"); + } } list_add(&bridge->list, &bridge_list); - - dbg("Bridge resource:\n"); - acpiphp_dump_resource(bridge); } /* allocate and initialize host bridge data structure */ -static void add_host_bridge(acpi_handle *handle, int seg, int bus) +static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) { - acpi_status status; struct acpiphp_bridge *bridge; bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); @@ -384,52 +334,19 @@ static void add_host_bridge(acpi_handle *handle, int seg, int bus) bridge->type = BRIDGE_TYPE_HOST; bridge->handle = handle; - bridge->seg = seg; - bridge->bus = bus; - bridge->pci_bus = pci_find_bus(seg, bus); + bridge->pci_bus = pci_bus; spin_lock_init(&bridge->res_lock); - /* to be overridden when we decode _CRS */ - bridge->sub = bridge->bus; - - /* decode resources */ - - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - decode_acpi_resource, bridge); - - if (ACPI_FAILURE(status)) { - err("failed to decode bridge resources\n"); - kfree(bridge); - return; - } - - acpiphp_resource_sort_and_combine(&bridge->io_head); - acpiphp_resource_sort_and_combine(&bridge->mem_head); - acpiphp_resource_sort_and_combine(&bridge->p_mem_head); - acpiphp_resource_sort_and_combine(&bridge->bus_head); - - dbg("ACPI _CRS resource:\n"); - acpiphp_dump_resource(bridge); - - if (bridge->bus_head) { - bridge->bus = bridge->bus_head->base; - bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1; - } - init_bridge_misc(bridge); } /* allocate and initialize PCI-to-PCI bridge data structure */ -static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int fn) +static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) { struct acpiphp_bridge *bridge; - u8 tmp8; - u16 tmp16; - u64 base64, limit64; - u32 base, limit, base32u, limit32u; bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); if (bridge == NULL) { @@ -441,133 +358,22 @@ static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int f bridge->type = BRIDGE_TYPE_P2P; bridge->handle = handle; - bridge->seg = seg; - - bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn)); - if (!bridge->pci_dev) { - err("Can't get pci_dev\n"); - kfree(bridge); - return; - } - bridge->pci_bus = bridge->pci_dev->subordinate; + bridge->pci_dev = pci_dev_get(pci_dev); + bridge->pci_bus = pci_dev->subordinate; if (!bridge->pci_bus) { err("This is not a PCI-to-PCI bridge!\n"); - kfree(bridge); - return; + goto err; } spin_lock_init(&bridge->res_lock); - bridge->bus = bridge->pci_bus->number; - bridge->sub = bridge->pci_bus->subordinate; - - /* - * decode resources under this P2P bridge - */ - - /* I/O resources */ - pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8); - base = tmp8; - pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8); - limit = tmp8; - - switch (base & PCI_IO_RANGE_TYPE_MASK) { - case PCI_IO_RANGE_TYPE_16: - base = (base << 8) & 0xf000; - limit = ((limit << 8) & 0xf000) + 0xfff; - bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->io_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("16bit I/O range: %04x-%04x\n", - (u32)bridge->io_head->base, - (u32)(bridge->io_head->base + bridge->io_head->length - 1)); - break; - case PCI_IO_RANGE_TYPE_32: - pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16); - base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000); - pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16); - limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff; - bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->io_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit I/O range: %08x-%08x\n", - (u32)bridge->io_head->base, - (u32)(bridge->io_head->base + bridge->io_head->length - 1)); - break; - case 0x0f: - dbg("I/O space unsupported\n"); - break; - default: - warn("Unknown I/O range type\n"); - } - - /* Memory resources (mandatory for P2P bridge) */ - pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16); - base = (tmp16 & 0xfff0) << 16; - pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16); - limit = ((tmp16 & 0xfff0) << 16) | 0xfffff; - bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit Memory range: %08x-%08x\n", - (u32)bridge->mem_head->base, - (u32)(bridge->mem_head->base + bridge->mem_head->length-1)); - - /* Prefetchable Memory resources (optional) */ - pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16); - base = tmp16; - pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16); - limit = tmp16; - - switch (base & PCI_MEMORY_RANGE_TYPE_MASK) { - case PCI_PREF_RANGE_TYPE_32: - base = (base & 0xfff0) << 16; - limit = ((limit & 0xfff0) << 16) | 0xfffff; - bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->p_mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit Prefetchable memory range: %08x-%08x\n", - (u32)bridge->p_mem_head->base, - (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1)); - break; - case PCI_PREF_RANGE_TYPE_64: - pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u); - pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u); - base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16); - limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff; - - bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1); - if (!bridge->p_mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n", - (u32)(bridge->p_mem_head->base >> 32), - (u32)(bridge->p_mem_head->base & 0xffffffff), - (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32), - (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff)); - break; - case 0x0f: - break; - default: - warn("Unknown prefetchale memory type\n"); - } - init_bridge_misc(bridge); + return; + err: + pci_dev_put(pci_dev); + kfree(bridge); + return; } @@ -577,14 +383,10 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) { acpi_status status; acpi_handle dummy_handle; - unsigned long *segbus = context; unsigned long tmp; - int seg, bus, device, function; + int device, function; struct pci_dev *dev; - - /* get PCI address */ - seg = (*segbus >> 8) & 0xff; - bus = *segbus & 0xff; + struct pci_bus *pci_bus = context; status = acpi_get_handle(handle, "_ADR", &dummy_handle); if (ACPI_FAILURE(status)) @@ -599,20 +401,19 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) device = (tmp >> 16) & 0xffff; function = tmp & 0xffff; - dev = pci_find_slot(bus, PCI_DEVFN(device, function)); + dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function)); - if (!dev) - return AE_OK; - - if (!dev->subordinate) - return AE_OK; + if (!dev || !dev->subordinate) + goto out; /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev)); - add_p2p_bridge(handle, seg, bus, device, function); + add_p2p_bridge(handle, dev); } + out: + pci_dev_put(dev); return AE_OK; } @@ -624,6 +425,7 @@ static int add_bridge(acpi_handle handle) unsigned long tmp; int seg, bus; acpi_handle dummy_handle; + struct pci_bus *pci_bus; /* if the bridge doesn't have _STA, we assume it is always there */ status = acpi_get_handle(handle, "_STA", &dummy_handle); @@ -653,18 +455,22 @@ static int add_bridge(acpi_handle handle) bus = 0; } + pci_bus = pci_find_bus(seg, bus); + if (!pci_bus) { + err("Can't find bus %04x:%02x\n", seg, bus); + return 0; + } + /* check if this bridge has ejectable slots */ if (detect_ejectable_slots(handle) > 0) { dbg("found PCI host-bus bridge with hot-pluggable slots\n"); - add_host_bridge(handle, seg, bus); + add_host_bridge(handle, pci_bus); return 0; } - tmp = seg << 8 | bus; - /* search P2P bridges under this host bridge */ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - find_p2p_bridge, &tmp, NULL); + find_p2p_bridge, pci_bus, NULL); if (ACPI_FAILURE(status)) warn("find_p2p_bridge faied (error code = 0x%x)\n",status); @@ -672,12 +478,205 @@ static int add_bridge(acpi_handle handle) return 0; } +static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) +{ + struct list_head *head; + list_for_each(head, &bridge_list) { + struct acpiphp_bridge *bridge = list_entry(head, + struct acpiphp_bridge, list); + if (bridge->handle == handle) + return bridge; + } + + return NULL; +} + +static void cleanup_bridge(struct acpiphp_bridge *bridge) +{ + struct list_head *list, *tmp; + struct acpiphp_slot *slot; + acpi_status status; + acpi_handle handle = bridge->handle; + + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + + slot = bridge->slots; + while (slot) { + struct acpiphp_slot *next = slot->next; + list_for_each_safe (list, tmp, &slot->funcs) { + struct acpiphp_func *func; + func = list_entry(list, struct acpiphp_func, sibling); + status = acpi_remove_notify_handler(func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + pci_dev_put(func->pci_dev); + list_del(list); + kfree(func); + } + kfree(slot); + slot = next; + } + + pci_dev_put(bridge->pci_dev); + list_del(&bridge->list); + kfree(bridge); +} + +static acpi_status +cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct acpiphp_bridge *bridge; + + if (!(bridge = acpiphp_handle_to_bridge(handle))) + return AE_OK; + cleanup_bridge(bridge); + return AE_OK; +} static void remove_bridge(acpi_handle handle) { - /* No-op for now .. */ + struct acpiphp_bridge *bridge; + + bridge = acpiphp_handle_to_bridge(handle); + if (bridge) { + cleanup_bridge(bridge); + } else { + /* clean-up p2p bridges under this host bridge */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + (u32)1, cleanup_p2p_bridge, NULL, NULL); + } +} + +static struct pci_dev * get_apic_pci_info(acpi_handle handle) +{ + struct acpi_pci_id id; + struct pci_bus *bus; + struct pci_dev *dev; + + if (ACPI_FAILURE(acpi_get_pci_id(handle, &id))) + return NULL; + + bus = pci_find_bus(id.segment, id.bus); + if (!bus) + return NULL; + + dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function)); + if (!dev) + return NULL; + + if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) && + (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC)) + { + pci_dev_put(dev); + return NULL; + } + + return dev; +} + +static int get_gsi_base(acpi_handle handle, u32 *gsi_base) +{ + acpi_status status; + int result = -1; + unsigned long gsb; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *obj; + void *table; + + status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb); + if (ACPI_SUCCESS(status)) { + *gsi_base = (u32)gsb; + return 0; + } + + status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer); + if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer) + return -1; + + obj = buffer.pointer; + if (obj->type != ACPI_TYPE_BUFFER) + goto out; + + table = obj->buffer.pointer; + switch (((acpi_table_entry_header *)table)->type) { + case ACPI_MADT_IOSAPIC: + *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base; + result = 0; + break; + case ACPI_MADT_IOAPIC: + *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base; + result = 0; + break; + default: + break; + } + out: + acpi_os_free(buffer.pointer); + return result; +} + +static acpi_status +ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + unsigned long sta; + acpi_handle tmp; + struct pci_dev *pdev; + u32 gsi_base; + u64 phys_addr; + + /* Evaluate _STA if present */ + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) + return AE_CTRL_DEPTH; + + /* Scan only PCI bus scope */ + status = acpi_get_handle(handle, "_HID", &tmp); + if (ACPI_SUCCESS(status)) + return AE_CTRL_DEPTH; + + if (get_gsi_base(handle, &gsi_base)) + return AE_OK; + + pdev = get_apic_pci_info(handle); + if (!pdev) + return AE_OK; + + if (pci_enable_device(pdev)) { + pci_dev_put(pdev); + return AE_OK; + } + + pci_set_master(pdev); + + if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { + pci_disable_device(pdev); + pci_dev_put(pdev); + return AE_OK; + } + + phys_addr = pci_resource_start(pdev, 0); + if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { + pci_release_region(pdev, 0); + pci_disable_device(pdev); + pci_dev_put(pdev); + return AE_OK; + } + + return AE_OK; } +static int acpiphp_configure_ioapics(acpi_handle handle) +{ + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, ioapic_add, NULL, NULL); + return 0; +} static int power_on_slot(struct acpiphp_slot *slot) { @@ -719,8 +718,6 @@ static int power_off_slot(struct acpiphp_slot *slot) acpi_status status; struct acpiphp_func *func; struct list_head *l; - struct acpi_object_list arg_list; - union acpi_object arg; int retval = 0; @@ -731,7 +728,7 @@ static int power_off_slot(struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) { + if (func->flags & FUNC_HAS_PS3) { status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status)) { warn("%s: _PS3 failed\n", __FUNCTION__); @@ -742,27 +739,6 @@ static int power_off_slot(struct acpiphp_slot *slot) } } - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - /* We don't want to call _EJ0 on non-existing functions. */ - if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) { - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } else - break; - } - } - /* TBD: evaluate _STA to check if the slot is disabled */ slot->flags &= (~SLOT_POWEREDON); @@ -782,70 +758,56 @@ static int power_off_slot(struct acpiphp_slot *slot) */ static int enable_device(struct acpiphp_slot *slot) { - u8 bus; struct pci_dev *dev; - struct pci_bus *child; + struct pci_bus *bus = slot->bridge->pci_bus; struct list_head *l; struct acpiphp_func *func; int retval = 0; - int num; + int num, max, pass; if (slot->flags & SLOT_ENABLED) goto err_exit; /* sanity check: dev should be NULL when hot-plugged in */ - dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); + dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0)); if (dev) { /* This case shouldn't happen */ err("pci_dev structure already exists.\n"); + pci_dev_put(dev); retval = -1; goto err_exit; } - /* allocate resources to device */ - retval = acpiphp_configure_slot(slot); - if (retval) - goto err_exit; - - /* returned `dev' is the *first function* only! */ - num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); - if (num) - pci_bus_add_devices(slot->bridge->pci_bus); - dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); - - if (!dev) { + num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); + if (num == 0) { err("No new device found\n"); retval = -1; goto err_exit; } - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus); - pci_do_scan_bus(child); + max = bus->secondary; + for (pass = 0; pass < 2; pass++) { + list_for_each_entry(dev, &bus->devices, bus_list) { + if (PCI_SLOT(dev->devfn) != slot->device) + continue; + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + max = pci_scan_bridge(bus, dev, max, pass); + } } + pci_bus_assign_resources(bus); + pci_bus_add_devices(bus); + /* associate pci_dev to our representation */ list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); - - func->pci_dev = pci_find_slot(slot->bridge->bus, - PCI_DEVFN(slot->device, + func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, func->function)); - if (!func->pci_dev) - continue; - - /* configure device */ - retval = acpiphp_configure_function(func); - if (retval) - goto err_exit; } slot->flags |= SLOT_ENABLED; - dbg("Available resources:\n"); - acpiphp_dump_resource(slot->bridge); - err_exit: return retval; } @@ -866,9 +828,12 @@ static int disable_device(struct acpiphp_slot *slot) list_for_each (l, &slot->funcs) { func = list_entry(l, struct acpiphp_func, sibling); + if (!func->pci_dev) + continue; - if (func->pci_dev) - acpiphp_unconfigure_function(func); + pci_remove_bus_device(func->pci_dev); + pci_dev_put(func->pci_dev); + func->pci_dev = NULL; } slot->flags &= (~SLOT_ENABLED); @@ -920,6 +885,39 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) } /** + * acpiphp_eject_slot - physically eject the slot + */ +static int acpiphp_eject_slot(struct acpiphp_slot *slot) +{ + acpi_status status; + struct acpiphp_func *func; + struct list_head *l; + struct acpi_object_list arg_list; + union acpi_object arg; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + /* We don't want to call _EJ0 on non-existing functions. */ + if ((func->flags & FUNC_HAS_EJ0)) { + /* _EJ0 method take one argument */ + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _EJ0 failed\n", __FUNCTION__); + return -1; + } else + break; + } + } + return 0; +} + +/** * acpiphp_check_bridge - re-enumerate devices * * Iterate over all slots under this bridge and make sure that if a @@ -942,6 +940,8 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) if (retval) { err("Error occurred in disabling\n"); goto err_exit; + } else { + acpiphp_eject_slot(slot); } disabled++; } else { @@ -962,6 +962,144 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge) return retval; } +static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) +{ + u16 pci_cmd, pci_bctl; + struct pci_dev *cdev; + + /* Program hpp values for this device */ + if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || + (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) + return; + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, + bridge->hpp.cache_line_size); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, + bridge->hpp.latency_timer); + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); + if (bridge->hpp.enable_SERR) + pci_cmd |= PCI_COMMAND_SERR; + else + pci_cmd &= ~PCI_COMMAND_SERR; + if (bridge->hpp.enable_PERR) + pci_cmd |= PCI_COMMAND_PARITY; + else + pci_cmd &= ~PCI_COMMAND_PARITY; + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); + + /* Program bridge control value and child devices */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, + bridge->hpp.latency_timer); + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); + if (bridge->hpp.enable_SERR) + pci_bctl |= PCI_BRIDGE_CTL_SERR; + else + pci_bctl &= ~PCI_BRIDGE_CTL_SERR; + if (bridge->hpp.enable_PERR) + pci_bctl |= PCI_BRIDGE_CTL_PARITY; + else + pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); + if (dev->subordinate) { + list_for_each_entry(cdev, &dev->subordinate->devices, + bus_list) + program_hpp(cdev, bridge); + } + } +} + +static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) +{ + struct acpiphp_bridge bridge; + struct pci_dev *dev; + + memset(&bridge, 0, sizeof(bridge)); + bridge.handle = handle; + decode_hpp(&bridge); + list_for_each_entry(dev, &bus->devices, bus_list) + program_hpp(dev, &bridge); + +} + +/* + * Remove devices for which we could not assign resources, call + * arch specific code to fix-up the bus + */ +static void acpiphp_sanitize_bus(struct pci_bus *bus) +{ + struct pci_dev *dev; + int i; + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; + + list_for_each_entry(dev, &bus->devices, bus_list) { + for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { + struct resource *res = &dev->resource[i]; + if ((res->flags & type_mask) && !res->start && + res->end) { + /* Could not assign a required resources + * for this device, remove it */ + pci_remove_bus_device(dev); + break; + } + } + } +} + +/* Program resources in newly inserted bridge */ +static int acpiphp_configure_bridge (acpi_handle handle) +{ + struct acpi_pci_id pci_id; + struct pci_bus *bus; + + if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { + err("cannot get PCI domain and bus number for bridge\n"); + return -EINVAL; + } + bus = pci_find_bus(pci_id.segment, pci_id.bus); + if (!bus) { + err("cannot find bus %d:%d\n", + pci_id.segment, pci_id.bus); + return -EINVAL; + } + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + acpiphp_sanitize_bus(bus); + acpiphp_set_hpp_values(handle, bus); + pci_enable_bridges(bus); + acpiphp_configure_ioapics(handle); + return 0; +} + +static void handle_bridge_insertion(acpi_handle handle, u32 type) +{ + struct acpi_device *device, *pdevice; + acpi_handle phandle; + + if ((type != ACPI_NOTIFY_BUS_CHECK) && + (type != ACPI_NOTIFY_DEVICE_CHECK)) { + err("unexpected notification type %d\n", type); + return; + } + + acpi_get_parent(handle, &phandle); + if (acpi_bus_get_device(phandle, &pdevice)) { + dbg("no parent device, assuming NULL\n"); + pdevice = NULL; + } + if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { + err("cannot add bridge to acpi list\n"); + return; + } + if (!acpiphp_configure_bridge(handle) && + !acpi_bus_start(device)) + add_bridge(handle); + else + err("cannot configure and start bridge\n"); + +} + /* * ACPI event handlers */ @@ -982,8 +1120,19 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; + struct acpi_device *device; - bridge = (struct acpiphp_bridge *)context; + if (acpi_bus_get_device(handle, &device)) { + /* This bridge must have just been physically inserted */ + handle_bridge_insertion(handle, type); + return; + } + + bridge = acpiphp_handle_to_bridge(handle); + if (!bridge) { + err("cannot get bridge info\n"); + return; + } acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1031,7 +1180,6 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont } } - /** * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) * @@ -1074,7 +1222,8 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - acpiphp_disable_slot(func->slot); + if (!(acpiphp_disable_slot(func->slot))) + acpiphp_eject_slot(func->slot); break; default: @@ -1083,6 +1232,47 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex } } +static int is_root_bridge(acpi_handle handle) +{ + acpi_status status; + struct acpi_device_info *info; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + int i; + + status = acpi_get_object_info(handle, &buffer); + if (ACPI_SUCCESS(status)) { + info = buffer.pointer; + if ((info->valid & ACPI_VALID_HID) && + !strcmp(PCI_ROOT_HID_STRING, + info->hardware_id.value)) { + acpi_os_free(buffer.pointer); + return 1; + } + if (info->valid & ACPI_VALID_CID) { + for (i=0; i < info->compatibility_id.count; i++) { + if (!strcmp(PCI_ROOT_HID_STRING, + info->compatibility_id.id[i].value)) { + acpi_os_free(buffer.pointer); + return 1; + } + } + } + } + return 0; +} + +static acpi_status +find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + + if (is_root_bridge(handle)) { + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, NULL); + (*count)++; + } + return AE_OK ; +} static struct acpi_pci_driver acpi_pci_hp_driver = { .add = add_bridge, @@ -1095,15 +1285,15 @@ static struct acpi_pci_driver acpi_pci_hp_driver = { */ int __init acpiphp_glue_init(void) { - int num; - - if (list_empty(&pci_root_buses)) - return -1; + int num = 0; - num = acpi_pci_register_driver(&acpi_pci_hp_driver); + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_root_bridges, &num, NULL); if (num <= 0) return -1; + else + acpi_pci_register_driver(&acpi_pci_hp_driver); return 0; } @@ -1116,46 +1306,6 @@ int __init acpiphp_glue_init(void) */ void __exit acpiphp_glue_exit(void) { - struct list_head *l1, *l2, *n1, *n2; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot, *next; - struct acpiphp_func *func; - acpi_status status; - - list_for_each_safe (l1, n1, &bridge_list) { - bridge = (struct acpiphp_bridge *)l1; - slot = bridge->slots; - while (slot) { - next = slot->next; - list_for_each_safe (l2, n2, &slot->funcs) { - func = list_entry(l2, struct acpiphp_func, sibling); - acpiphp_free_resource(&func->io_head); - acpiphp_free_resource(&func->mem_head); - acpiphp_free_resource(&func->p_mem_head); - acpiphp_free_resource(&func->bus_head); - status = acpi_remove_notify_handler(func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - kfree(func); - } - kfree(slot); - slot = next; - } - status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - - acpiphp_free_resource(&bridge->io_head); - acpiphp_free_resource(&bridge->mem_head); - acpiphp_free_resource(&bridge->p_mem_head); - acpiphp_free_resource(&bridge->bus_head); - - kfree(bridge); - } - acpi_pci_unregister_driver(&acpi_pci_hp_driver); } @@ -1173,11 +1323,14 @@ int __init acpiphp_get_num_slots(void) list_for_each (node, &bridge_list) { bridge = (struct acpiphp_bridge *)node; - dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); + dbg("Bus %04x:%02x has %d slot%s\n", + pci_domain_nr(bridge->pci_bus), + bridge->pci_bus->number, bridge->nr_slots, + bridge->nr_slots == 1 ? "" : "s"); num_slots += bridge->nr_slots; } - dbg("Total %dslots\n", num_slots); + dbg("Total %d slots\n", num_slots); return num_slots; } @@ -1254,7 +1407,6 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) return retval; } - /** * acpiphp_disable_slot - power off slot */ @@ -1274,13 +1426,6 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) if (retval) goto err_exit; - acpiphp_resource_sort_and_combine(&slot->bridge->io_head); - acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); - acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); - acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); - dbg("Available resources:\n"); - acpiphp_dump_resource(slot->bridge); - err_exit: up(&slot->crit_sect); return retval; @@ -1293,11 +1438,7 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot) */ u8 acpiphp_get_power_status(struct acpiphp_slot *slot) { - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_ENABLED) ? 1 : 0; + return (slot->flags & SLOT_POWEREDON); } @@ -1335,9 +1476,10 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot) u32 acpiphp_get_address(struct acpiphp_slot *slot) { u32 address; + struct pci_bus *pci_bus = slot->bridge->pci_bus; - address = ((slot->bridge->seg) << 16) | - ((slot->bridge->bus) << 8) | + address = (pci_domain_nr(pci_bus) << 16) | + (pci_bus->number << 8) | slot->device; return address; diff --git a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c deleted file mode 100644 index 54d97c9..0000000 --- a/drivers/pci/hotplug/acpiphp_pci.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * ACPI PCI HotPlug PCI configuration space management - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001,2002 IBM Corp. - * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) - * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (C) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <t-kochi@bq.jp.nec.com> - * - */ - -#include <linux/init.h> -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/acpi.h> -#include "../pci.h" -#include "pci_hotplug.h" -#include "acpiphp.h" - -#define MY_NAME "acpiphp_pci" - - -/* allocate mem/pmem/io resource to a new function */ -static int init_config_space (struct acpiphp_func *func) -{ - u32 bar, len; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct acpiphp_bridge *bridge; - struct pci_resource *res; - struct pci_bus *pbus; - int bus, device, function; - unsigned int devfn; - u16 tmp; - - bridge = func->slot->bridge; - pbus = bridge->pci_bus; - bus = bridge->bus; - device = func->slot->device; - function = func->function; - devfn = PCI_DEVFN(device, function); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_bus_write_config_dword(pbus, devfn, - address[count], 0xFFFFFFFF); - pci_bus_read_config_dword(pbus, devfn, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar); - - if (bar & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - - len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); - len = len & ~(len - 1); - - dbg("len in IO %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_io_resource(&bridge->io_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested io for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - res->next = func->io_head; - func->io_head = res; - - } else { - /* This is Memory */ - if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len = bar & 0xFFFFFFF0; - len = ~len + 1; - - dbg("len in PFMEM %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource(&bridge->p_mem_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - - if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("inside the pfmem 64 case, count %d\n", count); - count += 1; - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)(res->base >> 32)); - } - - res->next = func->p_mem_head; - func->p_mem_head = res; - - } else { - /* regular memory */ - - len = bar & 0xFFFFFFF0; - len = ~len + 1; - - dbg("len in MEM %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource(&bridge->mem_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - - if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("inside mem 64 case, reg. mem, count %d\n", count); - count += 1; - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)(res->base >> 32)); - } - - res->next = func->mem_head; - func->mem_head = res; - - } - } - } - - /* disable expansion rom */ - pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000); - - /* set PCI parameters from _HPP */ - pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE, - bridge->hpp.cache_line_size); - pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER, - bridge->hpp.latency_timer); - - pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp); - if (bridge->hpp.enable_SERR) - tmp |= PCI_COMMAND_SERR; - if (bridge->hpp.enable_PERR) - tmp |= PCI_COMMAND_PARITY; - pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp); - - return 0; -} - -/* detect_used_resource - subtract resource under dev from bridge */ -static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev) -{ - int count; - - dbg("Device %s\n", pci_name(dev)); - - for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) { - struct pci_resource *res; - struct pci_resource **head; - unsigned long base = dev->resource[count].start; - unsigned long len = dev->resource[count].end - base + 1; - unsigned long flags = dev->resource[count].flags; - - if (!flags) - continue; - - dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base, - base + len - 1, flags); - - if (flags & IORESOURCE_IO) { - head = &bridge->io_head; - } else if (flags & IORESOURCE_PREFETCH) { - head = &bridge->p_mem_head; - } else { - head = &bridge->mem_head; - } - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } - - return 0; -} - - -/** - * acpiphp_detect_pci_resource - detect resources under bridge - * @bridge: detect all resources already used under this bridge - * - * collect all resources already allocated for all devices under a bridge. - */ -int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge) -{ - struct list_head *l; - struct pci_dev *dev; - - list_for_each (l, &bridge->pci_bus->devices) { - dev = pci_dev_b(l); - detect_used_resource(bridge, dev); - } - - return 0; -} - - -/** - * acpiphp_init_slot_resource - gather resource usage information of a slot - * @slot: ACPI slot object to be checked, should have valid pci_dev member - * - * TBD: PCI-to-PCI bridge case - * use pci_dev->resource[] - */ -int acpiphp_init_func_resource (struct acpiphp_func *func) -{ - u64 base; - u32 bar, len; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct pci_resource *res; - struct pci_dev *dev; - - dev = func->pci_dev; - dbg("Hot-pluggable device %s\n", pci_name(dev)); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_read_config_dword(dev, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - pci_write_config_dword(dev, address[count], 0xFFFFFFFF); - pci_read_config_dword(dev, address[count], &len); - - if (len & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - base = bar & 0xFFFFFFFC; - len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF); - len = len & ~(len - 1); - - dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); - - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->io_head; - func->io_head = res; - - } else { - /* This is Memory */ - base = bar & 0xFFFFFFF0; - if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("prefetch mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->p_mem_head; - func->p_mem_head = res; - - } else { - /* regular memory */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->mem_head; - func->mem_head = res; - - } - } - - pci_write_config_dword(dev, address[count], bar); - } -#if 1 - acpiphp_dump_func_resource(func); -#endif - - return 0; - - no_memory: - err("out of memory\n"); - acpiphp_free_resource(&func->io_head); - acpiphp_free_resource(&func->mem_head); - acpiphp_free_resource(&func->p_mem_head); - - return -1; -} - - -/** - * acpiphp_configure_slot - allocate PCI resources - * @slot: slot to be configured - * - * initializes a PCI functions on a device inserted - * into the slot - * - */ -int acpiphp_configure_slot (struct acpiphp_slot *slot) -{ - struct acpiphp_func *func; - struct list_head *l; - u8 hdr; - u32 dvid; - int retval = 0; - int is_multi = 0; - - pci_bus_read_config_byte(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, 0), - PCI_HEADER_TYPE, &hdr); - - if (hdr & 0x80) - is_multi = 1; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - if (is_multi || func->function == 0) { - pci_bus_read_config_dword(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { - retval = init_config_space(func); - if (retval) - break; - } - } - } - - return retval; -} - -/** - * acpiphp_configure_function - configure PCI function - * @func: function to be configured - * - * initializes a PCI functions on a device inserted - * into the slot - * - */ -int acpiphp_configure_function (struct acpiphp_func *func) -{ - /* all handled by the pci core now */ - return 0; -} - -/** - * acpiphp_unconfigure_function - unconfigure PCI function - * @func: function to be unconfigured - * - */ -void acpiphp_unconfigure_function (struct acpiphp_func *func) -{ - struct acpiphp_bridge *bridge; - - /* if pci_dev is NULL, ignore it */ - if (!func->pci_dev) - return; - - pci_remove_bus_device(func->pci_dev); - - /* free all resources */ - bridge = func->slot->bridge; - - spin_lock(&bridge->res_lock); - acpiphp_move_resource(&func->io_head, &bridge->io_head); - acpiphp_move_resource(&func->mem_head, &bridge->mem_head); - acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head); - acpiphp_move_resource(&func->bus_head, &bridge->bus_head); - spin_unlock(&bridge->res_lock); -} diff --git a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c deleted file mode 100644 index f54b1fa..0000000 --- a/drivers/pci/hotplug/acpiphp_res.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * ACPI PCI HotPlug Utility functions - * - * Copyright (C) 1995,2001 Compaq Computer Corporation - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2001 IBM Corp. - * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com) - * Copyright (C) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; 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, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com> - * - */ - -#include <linux/init.h> -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/sysctl.h> -#include <linux/pci.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> - -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/timer.h> - -#include <linux/ioctl.h> -#include <linux/fcntl.h> - -#include <linux/list.h> - -#include "pci_hotplug.h" -#include "acpiphp.h" - -#define MY_NAME "acpiphp_res" - - -/* - * sort_by_size - sort nodes by their length, smallest first - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} - -#if 0 -/* - * sort_by_max_size - sort nodes by their length, largest first - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} -#endif - -/** - * get_io_resource - get resource for I/O ports - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - * - * difference from get_resource is handling of ISA aliasing space. - * - */ -struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_size(head)) - return NULL; - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - /* For IO make sure it's not in the ISA aliasing space */ - if ((node->base & 0x300L) && !(node->base & 0xfffff000)) - continue; - - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - - return node; -} - - -#if 0 -/** - * get_max_resource - get the largest resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - */ -static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_max_size(head)) - return NULL; - - for (max = *head;max; max = max->next) { - - /* If not big enough we could probably just bail, - instead we'll continue to the next. */ - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (max->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((max->length - (temp_qword - max->base)) < size) - continue; - - split_node = acpiphp_make_resource(max->base, temp_qword - max->base); - - if (!split_node) - return NULL; - - max->base = temp_qword; - max->length -= split_node->length; - - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - /* this one isn't end aligned properly at the top - so we'll make a new entry and split it up */ - temp_qword = ((max->base + max->length) & ~(size - 1)); - - split_node = acpiphp_make_resource(temp_qword, - max->length + max->base - temp_qword); - - if (!split_node) - return NULL; - - max->length -= split_node->length; - - /* Put it in the list */ - split_node->next = max->next; - max->next = split_node; - } - - /* Make sure it didn't shrink too much when we aligned it */ - if (max->length < size) - continue; - - /* Now take it out of the list */ - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return max; - } - - /* If we get here, we couldn't find one */ - return NULL; -} -#endif - -/** - * get_resource - get resource (mem, pfmem) - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - * - */ -struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_size(head)) - return NULL; - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", - __FUNCTION__, size, node, (u32)node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg("%s: got one!!!\n", __FUNCTION__); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return node; -} - -/** - * get_resource_with_base - get resource with specific base address - * - * this function - * returns the first node of "size" length located at specified base address. - * If it finds a node larger than "size" it will split it up. - * - * size must be a power of two. - * - */ -struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - for (node = *head; node; node = node->next) { - dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", - (u32)base, size, node, (u32)node->base, node->length); - if (node->base > base) - continue; - - if ((node->base + node->length) < (base + size)) - continue; - - if (node->base < base) { - dbg(": split 1\n"); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = base; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } - - dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n", - (u32)base, size, node, (u32)node->base, node->length); - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg(": split 2\n"); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg(": got one!!!\n"); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return node; -} - - -/** - * acpiphp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int acpiphp_resource_sort_and_combine (struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - if (!(*head)) - return 1; - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return 0; /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(u32)(*head)->base); - dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } /* End of out_of_order loop */ - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - /* Combine */ - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return 0; -} - - -/** - * acpiphp_make_resource - make resource structure - * @base: base address of a resource - * @length: length of a resource - */ -struct pci_resource *acpiphp_make_resource (u64 base, u32 length) -{ - struct pci_resource *res; - - res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (res) { - memset(res, 0, sizeof(struct pci_resource)); - res->base = base; - res->length = length; - } - - return res; -} - - -/** - * acpiphp_move_resource - move linked resources from one to another - * @from: head of linked resource list - * @to: head of linked resource list - */ -void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to) -{ - struct pci_resource *tmp; - - while (*from) { - tmp = (*from)->next; - (*from)->next = *to; - *to = *from; - *from = tmp; - } - - /* *from = NULL is guaranteed */ -} - - -/** - * acpiphp_free_resource - free all linked resources - * @res: head of linked resource list - */ -void acpiphp_free_resource (struct pci_resource **res) -{ - struct pci_resource *tmp; - - while (*res) { - tmp = (*res)->next; - kfree(*res); - *res = tmp; - } - - /* *res = NULL is guaranteed */ -} - - -/* debug support functions; will go away sometime :) */ -static void dump_resource(struct pci_resource *head) -{ - struct pci_resource *p; - int cnt; - - p = head; - cnt = 0; - - while (p) { - dbg("[%02d] %08x - %08x\n", - cnt++, (u32)p->base, (u32)p->base + p->length - 1); - p = p->next; - } -} - -void acpiphp_dump_resource(struct acpiphp_bridge *bridge) -{ - dbg("I/O resource:\n"); - dump_resource(bridge->io_head); - dbg("MEM resource:\n"); - dump_resource(bridge->mem_head); - dbg("PMEM resource:\n"); - dump_resource(bridge->p_mem_head); - dbg("BUS resource:\n"); - dump_resource(bridge->bus_head); -} - -void acpiphp_dump_func_resource(struct acpiphp_func *func) -{ - dbg("I/O resource:\n"); - dump_resource(func->io_head); - dbg("MEM resource:\n"); - dump_resource(func->mem_head); - dbg("PMEM resource:\n"); - dump_resource(func->p_mem_head); - dbg("BUS resource:\n"); - dump_resource(func->bus_head); -} diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index afbccfa..8c6d398 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -60,6 +60,7 @@ static void __iomem *smbios_start; static void __iomem *cpqhp_rom_start; static int power_mode; static int debug; +static int initialized; #define DRIVER_VERSION "0.9.8" #define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>" @@ -1271,7 +1272,6 @@ static int one_time_init(void) { int loop; int retval = 0; - static int initialized = 0; if (initialized) return 0; @@ -1441,7 +1441,8 @@ static void __exit unload_cpqphpd(void) } // Stop the notification mechanism - cpqhp_event_stop_thread(); + if (initialized) + cpqhp_event_stop_thread(); //unmap the rom address if (cpqhp_rom_start) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 30206ac..b5ab9aa6 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -28,10 +28,10 @@ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; static kmem_cache_t* msi_cachep; static int pci_msi_enable = 1; -static int last_alloc_vector = 0; -static int nr_released_vectors = 0; +static int last_alloc_vector; +static int nr_released_vectors; static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS; -static int nr_msix_devices = 0; +static int nr_msix_devices; #ifndef CONFIG_X86_IO_APIC int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; @@ -170,44 +170,30 @@ static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector) return 0; /* never anything pending */ } -static void release_msi(unsigned int vector); -static void shutdown_msi_irq(unsigned int vector) -{ - release_msi(vector); -} - -#define shutdown_msi_irq_wo_maskbit shutdown_msi_irq -static void enable_msi_irq_wo_maskbit(unsigned int vector) {} -static void disable_msi_irq_wo_maskbit(unsigned int vector) {} -static void ack_msi_irq_wo_maskbit(unsigned int vector) {} -static void end_msi_irq_wo_maskbit(unsigned int vector) +static unsigned int startup_msi_irq_w_maskbit(unsigned int vector) { - move_msi(vector); - ack_APIC_irq(); + startup_msi_irq_wo_maskbit(vector); + unmask_MSI_irq(vector); + return 0; /* never anything pending */ } -static unsigned int startup_msi_irq_w_maskbit(unsigned int vector) +static void shutdown_msi_irq(unsigned int vector) { struct msi_desc *entry; unsigned long flags; spin_lock_irqsave(&msi_lock, flags); entry = msi_desc[vector]; - if (!entry || !entry->dev) { - spin_unlock_irqrestore(&msi_lock, flags); - return 0; - } - entry->msi_attrib.state = 1; /* Mark it active */ + if (entry && entry->dev) + entry->msi_attrib.state = 0; /* Mark it not active */ spin_unlock_irqrestore(&msi_lock, flags); - - unmask_MSI_irq(vector); - return 0; /* never anything pending */ } -#define shutdown_msi_irq_w_maskbit shutdown_msi_irq -#define enable_msi_irq_w_maskbit unmask_MSI_irq -#define disable_msi_irq_w_maskbit mask_MSI_irq -#define ack_msi_irq_w_maskbit mask_MSI_irq +static void end_msi_irq_wo_maskbit(unsigned int vector) +{ + move_msi(vector); + ack_APIC_irq(); +} static void end_msi_irq_w_maskbit(unsigned int vector) { @@ -216,6 +202,10 @@ static void end_msi_irq_w_maskbit(unsigned int vector) ack_APIC_irq(); } +static void do_nothing(unsigned int vector) +{ +} + /* * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices, * which implement the MSI-X Capability Structure. @@ -223,10 +213,10 @@ static void end_msi_irq_w_maskbit(unsigned int vector) static struct hw_interrupt_type msix_irq_type = { .typename = "PCI-MSI-X", .startup = startup_msi_irq_w_maskbit, - .shutdown = shutdown_msi_irq_w_maskbit, - .enable = enable_msi_irq_w_maskbit, - .disable = disable_msi_irq_w_maskbit, - .ack = ack_msi_irq_w_maskbit, + .shutdown = shutdown_msi_irq, + .enable = unmask_MSI_irq, + .disable = mask_MSI_irq, + .ack = mask_MSI_irq, .end = end_msi_irq_w_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -239,10 +229,10 @@ static struct hw_interrupt_type msix_irq_type = { static struct hw_interrupt_type msi_irq_w_maskbit_type = { .typename = "PCI-MSI", .startup = startup_msi_irq_w_maskbit, - .shutdown = shutdown_msi_irq_w_maskbit, - .enable = enable_msi_irq_w_maskbit, - .disable = disable_msi_irq_w_maskbit, - .ack = ack_msi_irq_w_maskbit, + .shutdown = shutdown_msi_irq, + .enable = unmask_MSI_irq, + .disable = mask_MSI_irq, + .ack = mask_MSI_irq, .end = end_msi_irq_w_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -255,10 +245,10 @@ static struct hw_interrupt_type msi_irq_w_maskbit_type = { static struct hw_interrupt_type msi_irq_wo_maskbit_type = { .typename = "PCI-MSI", .startup = startup_msi_irq_wo_maskbit, - .shutdown = shutdown_msi_irq_wo_maskbit, - .enable = enable_msi_irq_wo_maskbit, - .disable = disable_msi_irq_wo_maskbit, - .ack = ack_msi_irq_wo_maskbit, + .shutdown = shutdown_msi_irq, + .enable = do_nothing, + .disable = do_nothing, + .ack = do_nothing, .end = end_msi_irq_wo_maskbit, .set_affinity = set_msi_irq_affinity }; @@ -407,7 +397,7 @@ static struct msi_desc* alloc_msi_entry(void) { struct msi_desc *entry; - entry = (struct msi_desc*) kmem_cache_alloc(msi_cachep, SLAB_KERNEL); + entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL); if (!entry) return NULL; @@ -796,18 +786,6 @@ void pci_disable_msi(struct pci_dev* dev) } } -static void release_msi(unsigned int vector) -{ - struct msi_desc *entry; - unsigned long flags; - - spin_lock_irqsave(&msi_lock, flags); - entry = msi_desc[vector]; - if (entry && entry->dev) - entry->msi_attrib.state = 0; /* Mark it not active */ - spin_unlock_irqrestore(&msi_lock, flags); -} - static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) { struct msi_desc *entry; @@ -924,7 +902,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) /** * pci_enable_msix - configure device's MSI-X capability structure * @dev: pointer to the pci_dev data structure of MSI-X device function - * @data: pointer to an array of MSI-X entries + * @entries: pointer to an array of MSI-X entries * @nvec: number of MSI-X vectors requested for allocation by device driver * * Setup the MSI-X capability structure of device function with the number diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index bef21ae..390f185 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h @@ -41,11 +41,11 @@ static inline void move_msi(int vector) {} #define PCI_MSIX_FLAGS_BIRMASK (7 << 0) #define PCI_MSIX_FLAGS_BITMASK (1 << 0) -#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0 -#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4 -#define PCI_MSIX_ENTRY_DATA_OFFSET 8 -#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12 #define PCI_MSIX_ENTRY_SIZE 16 +#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0 +#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4 +#define PCI_MSIX_ENTRY_DATA_OFFSET 8 +#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12 #define msi_control_reg(base) (base + PCI_MSI_FLAGS) #define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO) @@ -64,7 +64,6 @@ static inline void move_msi(int vector) {} #define msi_enable(control, num) multi_msi_enable(control, num); \ control |= PCI_MSI_FLAGS_ENABLE -#define msix_control_reg msi_control_reg #define msix_table_offset_reg(base) (base + 0x04) #define msix_pba_offset_reg(base) (base + 0x08) #define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index a15f940..cc9d653 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -60,15 +60,18 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) char * str = buf; int i; int max = 7; + u64 start, end; if (pci_dev->subordinate) max = DEVICE_COUNT_RESOURCE; for (i = 0; i < max; i++) { - str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n", - pci_resource_start(pci_dev,i), - pci_resource_end(pci_dev,i), - pci_resource_flags(pci_dev,i)); + struct resource *res = &pci_dev->resource[i]; + pci_resource_to_user(pci_dev, i, res, &start, &end); + str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n", + (unsigned long long)start, + (unsigned long long)end, + (unsigned long long)res->flags); } return (str - buf); } @@ -313,8 +316,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, struct device, kobj)); struct resource *res = (struct resource *)attr->private; enum pci_mmap_state mmap_type; + u64 start, end; + int i; - vma->vm_pgoff += res->start >> PAGE_SHIFT; + for (i = 0; i < PCI_ROM_RESOURCE; i++) + if (res == &pdev->resource[i]) + break; + if (i >= PCI_ROM_RESOURCE) + return -ENODEV; + + /* pci_mmap_page_range() expects the same kind of entry as coming + * from /proc/bus/pci/ which is a "user visible" value. If this is + * different from the resource itself, arch will do necessary fixup. + */ + pci_resource_to_user(pdev, i, res, &start, &end); + vma->vm_pgoff += start >> PAGE_SHIFT; mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; return pci_mmap_page_range(pdev, vma, mmap_type, 0); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index fd48b20..6a0a82f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -374,8 +374,11 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de struct pci_bus *child; child = pci_alloc_child_bus(parent, dev, busnr); - if (child) + if (child) { + spin_lock(&pci_bus_lock); list_add_tail(&child->node, &parent->children); + spin_unlock(&pci_bus_lock); + } return child; } @@ -411,7 +414,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max { struct pci_bus *child; int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); - u32 buses; + u32 buses, i; u16 bctl; pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); @@ -447,7 +450,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max return max; } - child = pci_alloc_child_bus(bus, dev, busnr); + child = pci_add_new_bus(bus, dev, busnr); if (!child) return max; child->primary = buses & 0xFF; @@ -470,7 +473,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max /* Clear errors */ pci_write_config_word(dev, PCI_STATUS, 0xffff); - child = pci_alloc_child_bus(bus, dev, ++max); + /* Prevent assigning a bus number that already exists. + * This can happen when a bridge is hot-plugged */ + if (pci_find_bus(pci_domain_nr(bus), max+1)) + return max; + child = pci_add_new_bus(bus, dev, ++max); buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) @@ -501,7 +508,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max * as cards with a PCI-to-PCI bridge can be * inserted later. */ - max += CARDBUS_RESERVE_BUSNR; + for (i=0; i<CARDBUS_RESERVE_BUSNR; i++) + if (pci_find_bus(pci_domain_nr(bus), + max+i+1)) + break; + max += i; } /* * Set the subordinate bus number to its real value. @@ -757,7 +768,9 @@ pci_scan_single_device(struct pci_bus *bus, int devfn) * and the bus list for fixup functions, etc. */ INIT_LIST_HEAD(&dev->global_list); + spin_lock(&pci_bus_lock); list_add_tail(&dev->bus_list, &bus->devices); + spin_unlock(&pci_bus_lock); return dev; } @@ -878,7 +891,9 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); goto err_out; } + spin_lock(&pci_bus_lock); list_add_tail(&b->node, &pci_root_buses); + spin_unlock(&pci_bus_lock); memset(dev, 0, sizeof(*dev)); dev->parent = parent; @@ -911,8 +926,6 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, b->subordinate = pci_scan_child_bus(b); - pci_bus_add_devices(b); - return b; sys_create_link_err: @@ -922,7 +935,9 @@ class_dev_create_file_err: class_dev_reg_err: device_unregister(dev); dev_reg_err: + spin_lock(&pci_bus_lock); list_del(&b->node); + spin_unlock(&pci_bus_lock); err_out: kfree(dev); kfree(b); diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index e68bbfb..7988fc8 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -355,14 +355,20 @@ static int show_device(struct seq_file *m, void *v) dev->device, dev->irq); /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ - for(i=0; i<7; i++) + for (i=0; i<7; i++) { + u64 start, end; + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); seq_printf(m, LONG_FORMAT, - dev->resource[i].start | + ((unsigned long)start) | (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); - for(i=0; i<7; i++) + } + for (i=0; i<7; i++) { + u64 start, end; + pci_resource_to_user(dev, i, &dev->resource[i], &start, &end); seq_printf(m, LONG_FORMAT, dev->resource[i].start < dev->resource[i].end ? - dev->resource[i].end - dev->resource[i].start + 1 : 0); + (unsigned long)(end - start) + 1 : 0); + } seq_putc(m, '\t'); if (drv) seq_printf(m, "%s", drv->name); diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 96f077f..27a294b 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -18,17 +18,21 @@ static void pci_free_resources(struct pci_dev *dev) static void pci_destroy_dev(struct pci_dev *dev) { - pci_proc_detach_device(dev); - pci_remove_sysfs_dev_files(dev); - device_unregister(&dev->dev); + if (!list_empty(&dev->global_list)) { + pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); + device_unregister(&dev->dev); + spin_lock(&pci_bus_lock); + list_del(&dev->global_list); + dev->global_list.next = dev->global_list.prev = NULL; + spin_unlock(&pci_bus_lock); + } /* Remove the device from the device lists, and prevent any further * list accesses from this device */ spin_lock(&pci_bus_lock); list_del(&dev->bus_list); - list_del(&dev->global_list); dev->bus_list.next = dev->bus_list.prev = NULL; - dev->global_list.next = dev->global_list.prev = NULL; spin_unlock(&pci_bus_lock); pci_free_resources(dev); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 1ba84be..6b628de 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -72,7 +72,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus) for (list = head.next; list;) { res = list->res; idx = res - &list->dev->resource[0]; - pci_assign_resource(list->dev, idx); + if (pci_assign_resource(list->dev, idx)) { + res->start = 0; + res->flags = 0; + } tmp = list; list = list->next; kfree(tmp); diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 34dbc37..bc6e462 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1916,9 +1916,9 @@ static void __twa_shutdown(TW_Device_Extension *tw_dev) } /* End __twa_shutdown() */ /* Wrapper for __twa_shutdown */ -static void twa_shutdown(struct device *dev) +static void twa_shutdown(struct pci_dev *pdev) { - struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); + struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; __twa_shutdown(tw_dev); @@ -2140,9 +2140,7 @@ static struct pci_driver twa_driver = { .id_table = twa_pci_tbl, .probe = twa_probe, .remove = twa_remove, - .driver = { - .shutdown = twa_shutdown - } + .shutdown = twa_shutdown }; /* This function is called on driver initialization */ diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index b6dc576..973c51f 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -2264,9 +2264,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev) } /* End __tw_shutdown() */ /* Wrapper for __tw_shutdown */ -static void tw_shutdown(struct device *dev) +static void tw_shutdown(struct pci_dev *pdev) { - struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); + struct Scsi_Host *host = pci_get_drvdata(pdev); TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; __tw_shutdown(tw_dev); @@ -2451,9 +2451,7 @@ static struct pci_driver tw_driver = { .id_table = tw_pci_tbl, .probe = tw_probe, .remove = tw_remove, - .driver = { - .shutdown = tw_shutdown - } + .shutdown = tw_shutdown, }; /* This function is called on driver initialization */ diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 9a547ca9..c562369 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -304,26 +304,19 @@ static int ahci_port_start(struct ata_port *ap) struct device *dev = ap->host_set->dev; struct ahci_host_priv *hpriv = ap->host_set->private_data; struct ahci_port_priv *pp; - int rc; void *mem, *mmio = ap->host_set->mmio_base; void *port_mmio = ahci_port_base(mmio, ap->port_no); dma_addr_t mem_dma; - rc = ata_port_start(ap); - if (rc) - return rc; - pp = kmalloc(sizeof(*pp), GFP_KERNEL); - if (!pp) { - rc = -ENOMEM; - goto err_out; - } + if (!pp) + return -ENOMEM; memset(pp, 0, sizeof(*pp)); mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); if (!mem) { - rc = -ENOMEM; - goto err_out_kfree; + kfree(pp); + return -ENOMEM; } memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ); @@ -373,12 +366,6 @@ static int ahci_port_start(struct ata_port *ap) readl(port_mmio + PORT_CMD); /* flush */ return 0; - -err_out_kfree: - kfree(pp); -err_out: - ata_port_stop(ap); - return rc; } @@ -404,7 +391,6 @@ static void ahci_port_stop(struct ata_port *ap) dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, pp->cmd_slot, pp->cmd_slot_dma); kfree(pp); - ata_port_stop(ap); } static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 80d0226..babd483 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6012,7 +6012,7 @@ static int __devinit ipr_probe(struct pci_dev *pdev, /** * ipr_shutdown - Shutdown handler. - * @dev: device struct + * @pdev: pci device struct * * This function is invoked upon system shutdown/reboot. It will issue * an adapter shutdown to the adapter to flush the write cache. @@ -6020,9 +6020,9 @@ static int __devinit ipr_probe(struct pci_dev *pdev, * Return value: * none **/ -static void ipr_shutdown(struct device *dev) +static void ipr_shutdown(struct pci_dev *pdev) { - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(to_pci_dev(dev)); + struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); unsigned long lock_flags = 0; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -6068,9 +6068,7 @@ static struct pci_driver ipr_driver = { .id_table = ipr_pci_table, .probe = ipr_probe, .remove = ipr_remove, - .driver = { - .shutdown = ipr_shutdown, - }, + .shutdown = ipr_shutdown, }; /** diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 36b401f..cb535fa 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -1408,7 +1408,9 @@ void __sata_phy_reset(struct ata_port *ap) if (ap->flags & ATA_FLAG_SATA_RESET) { /* issue phy wake/reset */ scr_write_flush(ap, SCR_CONTROL, 0x301); - udelay(400); /* FIXME: a guess */ + /* Couldn't find anything in SATA I/II specs, but + * AHCI-1.1 10.4.2 says at least 1 ms. */ + mdelay(1); } scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */ @@ -1920,6 +1922,7 @@ static const char * ata_dma_blacklist [] = { "HITACHI CDR-8335", "HITACHI CDR-8435", "Toshiba CD-ROM XM-6202B", + "TOSHIBA CD-ROM XM-1702BC", "CD-532E-A", "E-IDE CD-ROM CR-840", "CD-ROM Drive/F5A", @@ -1927,7 +1930,6 @@ static const char * ata_dma_blacklist [] = { "SAMSUNG CD-ROM SC-148C", "SAMSUNG CD-ROM SC", "SanDisk SDP3B-64", - "SAMSUNG CD-ROM SN-124", "ATAPI CD-ROM DRIVE 40X MAXIMUM", "_NEC DV5800A", }; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index ec81532..a70cdf3 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -5036,9 +5036,9 @@ megaraid_remove_one(struct pci_dev *pdev) } static void -megaraid_shutdown(struct device *dev) +megaraid_shutdown(struct pci_dev *pdev) { - struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev)); + struct Scsi_Host *host = pci_get_drvdata(pdev); adapter_t *adapter = (adapter_t *)host->hostdata; __megaraid_shutdown(adapter); @@ -5070,9 +5070,7 @@ static struct pci_driver megaraid_pci_driver = { .id_table = megaraid_pci_tbl, .probe = megaraid_probe_one, .remove = __devexit_p(megaraid_remove_one), - .driver = { - .shutdown = megaraid_shutdown, - }, + .shutdown = megaraid_shutdown, }; static int __init megaraid_init(void) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 621dee8..10506f9 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -632,7 +632,7 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index) { struct scsi_host_sg_pool *sgp; - BUG_ON(index > SG_MEMPOOL_NR); + BUG_ON(index >= SG_MEMPOOL_NR); sgp = scsi_sg_pools + index; mempool_free(sgl, sgp->pool); @@ -58,6 +58,7 @@ static DEFINE_SPINLOCK(fput_lock); static LIST_HEAD(fput_head); static void aio_kick_handler(void *); +static void aio_queue_work(struct kioctx *); /* aio_setup * Creates the slab caches used by the aio routines, panic on @@ -747,6 +748,14 @@ out: * has already been kicked */ if (kiocbIsKicked(iocb)) { __queue_kicked_iocb(iocb); + + /* + * __queue_kicked_iocb will always return 1 here, because + * iocb->ki_run_list is empty at this point so it should + * be safe to unconditionally queue the context into the + * work queue. + */ + aio_queue_work(ctx); } } return ret; diff --git a/fs/buffer.c b/fs/buffer.c index 13e5938..561e63a 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -278,7 +278,7 @@ EXPORT_SYMBOL(thaw_bdev); */ static void do_sync(unsigned long wait) { - wakeup_bdflush(0); + wakeup_pdflush(0); sync_inodes(0); /* All mappings, inodes and their blockdevs */ DQUOT_SYNC(NULL); sync_supers(); /* Write the superblocks */ @@ -497,7 +497,7 @@ static void free_more_memory(void) struct zone **zones; pg_data_t *pgdat; - wakeup_bdflush(1024); + wakeup_pdflush(1024); yield(); for_each_pgdat(pgdat) { diff --git a/fs/char_dev.c b/fs/char_dev.c index e82aac9..a69a5d8 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -150,7 +150,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) struct char_device_struct *cd = NULL, **cp; int i = major_to_index(major); - up(&chrdevs_lock); + down(&chrdevs_lock); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major == major && (*cp)->baseminor == baseminor && diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index ccd632f..e463dca 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -749,24 +749,24 @@ fail_access: * to find a free region that is of my size and has not * been reserved. * - * on succeed, it returns the reservation window to be appended to. - * failed, return NULL. */ -static struct ext3_reserve_window_node *find_next_reservable_window( +static int find_next_reservable_window( struct ext3_reserve_window_node *search_head, - unsigned long size, int *start_block, + struct ext3_reserve_window_node *my_rsv, + struct super_block * sb, int start_block, int last_block) { struct rb_node *next; struct ext3_reserve_window_node *rsv, *prev; int cur; + int size = my_rsv->rsv_goal_size; /* TODO: make the start of the reservation window byte-aligned */ /* cur = *start_block & ~7;*/ - cur = *start_block; + cur = start_block; rsv = search_head; if (!rsv) - return NULL; + return -1; while (1) { if (cur <= rsv->rsv_end) @@ -782,11 +782,11 @@ static struct ext3_reserve_window_node *find_next_reservable_window( * space with expected-size (or more)... */ if (cur > last_block) - return NULL; /* fail */ + return -1; /* fail */ prev = rsv; next = rb_next(&rsv->rsv_node); - rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node); + rsv = list_entry(next,struct ext3_reserve_window_node,rsv_node); /* * Reached the last reservation, we can just append to the @@ -813,8 +813,25 @@ static struct ext3_reserve_window_node *find_next_reservable_window( * return the reservation window that we could append to. * succeed. */ - *start_block = cur; - return prev; + + if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window))) + rsv_window_remove(sb, my_rsv); + + /* + * Let's book the whole avaliable window for now. We will check the + * disk bitmap later and then, if there are free blocks then we adjust + * the window size if it's larger than requested. + * Otherwise, we will remove this node from the tree next time + * call find_next_reservable_window. + */ + my_rsv->rsv_start = cur; + my_rsv->rsv_end = cur + size - 1; + my_rsv->rsv_alloc_hit = 0; + + if (prev != my_rsv) + ext3_rsv_window_add(sb, my_rsv); + + return 0; } /** @@ -852,6 +869,7 @@ static struct ext3_reserve_window_node *find_next_reservable_window( * @sb: the super block * @group: the group we are trying to allocate in * @bitmap_bh: the block group block bitmap + * */ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, int goal, struct super_block *sb, @@ -860,10 +878,10 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, struct ext3_reserve_window_node *search_head; int group_first_block, group_end_block, start_block; int first_free_block; - int reservable_space_start; - struct ext3_reserve_window_node *prev_rsv; struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root; unsigned long size; + int ret; + spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + group * EXT3_BLOCKS_PER_GROUP(sb); @@ -875,6 +893,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, start_block = goal + group_first_block; size = my_rsv->rsv_goal_size; + if (!rsv_is_empty(&my_rsv->rsv_window)) { /* * if the old reservation is cross group boundary @@ -908,6 +927,8 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, my_rsv->rsv_goal_size= size; } } + + spin_lock(rsv_lock); /* * shift the search start to the window near the goal block */ @@ -921,11 +942,16 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, * need to check the bitmap after we found a reservable window. */ retry: - prev_rsv = find_next_reservable_window(search_head, size, - &start_block, group_end_block); - if (prev_rsv == NULL) - goto failed; - reservable_space_start = start_block; + ret = find_next_reservable_window(search_head, my_rsv, sb, + start_block, group_end_block); + + if (ret == -1) { + if (!rsv_is_empty(&my_rsv->rsv_window)) + rsv_window_remove(sb, my_rsv); + spin_unlock(rsv_lock); + return -1; + } + /* * On success, find_next_reservable_window() returns the * reservation window where there is a reservable space after it. @@ -937,8 +963,9 @@ retry: * block. Search start from the start block of the reservable space * we just found. */ + spin_unlock(rsv_lock); first_free_block = bitmap_search_next_usable_block( - reservable_space_start - group_first_block, + my_rsv->rsv_start - group_first_block, bitmap_bh, group_end_block - group_first_block + 1); if (first_free_block < 0) { @@ -946,54 +973,29 @@ retry: * no free block left on the bitmap, no point * to reserve the space. return failed. */ - goto failed; + spin_lock(rsv_lock); + if (!rsv_is_empty(&my_rsv->rsv_window)) + rsv_window_remove(sb, my_rsv); + spin_unlock(rsv_lock); + return -1; /* failed */ } + start_block = first_free_block + group_first_block; /* * check if the first free block is within the - * free space we just found + * free space we just reserved */ - if ((start_block >= reservable_space_start) && - (start_block < reservable_space_start + size)) - goto found_rsv_window; + if (start_block >= my_rsv->rsv_start && start_block < my_rsv->rsv_end) + return 0; /* success */ /* * if the first free bit we found is out of the reservable space - * this means there is no free block on the reservable space - * we should continue search for next reservable space, + * continue search for next reservable space, * start from where the free block is, * we also shift the list head to where we stopped last time */ - search_head = prev_rsv; + search_head = my_rsv; + spin_lock(rsv_lock); goto retry; - -found_rsv_window: - /* - * great! the reservable space contains some free blocks. - * if the search returns that we should add the new - * window just next to where the old window, we don't - * need to remove the old window first then add it to the - * same place, just update the new start and new end. - */ - if (my_rsv != prev_rsv) { - if (!rsv_is_empty(&my_rsv->rsv_window)) - rsv_window_remove(sb, my_rsv); - } - my_rsv->rsv_start = reservable_space_start; - my_rsv->rsv_end = my_rsv->rsv_start + size - 1; - my_rsv->rsv_alloc_hit = 0; - if (my_rsv != prev_rsv) { - ext3_rsv_window_add(sb, my_rsv); - } - return 0; /* succeed */ -failed: - /* - * failed to find a new reservation window in the current - * group, remove the current(stale) reservation window - * if there is any - */ - if (!rsv_is_empty(&my_rsv->rsv_window)) - rsv_window_remove(sb, my_rsv); - return -1; /* failed */ } /* @@ -1023,7 +1025,6 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, int goal, struct ext3_reserve_window_node * my_rsv, int *errp) { - spinlock_t *rsv_lock; unsigned long group_first_block; int ret = 0; int fatal; @@ -1052,7 +1053,6 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL); goto out; } - rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; /* * goal is a group relative block number (if there is a goal) * 0 < goal < EXT3_BLOCKS_PER_GROUP(sb) @@ -1078,30 +1078,21 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, * then we could go to allocate from the reservation window directly. */ while (1) { - struct ext3_reserve_window rsv_copy; - - rsv_copy._rsv_start = my_rsv->rsv_start; - rsv_copy._rsv_end = my_rsv->rsv_end; - - if (rsv_is_empty(&rsv_copy) || (ret < 0) || - !goal_in_my_reservation(&rsv_copy, goal, group, sb)) { - spin_lock(rsv_lock); + if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || + !goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) { ret = alloc_new_reservation(my_rsv, goal, sb, group, bitmap_bh); - rsv_copy._rsv_start = my_rsv->rsv_start; - rsv_copy._rsv_end = my_rsv->rsv_end; - spin_unlock(rsv_lock); if (ret < 0) break; /* failed */ - if (!goal_in_my_reservation(&rsv_copy, goal, group, sb)) + if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) goal = -1; } - if ((rsv_copy._rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) - || (rsv_copy._rsv_end < group_first_block)) + if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb)) + || (my_rsv->rsv_end < group_first_block)) BUG(); ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, - &rsv_copy); + &my_rsv->rsv_window); if (ret >= 0) { my_rsv->rsv_alloc_hit++; break; /* succeed */ diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 5ad8cf02..98e7834 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -36,7 +36,11 @@ static int ext3_release_file (struct inode * inode, struct file * filp) /* if we are the last writer on the inode, drop the block reservation */ if ((filp->f_mode & FMODE_WRITE) && (atomic_read(&inode->i_writecount) == 1)) + { + down(&EXT3_I(inode)->truncate_sem); ext3_discard_reservation(inode); + up(&EXT3_I(inode)->truncate_sem); + } if (is_dx(inode) && filp->private_data) ext3_htree_free_dir_info(filp->private_data); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index b4b3e8a..a6d1779 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -944,7 +944,8 @@ clear_qf_name: "for remount\n"); return 0; } - match_int(&args[0], &option); + if (match_int(&args[0], &option) != 0) + return 0; *n_blocks_count = option; break; case Opt_nobh: diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index ee3536f..1b7a3ef 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c @@ -2,7 +2,7 @@ #include <linux/nfs.h> #include <linux/nfs3.h> #include <linux/nfs_fs.h> -#include <linux/xattr_acl.h> +#include <linux/posix_acl_xattr.h> #include <linux/nfsacl.h> #define NFSDBG_FACILITY NFSDBG_PROC @@ -53,9 +53,9 @@ ssize_t nfs3_getxattr(struct dentry *dentry, const char *name, struct posix_acl *acl; int type, error = 0; - if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) + if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) type = ACL_TYPE_ACCESS; - else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) + else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) type = ACL_TYPE_DEFAULT; else return -EOPNOTSUPP; @@ -82,9 +82,9 @@ int nfs3_setxattr(struct dentry *dentry, const char *name, struct posix_acl *acl; int type, error; - if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) + if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) type = ACL_TYPE_ACCESS; - else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) + else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) type = ACL_TYPE_DEFAULT; else return -EOPNOTSUPP; @@ -103,9 +103,9 @@ int nfs3_removexattr(struct dentry *dentry, const char *name) struct inode *inode = dentry->d_inode; int type; - if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0) + if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) type = ACL_TYPE_ACCESS; - else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0) + else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) type = ACL_TYPE_DEFAULT; else return -EOPNOTSUPP; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index de340ff..be24ead 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -46,10 +46,9 @@ #include <linux/nfsd/nfsfh.h> #include <linux/quotaops.h> #include <linux/dnotify.h> -#include <linux/xattr_acl.h> #include <linux/posix_acl.h> -#ifdef CONFIG_NFSD_V4 #include <linux/posix_acl_xattr.h> +#ifdef CONFIG_NFSD_V4 #include <linux/xattr.h> #include <linux/nfs4.h> #include <linux/nfs4_acl.h> @@ -1872,10 +1871,10 @@ nfsd_get_posix_acl(struct svc_fh *fhp, int type) return ERR_PTR(-EOPNOTSUPP); switch(type) { case ACL_TYPE_ACCESS: - name = XATTR_NAME_ACL_ACCESS; + name = POSIX_ACL_XATTR_ACCESS; break; case ACL_TYPE_DEFAULT: - name = XATTR_NAME_ACL_DEFAULT; + name = POSIX_ACL_XATTR_DEFAULT; break; default: return ERR_PTR(-EOPNOTSUPP); @@ -1919,17 +1918,17 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) return -EOPNOTSUPP; switch(type) { case ACL_TYPE_ACCESS: - name = XATTR_NAME_ACL_ACCESS; + name = POSIX_ACL_XATTR_ACCESS; break; case ACL_TYPE_DEFAULT: - name = XATTR_NAME_ACL_DEFAULT; + name = POSIX_ACL_XATTR_DEFAULT; break; default: return -EOPNOTSUPP; } if (acl && acl->a_count) { - size = xattr_acl_size(acl->a_count); + size = posix_acl_xattr_size(acl->a_count); value = kmalloc(size, GFP_KERNEL); if (!value) return -ENOMEM; diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 3f6dc71..4673157 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -159,7 +159,7 @@ udf_find_entry(struct inode *dir, struct dentry *dentry, char *nameptr; uint8_t lfi; uint16_t liu; - loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; + loff_t size; kernel_lb_addr bloc, eloc; uint32_t extoffset, elen, offset; struct buffer_head *bh = NULL; @@ -167,6 +167,8 @@ udf_find_entry(struct inode *dir, struct dentry *dentry, if (!dir) return NULL; + size = (udf_ext0_offset(dir) + dir->i_size) >> 2; + f_pos = (udf_ext0_offset(dir) >> 2); fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c627bc4..9ad1424 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -108,6 +108,21 @@ typedef int (*acpi_op_unbind) (struct acpi_device *device); typedef int (*acpi_op_match) (struct acpi_device *device, struct acpi_driver *driver); +struct acpi_bus_ops { + u32 acpi_op_add:1; + u32 acpi_op_remove:1; + u32 acpi_op_lock:1; + u32 acpi_op_start:1; + u32 acpi_op_stop:1; + u32 acpi_op_suspend:1; + u32 acpi_op_resume:1; + u32 acpi_op_scan:1; + u32 acpi_op_bind:1; + u32 acpi_op_unbind:1; + u32 acpi_op_match:1; + u32 reserved:21; +}; + struct acpi_device_ops { acpi_op_add add; acpi_op_remove remove; @@ -327,9 +342,9 @@ int acpi_bus_generate_event (struct acpi_device *device, u8 type, int data); int acpi_bus_receive_event (struct acpi_bus_event *event); int acpi_bus_register_driver (struct acpi_driver *driver); int acpi_bus_unregister_driver (struct acpi_driver *driver); -int acpi_bus_scan (struct acpi_device *start); int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type); +int acpi_bus_start (struct acpi_device *device); int acpi_match_ids (struct acpi_device *device, char *ids); diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index c62e92e..4ec722d 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -68,6 +68,7 @@ void acpi_pci_irq_del_prt (int segment, int bus); struct pci_bus; +acpi_status acpi_get_pci_id (acpi_handle handle, struct acpi_pci_id *id); int acpi_pci_bind (struct acpi_device *device); int acpi_pci_unbind (struct acpi_device *device); int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus); diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h index 0c7b57b..b7806aa 100644 --- a/include/asm-alpha/pci.h +++ b/include/asm-alpha/pci.h @@ -223,6 +223,25 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, /* Nothing to do. */ } +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + unsigned long cacheline_size; + u8 byte; + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); + if (byte == 0) + cacheline_size = 1024; + else + cacheline_size = (int) byte * 4; + + *strat = PCI_DMA_BURST_BOUNDARY; + *strategy_parameter = cacheline_size; +} +#endif + /* TODO: integrate with include/asm-generic/pci.h ? */ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) { diff --git a/include/asm-arm/arch-s3c2410/audio.h b/include/asm-arm/arch-s3c2410/audio.h new file mode 100644 index 0000000..0d276e6 --- /dev/null +++ b/include/asm-arm/arch-s3c2410/audio.h @@ -0,0 +1,49 @@ +/* linux/include/asm-arm/arch-s3c2410/audio.h + * + * (c) 2004-2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX - Audio platfrom_device info + * + * 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. + * + * Changelog: + * 20-Nov-2004 BJD Created file + * 07-Mar-2005 BJD Added suspend/resume calls +*/ + +#ifndef __ASM_ARCH_AUDIO_H +#define __ASM_ARCH_AUDIO_H __FILE__ + +/* struct s3c24xx_iis_ops + * + * called from the s3c24xx audio core to deal with the architecture + * or the codec's setup and control. + * + * the pointer to itself is passed through in case the caller wants to + * embed this in an larger structure for easy reference to it's context. +*/ + +struct s3c24xx_iis_ops { + struct module *owner; + + int (*startup)(struct s3c24xx_iis_ops *me); + void (*shutdown)(struct s3c24xx_iis_ops *me); + int (*suspend)(struct s3c24xx_iis_ops *me); + int (*resume)(struct s3c24xx_iis_ops *me); + + int (*open)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm); + int (*close)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm); + int (*prepare)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm, snd_pcm_runtime_t *rt); +}; + +struct s3c24xx_platdata_iis { + const char *codec_clk; + struct s3c24xx_iis_ops *ops; + int (*match_dev)(struct device *dev); +}; + +#endif /* __ASM_ARCH_AUDIO_H */ diff --git a/include/asm-arm/pci.h b/include/asm-arm/pci.h index 40ffaef..e300646 100644 --- a/include/asm-arm/pci.h +++ b/include/asm-arm/pci.h @@ -42,6 +42,16 @@ static inline void pcibios_penalize_isa_irq(int irq) #define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME) #define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL)) +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + #define HAVE_PCI_MMAP extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); diff --git a/include/asm-frv/pci.h b/include/asm-frv/pci.h index a6a4692..b4efe5e 100644 --- a/include/asm-frv/pci.h +++ b/include/asm-frv/pci.h @@ -57,6 +57,16 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, */ #define PCI_DMA_BUS_IS_PHYS (1) +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + /* * These are pretty much arbitary with the CoMEM implementation. * We have the whole address space to ourselves. diff --git a/include/asm-i386/pci.h b/include/asm-i386/pci.h index fb749b8..3561899 100644 --- a/include/asm-i386/pci.h +++ b/include/asm-i386/pci.h @@ -99,6 +99,16 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev) { } +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + #endif /* __KERNEL__ */ /* implement the pci_ DMA API in terms of the generic device dma_ one */ diff --git a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h index 38a7a72..1093f35 100644 --- a/include/asm-ia64/iosapic.h +++ b/include/asm-ia64/iosapic.h @@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector) } extern void __init iosapic_system_init (int pcat_compat); -extern void __init iosapic_init (unsigned long address, +extern int __devinit iosapic_init (unsigned long address, unsigned int gsi_base); +#ifdef CONFIG_HOTPLUG +extern int iosapic_remove (unsigned int gsi_base); +#endif /* CONFIG_HOTPLUG */ extern int gsi_to_vector (unsigned int gsi); extern int gsi_to_irq (unsigned int gsi); extern void iosapic_enable_intr (unsigned int vector); @@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr); extern void iosapic_pci_fixup (int); #ifdef CONFIG_NUMA -extern void __init map_iosapic_to_node (unsigned int, int); +extern void __devinit map_iosapic_to_node (unsigned int, int); #endif #else #define iosapic_system_init(pcat_compat) do { } while (0) -#define iosapic_init(address,gsi_base) do { } while (0) +#define iosapic_init(address,gsi_base) (-EINVAL) +#ifdef CONFIG_HOTPLUG +#define iosapic_remove(gsi_base) (-ENODEV) +#endif /* CONFIG_HOTPLUG */ #define iosapic_register_intr(gsi,polarity,trigger) (gsi) #define iosapic_unregister_intr(irq) do { } while (0) #define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0) diff --git a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h index a8314ee..0c4c5d8 100644 --- a/include/asm-ia64/pci.h +++ b/include/asm-ia64/pci.h @@ -82,6 +82,25 @@ extern int pcibios_prep_mwi (struct pci_dev *); #define sg_dma_len(sg) ((sg)->dma_length) #define sg_dma_address(sg) ((sg)->dma_address) +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + unsigned long cacheline_size; + u8 byte; + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); + if (byte == 0) + cacheline_size = 1024; + else + cacheline_size = (int) byte * 4; + + *strat = PCI_DMA_BURST_MULTIPLE; + *strategy_parameter = cacheline_size; +} +#endif + #define HAVE_PCI_MMAP extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h index c9c576b..2d323b6 100644 --- a/include/asm-mips/pci.h +++ b/include/asm-mips/pci.h @@ -130,6 +130,16 @@ extern void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, extern void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction); +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + extern void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, struct resource *res); diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h index 0763c29..ee741c1 100644 --- a/include/asm-parisc/pci.h +++ b/include/asm-parisc/pci.h @@ -230,6 +230,25 @@ extern inline void pcibios_register_hba(struct pci_hba_data *x) /* export the pci_ DMA API in terms of the dma_ one */ #include <asm-generic/pci-dma-compat.h> +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + unsigned long cacheline_size; + u8 byte; + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); + if (byte == 0) + cacheline_size = 1024; + else + cacheline_size = (int) byte * 4; + + *strat = PCI_DMA_BURST_MULTIPLE; + *strategy_parameter = cacheline_size; +} +#endif + extern void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, struct resource *res); diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h index ce5ae6d..db0a2a0 100644 --- a/include/asm-ppc/pci.h +++ b/include/asm-ppc/pci.h @@ -69,6 +69,16 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr); #define pci_unmap_len(PTR, LEN_NAME) (0) #define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + /* * At present there are very few 32-bit PPC machines that can have * memory above the 4GB point, and we don't support that. @@ -103,6 +113,12 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, unsigned long size, pgprot_t prot); +#define HAVE_ARCH_PCI_RESOURCE_TO_USER +extern void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, + u64 *start, u64 *end); + + #endif /* __KERNEL__ */ #endif /* __PPC_PCI_H */ diff --git a/include/asm-ppc64/byteorder.h b/include/asm-ppc64/byteorder.h index 8032753..8b57da6 100644 --- a/include/asm-ppc64/byteorder.h +++ b/include/asm-ppc64/byteorder.h @@ -40,7 +40,6 @@ static __inline__ void st_le32(volatile __u32 *addr, const __u32 val) __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr)); } -#if 0 static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value) { __u16 result; @@ -63,17 +62,8 @@ static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value) return result; } -static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 value) -{ - __u64 result; -#error implement me -} - #define __arch__swab16(x) ___arch__swab16(x) #define __arch__swab32(x) ___arch__swab32(x) -#define __arch__swab64(x) ___arch__swab64(x) - -#endif /* The same, but returns converted value from the location pointer by addr. */ #define __arch__swab16p(addr) ld_le16(addr) diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h index 6cd593f..d12dfce 100644 --- a/include/asm-ppc64/pci.h +++ b/include/asm-ppc64/pci.h @@ -78,6 +78,25 @@ static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask) return 0; } +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + unsigned long cacheline_size; + u8 byte; + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); + if (byte == 0) + cacheline_size = 1024; + else + cacheline_size = (int) byte * 4; + + *strat = PCI_DMA_BURST_MULTIPLE; + *strategy_parameter = cacheline_size; +} +#endif + extern int pci_domain_nr(struct pci_bus *bus); /* Decide whether to display the domain number in /proc */ @@ -136,6 +155,13 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file, unsigned long size, pgprot_t prot); +#ifdef CONFIG_PPC_MULTIPLATFORM +#define HAVE_ARCH_PCI_RESOURCE_TO_USER +extern void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, + u64 *start, u64 *end); +#endif /* CONFIG_PPC_MULTIPLATFORM */ + #endif /* __KERNEL__ */ diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h index 9c3b63d..2604488 100644 --- a/include/asm-sh/pci.h +++ b/include/asm-sh/pci.h @@ -96,6 +96,16 @@ static inline void pcibios_penalize_isa_irq(int irq) #define sg_dma_address(sg) (virt_to_bus((sg)->dma_address)) #define sg_dma_len(sg) ((sg)->length) +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + /* Board-specific fixup routines. */ extern void pcibios_fixup(void); extern void pcibios_fixup_irqs(void); diff --git a/include/asm-sh64/pci.h b/include/asm-sh64/pci.h index 8cc14e139..c68870e 100644 --- a/include/asm-sh64/pci.h +++ b/include/asm-sh64/pci.h @@ -86,6 +86,16 @@ static inline void pcibios_penalize_isa_irq(int irq) #define sg_dma_address(sg) ((sg)->dma_address) #define sg_dma_len(sg) ((sg)->length) +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + /* Board-specific fixup routines. */ extern void pcibios_fixup(void); extern void pcibios_fixup_irqs(void); diff --git a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h index d200a25..44bb387 100644 --- a/include/asm-sparc/pci.h +++ b/include/asm-sparc/pci.h @@ -144,6 +144,16 @@ extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask) #define pci_dac_dma_supported(dev, mask) (0) +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + static inline void pcibios_add_platform_entries(struct pci_dev *dev) { } diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index 2a0c85c..84e41c1 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h @@ -220,6 +220,25 @@ static inline int pci_dma_mapping_error(dma_addr_t dma_addr) return (dma_addr == PCI_DMA_ERROR_CODE); } +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + unsigned long cacheline_size; + u8 byte; + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); + if (byte == 0) + cacheline_size = 1024; + else + cacheline_size = (int) byte * 4; + + *strat = PCI_DMA_BURST_BOUNDARY; + *strategy_parameter = cacheline_size; +} +#endif + /* Return the index of the PCI controller for device PDEV. */ extern int pci_domain_nr(struct pci_bus *bus); diff --git a/include/asm-v850/pci.h b/include/asm-v850/pci.h index e419414..8e79be0 100644 --- a/include/asm-v850/pci.h +++ b/include/asm-v850/pci.h @@ -81,6 +81,16 @@ extern void pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr, dma_addr_t dma_addr); +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + static inline void pcibios_add_platform_entries(struct pci_dev *dev) { } diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h index 8712520..c1961db 100644 --- a/include/asm-x86_64/pci.h +++ b/include/asm-x86_64/pci.h @@ -123,6 +123,16 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, flush_write_buffers(); } +#ifdef CONFIG_PCI +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + *strat = PCI_DMA_BURST_INFINITY; + *strategy_parameter = ~0UL; +} +#endif + #define HAVE_PCI_MMAP extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, enum pci_mmap_state mmap_state, int write_combine); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index b123cc0..ef84836 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -342,11 +342,19 @@ struct acpi_table_ecdt { /* PCI MMCONFIG */ +/* Defined in PCI Firmware Specification 3.0 */ +struct acpi_table_mcfg_config { + u32 base_address; + u32 base_reserved; + u16 pci_segment_group_number; + u8 start_bus_number; + u8 end_bus_number; + u8 reserved[4]; +} __attribute__ ((packed)); struct acpi_table_mcfg { struct acpi_table_header header; u8 reserved[8]; - u32 base_address; - u32 base_reserved; + struct acpi_table_mcfg_config config[0]; } __attribute__ ((packed)); /* Table Handlers */ @@ -391,6 +399,7 @@ int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header); int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); +int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); void acpi_table_print_madt_entry (acpi_table_entry_header *madt); void acpi_table_print_srat_entry (acpi_table_entry_header *srat); @@ -407,9 +416,13 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu); int acpi_unmap_lsapic(int cpu); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ +int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); +int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); + extern int acpi_mp_config; -extern u32 pci_mmcfg_base_addr; +extern struct acpi_table_mcfg_config *pci_mmcfg_config; +extern int pci_mmcfg_config_num; extern int sbf_port ; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 21a8674..0881b5c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -96,6 +96,7 @@ struct io_context { void put_io_context(struct io_context *ioc); void exit_io_context(void); +struct io_context *current_io_context(int gfp_flags); struct io_context *get_io_context(int gfp_flags); void copy_io_context(struct io_context **pdst, struct io_context **psrc); void swap_io_context(struct io_context **ioc1, struct io_context **ioc2); diff --git a/include/linux/byteorder/swabb.h b/include/linux/byteorder/swabb.h index d28d9a8..d5f2a32 100644 --- a/include/linux/byteorder/swabb.h +++ b/include/linux/byteorder/swabb.h @@ -92,29 +92,32 @@ #endif /* OPTIMIZE */ -static __inline__ __const__ __u32 __fswahw32(__u32 x) +static inline __u32 __fswahw32(__u32 x) { return __arch__swahw32(x); } -static __inline__ __u32 __swahw32p(__u32 *x) + +static inline __u32 __swahw32p(__u32 *x) { return __arch__swahw32p(x); } -static __inline__ void __swahw32s(__u32 *addr) + +static inline void __swahw32s(__u32 *addr) { __arch__swahw32s(addr); } - -static __inline__ __const__ __u32 __fswahb32(__u32 x) +static inline __u32 __fswahb32(__u32 x) { return __arch__swahb32(x); } -static __inline__ __u32 __swahb32p(__u32 *x) + +static inline __u32 __swahb32p(__u32 *x) { return __arch__swahb32p(x); } -static __inline__ void __swahb32s(__u32 *addr) + +static inline void __swahb32s(__u32 *addr) { __arch__swahb32s(addr); } diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index a147825..cf3847e 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -25,6 +25,7 @@ #define _LINUX_ETHERDEVICE_H #include <linux/if_ether.h> +#include <linux/netdevice.h> #include <linux/random.h> #ifdef __KERNEL__ @@ -65,7 +66,7 @@ static inline int is_zero_ether_addr(const u8 *addr) */ static inline int is_multicast_ether_addr(const u8 *addr) { - return addr[0] & 0x01; + return ((addr[0] != 0xff) && (0x01 & addr[0])); } /** diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h index d228230..5416956 100644 --- a/include/linux/i2c-dev.h +++ b/include/linux/i2c-dev.h @@ -25,6 +25,7 @@ #define _LINUX_I2C_DEV_H #include <linux/types.h> +#include <linux/compiler.h> /* Some IOCTL commands are defined in <linux/i2c.h> */ /* Note: 10-bit addresses are NOT supported! */ diff --git a/include/linux/in6.h b/include/linux/in6.h index f8256c5..dcf5720 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -156,7 +156,7 @@ struct in6_flowlabel_req #define IPV6_CHECKSUM 7 #define IPV6_HOPLIMIT 8 #define IPV6_NEXTHOP 9 -#define IPV6_AUTHHDR 10 +#define IPV6_AUTHHDR 10 /* obsolete */ #define IPV6_FLOWINFO 11 #define IPV6_UNICAST_HOPS 16 diff --git a/include/linux/irq.h b/include/linux/irq.h index 1227779..069d3b8 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -85,9 +85,10 @@ extern int no_irq_affinity; extern int noirqdebug_setup(char *str); extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, - struct irqaction *action); + struct irqaction *action); extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); -extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret); +extern void note_interrupt(unsigned int irq, irq_desc_t *desc, + int action_ret, struct pt_regs *regs); extern int can_request_irq(unsigned int irq, unsigned long irqflags); extern void init_irq_proc(void); diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 3029cad..27e4d16 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -168,6 +168,7 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) nlh->nlmsg_flags = flags; nlh->nlmsg_pid = pid; nlh->nlmsg_seq = seq; + memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size); return nlh; } diff --git a/include/linux/pci.h b/include/linux/pci.h index b5238bd..66798b4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -734,16 +734,20 @@ void pcibios_update_irq(struct pci_dev *, int irq); /* Generic PCI functions used internally */ extern struct pci_bus *pci_find_bus(int domain, int busnr); +void pci_bus_add_devices(struct pci_bus *bus); struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata); static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { - return pci_scan_bus_parented(NULL, bus, ops, sysdata); + struct pci_bus *root_bus; + root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata); + if (root_bus) + pci_bus_add_devices(root_bus); + return root_bus; } int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn); unsigned int pci_scan_child_bus(struct pci_bus *bus); void pci_bus_add_device(struct pci_dev *dev); -void pci_bus_add_devices(struct pci_bus *bus); void pci_name_device(struct pci_dev *dev); char *pci_class_name(u32 class); void pci_read_bridge_bases(struct pci_bus *child); @@ -870,6 +874,15 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass #define pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle) #define pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr) +enum pci_dma_burst_strategy { + PCI_DMA_BURST_INFINITY, /* make bursts as large as possible, + strategy_parameter is N/A */ + PCI_DMA_BURST_BOUNDARY, /* disconnect at every strategy_parameter + byte boundaries */ + PCI_DMA_BURST_MULTIPLE, /* disconnect at some multiple of + strategy_parameter byte boundaries */ +}; + #if defined(CONFIG_ISA) || defined(CONFIG_EISA) extern struct pci_dev *isa_bridge; #endif @@ -972,6 +985,8 @@ static inline int pci_proc_domain(struct pci_bus *bus) } #endif +#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0) + #endif /* !CONFIG_PCI */ /* these helpers provide future and backwards compatibility @@ -1016,6 +1031,20 @@ static inline char *pci_name(struct pci_dev *pdev) #define pci_pretty_name(dev) "" #endif + +/* Some archs don't want to expose struct resource to userland as-is + * in sysfs and /proc + */ +#ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER +static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, + const struct resource *rsrc, u64 *start, u64 *end) +{ + *start = rsrc->start; + *end = rsrc->end; +} +#endif /* HAVE_ARCH_PCI_RESOURCE_TO_USER */ + + /* * The world is not perfect and supplies us with broken PCI devices. * For at least a part of these bugs we need a work-around, so both diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 1e0bc6a..c3ee1ae 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -62,6 +62,8 @@ #define PCI_BASE_CLASS_SYSTEM 0x08 #define PCI_CLASS_SYSTEM_PIC 0x0800 +#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010 +#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020 #define PCI_CLASS_SYSTEM_DMA 0x0801 #define PCI_CLASS_SYSTEM_TIMER 0x0802 #define PCI_CLASS_SYSTEM_RTC 0x0803 diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 25d2d67..bd2c5a2 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -276,6 +276,7 @@ struct tc_rsvp_pinfo __u8 protocol; __u8 tunnelid; __u8 tunnelhdr; + __u8 pad; }; /* ROUTE filter */ diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 1d9da36..60ffcb9 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -221,9 +221,11 @@ struct tc_gred_qopt /* gred setup */ struct tc_gred_sopt { - __u32 DPs; - __u32 def_DP; - __u8 grio; + __u32 DPs; + __u32 def_DP; + __u8 grio; + __u8 pad1; + __u16 pad2; }; /* HTB section */ @@ -351,6 +353,7 @@ struct tc_cbq_ovl #define TC_CBQ_OVL_DROP 3 #define TC_CBQ_OVL_RCLASSIC 4 unsigned char priority2; + __u16 pad; __u32 penalty; }; diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index d021888..657c05a 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -363,6 +363,8 @@ enum struct rta_session { __u8 proto; + __u8 pad1; + __u16 pad2; union { struct { @@ -635,10 +637,13 @@ struct ifinfomsg struct prefixmsg { unsigned char prefix_family; + unsigned char prefix_pad1; + unsigned short prefix_pad2; int prefix_ifindex; unsigned char prefix_type; unsigned char prefix_len; unsigned char prefix_flags; + unsigned char prefix_pad3; }; enum @@ -898,7 +903,9 @@ extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const voi memcpy(skb_put(skb, attrlen), data, attrlen); }) #define RTA_PUT_NOHDR(skb, attrlen, data) \ - RTA_APPEND(skb, RTA_ALIGN(attrlen), data) +({ RTA_APPEND(skb, RTA_ALIGN(attrlen), data); \ + memset(skb->tail - (RTA_ALIGN(attrlen) - attrlen), 0, \ + RTA_ALIGN(attrlen) - attrlen); }) #define RTA_PUT_U8(skb, attrtype, value) \ ({ u8 _tmp = (value); \ @@ -978,6 +985,7 @@ __rta_reserve(struct sk_buff *skb, int attrtype, int attrlen) rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size)); rta->rta_type = attrtype; rta->rta_len = size; + memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size); return rta; } diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index ebfe125..5b5f434 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -641,6 +641,7 @@ enum { NET_SCTP_ADDIP_ENABLE = 13, NET_SCTP_PRSCTP_ENABLE = 14, NET_SCTP_SNDBUF_POLICY = 15, + NET_SCTP_SACK_TIMEOUT = 16, }; /* /proc/sys/net/bridge */ diff --git a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h index 39e7ff4..ee21e6b 100644 --- a/include/linux/usb_ch9.h +++ b/include/linux/usb_ch9.h @@ -19,7 +19,7 @@ #ifndef __LINUX_USB_CH9_H #define __LINUX_USB_CH9_H -#include <asm/types.h> /* __u8 etc */ +#include <linux/types.h> /* __u8 etc */ /*-------------------------------------------------------------------------*/ @@ -294,8 +294,8 @@ struct usb_endpoint_descriptor { __le16 wMaxPacketSize; __u8 bInterval; - // NOTE: these two are _only_ in audio endpoints. - // use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. + /* NOTE: these two are _only_ in audio endpoints. */ + /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ __u8 bRefresh; __u8 bSynchAddress; } __attribute__ ((packed)); diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 4e0edce..acbfc52 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -221,6 +221,8 @@ struct v4l2_pix_format /* Vendor-specific formats */ #define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */ #define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') /* SN9C10x compression */ +#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1') /* pwc older webcam */ +#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2') /* pwc newer webcam */ /* * F O R M A T E N U M E R A T I O N diff --git a/include/linux/writeback.h b/include/linux/writeback.h index d5c3fe1..542dbae 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -85,7 +85,7 @@ static inline void wait_on_inode(struct inode *inode) /* * mm/page-writeback.c */ -int wakeup_bdflush(long nr_pages); +int wakeup_pdflush(long nr_pages); void laptop_io_completion(void); void laptop_sync_completion(void); void throttle_vm_writeout(void); diff --git a/include/linux/xattr_acl.h b/include/linux/xattr_acl.h deleted file mode 100644 index 7a1f9b9..0000000 --- a/include/linux/xattr_acl.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - File: linux/xattr_acl.h - - (extended attribute representation of access control lists) - - (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org> -*/ - -#ifndef _LINUX_XATTR_ACL_H -#define _LINUX_XATTR_ACL_H - -#include <linux/posix_acl.h> - -#define XATTR_NAME_ACL_ACCESS "system.posix_acl_access" -#define XATTR_NAME_ACL_DEFAULT "system.posix_acl_default" - -#define XATTR_ACL_VERSION 0x0002 - -typedef struct { - __u16 e_tag; - __u16 e_perm; - __u32 e_id; -} xattr_acl_entry; - -typedef struct { - __u32 a_version; - xattr_acl_entry a_entries[0]; -} xattr_acl_header; - -static inline size_t xattr_acl_size(int count) -{ - return sizeof(xattr_acl_header) + count * sizeof(xattr_acl_entry); -} - -static inline int xattr_acl_count(size_t size) -{ - if (size < sizeof(xattr_acl_header)) - return -1; - size -= sizeof(xattr_acl_header); - if (size % sizeof(xattr_acl_entry)) - return -1; - return size / sizeof(xattr_acl_entry); -} - -struct posix_acl * posix_acl_from_xattr(const void *value, size_t size); -int posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size); - - - -#endif /* _LINUX_XATTR_ACL_H */ diff --git a/include/media/tuner.h b/include/media/tuner.h index 2dd8310..4794c56 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -1,5 +1,6 @@ -/* +/* $Id: tuner.h,v 1.33 2005/06/21 14:58:08 mkrufky Exp $ + * tuner.h - definition for different tuners Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) @@ -23,6 +24,8 @@ #ifndef _TUNER_H #define _TUNER_H +#include <linux/videodev2.h> + #include "id.h" #define ADDR_UNSET (255) @@ -88,7 +91,7 @@ #define TUNER_LG_NTSC_TAPE 47 #define TUNER_TNF_8831BGFF 48 -#define TUNER_MICROTUNE_4042FI5 49 /* FusionHDTV 3 Gold - 4042 FI5 (3X 8147) */ +#define TUNER_MICROTUNE_4042FI5 49 /* DViCO FusionHDTV 3 Gold-Q - 4042 FI5 (3X 8147) */ #define TUNER_TCL_2002N 50 #define TUNER_PHILIPS_FM1256_IH3 51 @@ -98,18 +101,18 @@ #define TUNER_LG_PAL_TAPE 55 /* Hauppauge PVR-150 PAL */ #define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */ -#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */ +#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */ #define TUNER_YMEC_TVF_8531MF 58 #define TUNER_YMEC_TVF_5533MF 59 /* Pixelview Pro Ultra NTSC */ -#define TUNER_THOMSON_DTT7611 60 +#define TUNER_THOMSON_DTT7611 60 /* DViCO FusionHDTV 3 Gold-T */ #define TUNER_TENA_9533_DI 61 + #define TUNER_TEA5767 62 /* Only FM Radio Tuner */ +#define TUNER_PHILIPS_FMD1216ME_MK3 63 #define TEA5767_TUNER_NAME "Philips TEA5767HN FM Radio" -#define TUNER_THOMSON_DTT7611 60 - #define NOTUNER 0 #define PAL 1 /* PAL_BG */ #define PAL_I 2 @@ -194,11 +197,15 @@ struct tuner { unsigned char i2c_easy_mode[2]; unsigned char i2c_set_freq[8]; + /* used to keep track of audmode */ + unsigned int audmode; + /* function ptrs */ void (*tv_freq)(struct i2c_client *c, unsigned int freq); void (*radio_freq)(struct i2c_client *c, unsigned int freq); int (*has_signal)(struct i2c_client *c); int (*is_stereo)(struct i2c_client *c); + int (*set_tuner)(struct i2c_client *c, struct v4l2_tuner *v); }; extern unsigned int tuner_debug; @@ -206,6 +213,7 @@ extern unsigned const int tuner_count; extern int microtune_init(struct i2c_client *c); extern int tda8290_init(struct i2c_client *c); +extern int tea5767_tuner_init(struct i2c_client *c); extern int default_tuner_init(struct i2c_client *c); #define tuner_warn(fmt, arg...) \ diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 7fe57f9..db09580 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -94,6 +94,8 @@ struct eapol { u16 length; } __attribute__ ((packed)); +#define IEEE80211_1ADDR_LEN 10 +#define IEEE80211_2ADDR_LEN 16 #define IEEE80211_3ADDR_LEN 24 #define IEEE80211_4ADDR_LEN 30 #define IEEE80211_FCS_LEN 4 @@ -300,23 +302,6 @@ struct ieee80211_snap_hdr { #define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9 -/* Information Element IDs */ -#define WLAN_EID_SSID 0 -#define WLAN_EID_SUPP_RATES 1 -#define WLAN_EID_FH_PARAMS 2 -#define WLAN_EID_DS_PARAMS 3 -#define WLAN_EID_CF_PARAMS 4 -#define WLAN_EID_TIM 5 -#define WLAN_EID_IBSS_PARAMS 6 -#define WLAN_EID_CHALLENGE 16 -#define WLAN_EID_RSN 48 -#define WLAN_EID_GENERIC 221 - -#define IEEE80211_MGMT_HDR_LEN 24 -#define IEEE80211_DATA_HDR3_LEN 24 -#define IEEE80211_DATA_HDR4_LEN 30 - - #define IEEE80211_STATMASK_SIGNAL (1<<0) #define IEEE80211_STATMASK_RSSI (1<<1) #define IEEE80211_STATMASK_NOISE (1<<2) @@ -441,6 +426,10 @@ struct ieee80211_stats { struct ieee80211_device; +#if 0 /* for later */ +#include "ieee80211_crypt.h" +#endif + #define SEC_KEY_1 (1<<0) #define SEC_KEY_2 (1<<1) #define SEC_KEY_3 (1<<2) @@ -488,15 +477,6 @@ Total: 28-2340 bytes */ -struct ieee80211_header_data { - u16 frame_ctl; - u16 duration_id; - u8 addr1[6]; - u8 addr2[6]; - u8 addr3[6]; - u16 seq_ctrl; -}; - #define BEACON_PROBE_SSID_ID_POSITION 12 /* Management Frame Information Element Types */ @@ -541,7 +521,7 @@ struct ieee80211_info_element { */ struct ieee80211_authentication { - struct ieee80211_header_data header; + struct ieee80211_hdr_3addr header; u16 algorithm; u16 transaction; u16 status; @@ -550,7 +530,7 @@ struct ieee80211_authentication { struct ieee80211_probe_response { - struct ieee80211_header_data header; + struct ieee80211_hdr_3addr header; u32 time_stamp[2]; u16 beacon_interval; u16 capability; @@ -648,12 +628,6 @@ enum ieee80211_state { #define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5] -extern inline int is_broadcast_ether_addr(const u8 *addr) -{ - return ((addr[0] == 0xff) && (addr[1] == 0xff) && (addr[2] == 0xff) && \ - (addr[3] == 0xff) && (addr[4] == 0xff) && (addr[5] == 0xff)); -} - #define CFG_IEEE80211_RESERVE_FCS (1<<0) #define CFG_IEEE80211_COMPUTE_FCS (1<<1) @@ -787,21 +761,21 @@ extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mod extern inline int ieee80211_get_hdrlen(u16 fc) { - int hdrlen = 24; + int hdrlen = IEEE80211_3ADDR_LEN; switch (WLAN_FC_GET_TYPE(fc)) { case IEEE80211_FTYPE_DATA: if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = 30; /* Addr4 */ + hdrlen = IEEE80211_4ADDR_LEN; break; case IEEE80211_FTYPE_CTL: switch (WLAN_FC_GET_STYPE(fc)) { case IEEE80211_STYPE_CTS: case IEEE80211_STYPE_ACK: - hdrlen = 10; + hdrlen = IEEE80211_1ADDR_LEN; break; default: - hdrlen = 16; + hdrlen = IEEE80211_2ADDR_LEN; break; } break; diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 771b47e..6932446 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -183,7 +183,6 @@ struct ipv6_txoptions struct ipv6_opt_hdr *hopopt; struct ipv6_opt_hdr *dst0opt; struct ipv6_rt_hdr *srcrt; /* Routing Header */ - struct ipv6_opt_hdr *auth; struct ipv6_opt_hdr *dst1opt; /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */ diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 4868c7f..5999e56 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -263,23 +263,11 @@ enum { SCTP_MIN_PMTU = 576 }; enum { SCTP_MAX_DUP_TSNS = 16 }; enum { SCTP_MAX_GABS = 16 }; -/* Here we define the default timers. */ +/* Heartbeat interval - 30 secs */ +#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (30 * HZ) -/* cookie timer def = ? seconds */ -#define SCTP_DEFAULT_TIMEOUT_T1_COOKIE (3 * HZ) - -/* init timer def = 3 seconds */ -#define SCTP_DEFAULT_TIMEOUT_T1_INIT (3 * HZ) - -/* shutdown timer def = 300 ms */ -#define SCTP_DEFAULT_TIMEOUT_T2_SHUTDOWN ((300 * HZ) / 1000) - -/* 0 seconds + RTO */ -#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (10 * HZ) - -/* recv timer def = 200ms (in usec) */ +/* Delayed sack timer - 200ms */ #define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000) -#define SCTP_DEFAULT_TIMEOUT_SACK_MAX ((500 * HZ) / 1000) /* 500 ms */ /* RTO.Initial - 3 seconds * RTO.Min - 1 second diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index dfad4d3..47727c7 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -161,6 +161,9 @@ extern struct sctp_globals { */ int sndbuf_policy; + /* Delayed SACK timeout 200ms default*/ + int sack_timeout; + /* HB.interval - 30 seconds */ int hb_interval; @@ -217,6 +220,7 @@ extern struct sctp_globals { #define sctp_sndbuf_policy (sctp_globals.sndbuf_policy) #define sctp_max_retrans_path (sctp_globals.max_retrans_path) #define sctp_max_retrans_init (sctp_globals.max_retrans_init) +#define sctp_sack_timeout (sctp_globals.sack_timeout) #define sctp_hb_interval (sctp_globals.hb_interval) #define sctp_max_instreams (sctp_globals.max_instreams) #define sctp_max_outstreams (sctp_globals.max_outstreams) diff --git a/init/main.c b/init/main.c index d324801..b5e421e 100644 --- a/init/main.c +++ b/init/main.c @@ -383,6 +383,13 @@ static void noinline rest_init(void) numa_default_policy(); unlock_kernel(); preempt_enable_no_resched(); + + /* + * The boot idle thread must execute schedule() + * at least one to get things moving: + */ + schedule(); + cpu_idle(); } diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c index 98d62d8..3467097 100644 --- a/kernel/irq/autoprobe.c +++ b/kernel/irq/autoprobe.c @@ -9,6 +9,7 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/delay.h> /* * Autodetection depends on the fact that any interrupt that @@ -26,7 +27,7 @@ static DECLARE_MUTEX(probe_sem); */ unsigned long probe_irq_on(void) { - unsigned long val, delay; + unsigned long val; irq_desc_t *desc; unsigned int i; @@ -45,8 +46,7 @@ unsigned long probe_irq_on(void) } /* Wait for longstanding interrupts to trigger. */ - for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) - /* about 20ms delay */ barrier(); + msleep(20); /* * enable any unassigned irqs @@ -68,8 +68,7 @@ unsigned long probe_irq_on(void) /* * Wait for spurious interrupts to trigger */ - for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) - /* about 100ms delay */ barrier(); + msleep(100); /* * Now filter out any obviously spurious interrupts diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 436c7d9..c29f83c 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -172,7 +172,7 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index ba039e8..7df9abd 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -11,6 +11,83 @@ #include <linux/kallsyms.h> #include <linux/interrupt.h> +static int irqfixup; + +/* + * Recovery handler for misrouted interrupts. + */ + +static int misrouted_irq(int irq, struct pt_regs *regs) +{ + int i; + irq_desc_t *desc; + int ok = 0; + int work = 0; /* Did we do work for a real IRQ */ + + for(i = 1; i < NR_IRQS; i++) { + struct irqaction *action; + + if (i == irq) /* Already tried */ + continue; + desc = &irq_desc[i]; + spin_lock(&desc->lock); + action = desc->action; + /* Already running on another processor */ + if (desc->status & IRQ_INPROGRESS) { + /* + * Already running: If it is shared get the other + * CPU to go looking for our mystery interrupt too + */ + if (desc->action && (desc->action->flags & SA_SHIRQ)) + desc->status |= IRQ_PENDING; + spin_unlock(&desc->lock); + continue; + } + /* Honour the normal IRQ locking */ + desc->status |= IRQ_INPROGRESS; + spin_unlock(&desc->lock); + while (action) { + /* Only shared IRQ handlers are safe to call */ + if (action->flags & SA_SHIRQ) { + if (action->handler(i, action->dev_id, regs) == + IRQ_HANDLED) + ok = 1; + } + action = action->next; + } + local_irq_disable(); + /* Now clean up the flags */ + spin_lock(&desc->lock); + action = desc->action; + + /* + * While we were looking for a fixup someone queued a real + * IRQ clashing with our walk + */ + + while ((desc->status & IRQ_PENDING) && action) { + /* + * Perform real IRQ processing for the IRQ we deferred + */ + work = 1; + spin_unlock(&desc->lock); + handle_IRQ_event(i, regs, action); + spin_lock(&desc->lock); + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + /* + * If we did actual work for the real IRQ line we must let the + * IRQ controller clean up too + */ + if(work) + desc->handler->end(i); + spin_unlock(&desc->lock); + } + /* So the caller can adjust the irq error counts */ + return ok; +} + /* * If 99,900 of the previous 100,000 interrupts have not been handled * then assume that the IRQ is stuck in some manner. Drop a diagnostic @@ -31,7 +108,8 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) printk(KERN_ERR "irq event %d: bogus return value %x\n", irq, action_ret); } else { - printk(KERN_ERR "irq %d: nobody cared!\n", irq); + printk(KERN_ERR "irq %d: nobody cared (try booting with " + "the \"irqpoll\" option)\n", irq); } dump_stack(); printk(KERN_ERR "handlers:\n"); @@ -55,7 +133,8 @@ static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t actio } } -void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) +void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret, + struct pt_regs *regs) { if (action_ret != IRQ_HANDLED) { desc->irqs_unhandled++; @@ -63,6 +142,15 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) report_bad_irq(irq, desc, action_ret); } + if (unlikely(irqfixup)) { + /* Don't punish working computers */ + if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) { + int ok = misrouted_irq(irq, regs); + if (action_ret == IRQ_NONE) + desc->irqs_unhandled -= ok; + } + } + desc->irq_count++; if (desc->irq_count < 100000) return; @@ -94,3 +182,24 @@ int __init noirqdebug_setup(char *str) __setup("noirqdebug", noirqdebug_setup); +static int __init irqfixup_setup(char *str) +{ + irqfixup = 1; + printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n"); + printk(KERN_WARNING "This may impact system performance.\n"); + return 1; +} + +__setup("irqfixup", irqfixup_setup); + +static int __init irqpoll_setup(char *str) +{ + irqfixup = 2; + printk(KERN_WARNING "Misrouted IRQ fixup and polling support " + "enabled\n"); + printk(KERN_WARNING "This may significantly impact system " + "performance\n"); + return 1; +} + +__setup("irqpoll", irqpoll_setup); diff --git a/kernel/itimer.c b/kernel/itimer.c index 1dc988e..a72cb0e 100644 --- a/kernel/itimer.c +++ b/kernel/itimer.c @@ -153,11 +153,15 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) switch (which) { case ITIMER_REAL: +again: spin_lock_irq(&tsk->sighand->siglock); interval = tsk->signal->it_real_incr; val = it_real_value(tsk->signal); - if (val) - del_timer_sync(&tsk->signal->real_timer); + /* We are sharing ->siglock with it_real_fn() */ + if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) { + spin_unlock_irq(&tsk->sighand->siglock); + goto again; + } tsk->signal->it_real_incr = timeval_to_jiffies(&value->it_interval); it_real_arm(tsk, timeval_to_jiffies(&value->it_value)); diff --git a/kernel/kexec.c b/kernel/kexec.c index 7843548..cdd4dcd 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -241,7 +241,7 @@ static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry, unsigned long nr_segments, - struct kexec_segment *segments) + struct kexec_segment __user *segments) { int result; struct kimage *image; @@ -650,7 +650,7 @@ static kimage_entry_t *kimage_dst_used(struct kimage *image, } } - return 0; + return NULL; } static struct page *kimage_alloc_page(struct kimage *image, @@ -696,7 +696,7 @@ static struct page *kimage_alloc_page(struct kimage *image, /* Allocate a page, if we run out of memory give up */ page = kimage_alloc_pages(gfp_mask, 0); if (!page) - return 0; + return NULL; /* If the page cannot be used file it away */ if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { @@ -754,7 +754,7 @@ static int kimage_load_normal_segment(struct kimage *image, unsigned long maddr; unsigned long ubytes, mbytes; int result; - unsigned char *buf; + unsigned char __user *buf; result = 0; buf = segment->buf; @@ -818,7 +818,7 @@ static int kimage_load_crash_segment(struct kimage *image, unsigned long maddr; unsigned long ubytes, mbytes; int result; - unsigned char *buf; + unsigned char __user *buf; result = 0; buf = segment->buf; diff --git a/kernel/sched.c b/kernel/sched.c index e2b0d3e..5f2182d 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4166,6 +4166,14 @@ void show_state(void) read_unlock(&tasklist_lock); } +/** + * init_idle - set up an idle thread for a given CPU + * @idle: task in question + * @cpu: cpu the idle task belongs to + * + * NOTE: this function does not set the idle thread's NEED_RESCHED + * flag, to make booting more robust. + */ void __devinit init_idle(task_t *idle, int cpu) { runqueue_t *rq = cpu_rq(cpu); @@ -4183,7 +4191,6 @@ void __devinit init_idle(task_t *idle, int cpu) #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) idle->oncpu = 1; #endif - set_tsk_need_resched(idle); spin_unlock_irqrestore(&rq->lock, flags); /* Set the preempt count _outside_ the spinlocks! */ diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 613b99a..a6329fa 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -354,7 +354,7 @@ static void background_writeout(unsigned long _min_pages) * the whole world. Returns 0 if a pdflush thread was dispatched. Returns * -1 if all pdflush threads were busy. */ -int wakeup_bdflush(long nr_pages) +int wakeup_pdflush(long nr_pages) { if (nr_pages == 0) { struct writeback_state wbs; diff --git a/mm/vmscan.c b/mm/vmscan.c index 1fa312a..cfffe50 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -972,7 +972,7 @@ int try_to_free_pages(struct zone **zones, unsigned int gfp_mask) * writeout. So in laptop mode, write out the whole world. */ if (total_scanned > sc.swap_cluster_max + sc.swap_cluster_max/2) { - wakeup_bdflush(laptop_mode ? 0 : total_scanned); + wakeup_pdflush(laptop_mode ? 0 : total_scanned); sc.may_writepage = 1; } diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 03ae4ed..2d52fee 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -844,7 +844,7 @@ static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb, * doesn't use the bridge parent of the indev by using * the BRNF_DONT_TAKE_PARENT mask. */ if (hook == NF_IP_FORWARD && nf_bridge->physindev == NULL) { - nf_bridge->mask &= BRNF_DONT_TAKE_PARENT; + nf_bridge->mask |= BRNF_DONT_TAKE_PARENT; nf_bridge->physindev = (struct net_device *)in; } #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index e4ae34b..662975b 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -61,8 +61,6 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr, { struct ebt_log_info *info = (struct ebt_log_info *)data; char level_string[4] = "< >"; - union {struct iphdr iph; struct tcpudphdr ports; - struct arphdr arph; struct arppayload arpp;} u; level_string[1] = '0' + info->loglevel; spin_lock_bh(&ebt_log_lock); @@ -88,7 +86,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr, } printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,", NIPQUAD(ih->saddr), NIPQUAD(ih->daddr)); - printk(" IP tos=0x%02X, IP proto=%d", u.iph.tos, + printk(" IP tos=0x%02X, IP proto=%d", ih->tos, ih->protocol); if (ih->protocol == IPPROTO_TCP || ih->protocol == IPPROTO_UDP) { @@ -127,7 +125,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr, ah->ar_pln == sizeof(uint32_t)) { struct arppayload _arpp, *ap; - ap = skb_header_pointer(skb, sizeof(u.arph), + ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp); if (ap == NULL) { printk(" INCOMPLETE ARP payload"); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 851eb92..1beb782 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1598,6 +1598,8 @@ static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb, read_lock_bh(&tbl->lock); ndtmsg->ndtm_family = tbl->family; + ndtmsg->ndtm_pad1 = 0; + ndtmsg->ndtm_pad2 = 0; RTA_PUT_STRING(skb, NDTA_NAME, tbl->id); RTA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval); @@ -1683,6 +1685,8 @@ static int neightbl_fill_param_info(struct neigh_table *tbl, read_lock_bh(&tbl->lock); ndtmsg->ndtm_family = tbl->family; + ndtmsg->ndtm_pad1 = 0; + ndtmsg->ndtm_pad2 = 0; RTA_PUT_STRING(skb, NDTA_NAME, tbl->id); if (neightbl_fill_parms(skb, parms) < 0) @@ -1872,6 +1876,8 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n, struct ndmsg *ndm = NLMSG_DATA(nlh); ndm->ndm_family = n->ops->family; + ndm->ndm_pad1 = 0; + ndm->ndm_pad2 = 0; ndm->ndm_flags = n->flags; ndm->ndm_type = n->type; ndm->ndm_ifindex = n->dev->ifindex; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e013d83..4b1bb30 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -126,6 +126,7 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data rta->rta_type = attrtype; rta->rta_len = size; memcpy(RTA_DATA(rta), data, attrlen); + memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size); } size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size) @@ -188,6 +189,7 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*r), flags); r = NLMSG_DATA(nlh); r->ifi_family = AF_UNSPEC; + r->__ifi_pad = 0; r->ifi_type = dev->type; r->ifi_index = dev->ifindex; r->ifi_flags = dev_get_flags(dev); diff --git a/net/core/wireless.c b/net/core/wireless.c index b2fe378..3ff5639 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c @@ -1102,6 +1102,7 @@ static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); r = NLMSG_DATA(nlh); r->ifi_family = AF_UNSPEC; + r->__ifi_pad = 0; r->ifi_type = dev->type; r->ifi_index = dev->ifindex; r->ifi_flags = dev->flags; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 6617ea4..ab60ea6 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -92,10 +92,9 @@ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, * Set the source hardware address. */ - if(saddr) - memcpy(eth->h_source,saddr,dev->addr_len); - else - memcpy(eth->h_source,dev->dev_addr,dev->addr_len); + if(!saddr) + saddr = dev->dev_addr; + memcpy(eth->h_source,saddr,dev->addr_len); /* * Anyway, the loopback-device should never use this function... diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 0671569..b56e88e 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -43,7 +43,7 @@ * 2 of the License, or (at your option) any later version. */ -#define VERSION "0.323" +#define VERSION "0.324" #include <linux/config.h> #include <asm/uaccess.h> @@ -341,8 +341,10 @@ static struct leaf *leaf_new(void) static struct leaf_info *leaf_info_new(int plen) { struct leaf_info *li = kmalloc(sizeof(struct leaf_info), GFP_KERNEL); - li->plen = plen; - INIT_LIST_HEAD(&li->falh); + if(li) { + li->plen = plen; + INIT_LIST_HEAD(&li->falh); + } return li; } @@ -879,8 +881,8 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) return (struct node*) tn; } -static struct list_head * -fib_insert_node(struct trie *t, u32 key, int plen) +static struct list_head * +fib_insert_node(struct trie *t, int *err, u32 key, int plen) { int pos, newpos; struct tnode *tp = NULL, *tn = NULL; @@ -940,7 +942,6 @@ fib_insert_node(struct trie *t, u32 key, int plen) if(tp && IS_LEAF(tp)) BUG(); - t->revision++; /* Case 1: n is a leaf. Compare prefixes */ @@ -949,8 +950,10 @@ fib_insert_node(struct trie *t, u32 key, int plen) li = leaf_info_new(plen); - if(! li) - BUG(); + if(! li) { + *err = -ENOMEM; + goto err; + } fa_head = &li->falh; insert_leaf_info(&l->list, li); @@ -959,14 +962,19 @@ fib_insert_node(struct trie *t, u32 key, int plen) t->size++; l = leaf_new(); - if(! l) - BUG(); + if(! l) { + *err = -ENOMEM; + goto err; + } l->key = key; li = leaf_info_new(plen); - if(! li) - BUG(); + if(! li) { + tnode_free((struct tnode *) l); + *err = -ENOMEM; + goto err; + } fa_head = &li->falh; insert_leaf_info(&l->list, li); @@ -1003,9 +1011,14 @@ fib_insert_node(struct trie *t, u32 key, int plen) newpos = 0; tn = tnode_new(key, newpos, 1); /* First tnode */ } - if(!tn) - trie_bug("tnode_pfx_new failed"); + if(!tn) { + free_leaf_info(li); + tnode_free((struct tnode *) l); + *err = -ENOMEM; + goto err; + } + NODE_SET_PARENT(tn, tp); missbit=tkey_extract_bits(key, newpos, 1); @@ -1027,7 +1040,9 @@ fib_insert_node(struct trie *t, u32 key, int plen) } /* Rebalance the trie */ t->trie = trie_rebalance(t, tp); -done:; +done: + t->revision++; +err:; return fa_head; } @@ -1156,8 +1171,12 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, * Insert new entry to the list. */ - if(!fa_head) - fa_head = fib_insert_node(t, key, plen); + if(!fa_head) { + fa_head = fib_insert_node(t, &err, key, plen); + err = 0; + if(err) + goto out_free_new_fa; + } write_lock_bh(&fib_lock); @@ -1170,6 +1189,9 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req); succeeded: return 0; + +out_free_new_fa: + kmem_cache_free(fn_alias_kmem, new_fa); out: fib_release_info(fi); err:; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index af2ec88..c703528 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -283,14 +283,18 @@ static inline int ip_rcv_finish(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct iphdr *iph = skb->nh.iph; + int err; /* * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ if (skb->dst == NULL) { - if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev)) + if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) { + if (err == -EHOSTUNREACH) + IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); goto drop; + } } #ifdef CONFIG_NET_CLS_ROUTE diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index ee07aec..6ce5c32 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -188,7 +188,13 @@ static inline int ip_finish_output2(struct sk_buff *skb) skb = skb2; } - nf_reset(skb); +#ifdef CONFIG_BRIDGE_NETFILTER + /* bridge-netfilter defers calling some IP hooks to the bridge layer + * and still needs the conntrack reference. + */ + if (skb->nf_bridge == NULL) +#endif + nf_reset(skb); if (hh) { int hh_alen; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index f250903..d2bf8e1 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1149,8 +1149,10 @@ static int __init ic_dynamic(void) ic_rarp_cleanup(); #endif - if (!ic_got_reply) + if (!ic_got_reply) { + ic_myaddr = INADDR_NONE; return -1; + } printk("IP-Config: Got %s answer from %u.%u.%u.%u, ", ((ic_got_reply & IC_RARP) ? "RARP" diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index e4f809a..7833d92 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -297,6 +297,7 @@ static int vif_delete(int vifi) static void ipmr_destroy_unres(struct mfc_cache *c) { struct sk_buff *skb; + struct nlmsgerr *e; atomic_dec(&cache_resolve_queue_len); @@ -306,7 +307,9 @@ static void ipmr_destroy_unres(struct mfc_cache *c) nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); - ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT; + e = NLMSG_DATA(nlh); + e->error = -ETIMEDOUT; + memset(&e->msg, 0, sizeof(e->msg)); netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); } else kfree_skb(skb); @@ -499,6 +502,7 @@ static struct mfc_cache *ipmr_cache_alloc_unres(void) static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) { struct sk_buff *skb; + struct nlmsgerr *e; /* * Play the pending entries through our router @@ -515,7 +519,9 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); - ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -EMSGSIZE; + e = NLMSG_DATA(nlh); + e->error = -EMSGSIZE; + memset(&e->msg, 0, sizeof(e->msg)); } err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); } else diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index fd6feb5..9f16ab3 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -548,7 +548,6 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp) { if (del_timer(&cp->timer)) mod_timer(&cp->timer, jiffies); - __ip_vs_conn_put(cp); } @@ -764,7 +763,6 @@ void ip_vs_random_dropentry(void) { int idx; struct ip_vs_conn *cp; - struct ip_vs_conn *ct; /* * Randomly scan 1/32 of the whole table every second @@ -801,21 +799,12 @@ void ip_vs_random_dropentry(void) continue; } - /* - * Drop the entry, and drop its ct if not referenced - */ - atomic_inc(&cp->refcnt); - ct_write_unlock(hash); - - if ((ct = cp->control)) - atomic_inc(&ct->refcnt); IP_VS_DBG(4, "del connection\n"); ip_vs_conn_expire_now(cp); - if (ct) { + if (cp->control) { IP_VS_DBG(4, "del conn template\n"); - ip_vs_conn_expire_now(ct); + ip_vs_conn_expire_now(cp->control); } - ct_write_lock(hash); } ct_write_unlock(hash); } @@ -829,7 +818,6 @@ static void ip_vs_conn_flush(void) { int idx; struct ip_vs_conn *cp; - struct ip_vs_conn *ct; flush_again: for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) { @@ -839,18 +827,13 @@ static void ip_vs_conn_flush(void) ct_write_lock_bh(idx); list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) { - atomic_inc(&cp->refcnt); - ct_write_unlock(idx); - if ((ct = cp->control)) - atomic_inc(&ct->refcnt); IP_VS_DBG(4, "del connection\n"); ip_vs_conn_expire_now(cp); - if (ct) { + if (cp->control) { IP_VS_DBG(4, "del conn template\n"); - ip_vs_conn_expire_now(ct); + ip_vs_conn_expire_now(cp->control); } - ct_write_lock(idx); } ct_write_unlock_bh(idx); } diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 9cde8c6..6706d3a 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -30,7 +30,7 @@ #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> #include <linux/netfilter_ipv4/ip_conntrack.h> -#define CLUSTERIP_VERSION "0.6" +#define CLUSTERIP_VERSION "0.7" #define DEBUG_CLUSTERIP @@ -524,8 +524,9 @@ arp_mangle(unsigned int hook, || arp->ar_pln != 4 || arp->ar_hln != ETH_ALEN) return NF_ACCEPT; - /* we only want to mangle arp replies */ - if (arp->ar_op != htons(ARPOP_REPLY)) + /* we only want to mangle arp requests and replies */ + if (arp->ar_op != htons(ARPOP_REPLY) + && arp->ar_op != htons(ARPOP_REQUEST)) return NF_ACCEPT; payload = (void *)(arp+1); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 80cf633..12a1cf3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1909,7 +1909,7 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, */ if ((err = fib_lookup(&fl, &res)) != 0) { if (!IN_DEV_FORWARD(in_dev)) - goto e_inval; + goto e_hostunreach; goto no_route; } free_res = 1; @@ -1933,7 +1933,7 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, } if (!IN_DEV_FORWARD(in_dev)) - goto e_inval; + goto e_hostunreach; if (res.type != RTN_UNICAST) goto martian_destination; @@ -2025,6 +2025,11 @@ martian_destination: "%u.%u.%u.%u, dev %s\n", NIPQUAD(daddr), NIPQUAD(saddr), dev->name); #endif + +e_hostunreach: + err = -EHOSTUNREACH; + goto done; + e_inval: err = -EINVAL; goto done; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a54d4ef..77004b9 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2777,7 +2777,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, read_lock_bh(&idev->lock); switch (type) { case UNICAST_ADDR: - /* unicast address */ + /* unicast address incl. temp addr */ for (ifa = idev->addr_list; ifa; ifa = ifa->if_next, ip_idx++) { if (ip_idx < s_ip_idx) @@ -2788,19 +2788,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, NLM_F_MULTI)) <= 0) goto done; } - /* temp addr */ -#ifdef CONFIG_IPV6_PRIVACY - for (ifa = idev->tempaddr_list; ifa; - ifa = ifa->tmp_next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; - if ((err = inet6_fill_ifaddr(skb, ifa, - NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, RTM_NEWADDR, - NLM_F_MULTI)) <= 0) - goto done; - } -#endif break; case MULTICAST_ADDR: /* multicast address */ @@ -2923,6 +2910,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags); r = NLMSG_DATA(nlh); r->ifi_family = AF_INET6; + r->__ifi_pad = 0; r->ifi_type = dev->type; r->ifi_index = dev->ifindex; r->ifi_flags = dev_get_flags(dev); @@ -3030,9 +3018,12 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*pmsg), flags); pmsg = NLMSG_DATA(nlh); pmsg->prefix_family = AF_INET6; + pmsg->prefix_pad1 = 0; + pmsg->prefix_pad2 = 0; pmsg->prefix_ifindex = idev->dev->ifindex; pmsg->prefix_len = pinfo->prefix_len; pmsg->prefix_type = pinfo->type; + pmsg->prefix_pad3 = 0; pmsg->prefix_flags = 0; if (pinfo->onlink) diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 0e5f7499..b6c73da5 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -244,7 +244,6 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space, opt_space->opt_nflen = 0; } opt_space->dst1opt = fopt->dst1opt; - opt_space->auth = fopt->auth; opt_space->opt_flen = fopt->opt_flen; return opt_space; } diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 9594206..249c619 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -439,6 +439,8 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 pid, u32 seq, t = NLMSG_DATA(nlh); t->tca_family = AF_UNSPEC; + t->tca__pad1 = 0; + t->tca__pad2 = 0; x = (struct rtattr*) skb->tail; RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); @@ -580,6 +582,8 @@ static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid) nlh = NLMSG_PUT(skb, pid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t)); t = NLMSG_DATA(nlh); t->tca_family = AF_UNSPEC; + t->tca__pad1 = 0; + t->tca__pad2 = 0; x = (struct rtattr *) skb->tail; RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); @@ -687,7 +691,9 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event, nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags); t = NLMSG_DATA(nlh); t->tca_family = AF_UNSPEC; - + t->tca__pad1 = 0; + t->tca__pad2 = 0; + x = (struct rtattr*) skb->tail; RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); @@ -842,6 +848,8 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) cb->nlh->nlmsg_type, sizeof(*t)); t = NLMSG_DATA(nlh); t->tca_family = AF_UNSPEC; + t->tca__pad1 = 0; + t->tca__pad2 = 0; x = (struct rtattr *) skb->tail; RTA_PUT(skb, TCA_ACT_TAB, 0, NULL); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 1616bf5..3b5714e 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -331,6 +331,8 @@ tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, unsigned long fh, nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); tcm = NLMSG_DATA(nlh); tcm->tcm_family = AF_UNSPEC; + tcm->tcm__pad1 = 0; + tcm->tcm__pad1 = 0; tcm->tcm_ifindex = tp->q->dev->ifindex; tcm->tcm_parent = tp->classid; tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol); diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 232fb91..006168d 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -618,6 +618,7 @@ static int rsvp_dump(struct tcf_proto *tp, unsigned long fh, pinfo.protocol = s->protocol; pinfo.tunnelid = s->tunnelid; pinfo.tunnelhdr = f->tunnelhdr; + pinfo.pad = 0; RTA_PUT(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo); if (f->res.classid) RTA_PUT(skb, TCA_RSVP_CLASSID, 4, &f->res.classid); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 97c1c75..05e6e0a 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -770,6 +770,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); tcm = NLMSG_DATA(nlh); tcm->tcm_family = AF_UNSPEC; + tcm->tcm__pad1 = 0; + tcm->tcm__pad2 = 0; tcm->tcm_ifindex = q->dev->ifindex; tcm->tcm_parent = clid; tcm->tcm_handle = q->handle; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index d43e3b8..09453f9 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1528,6 +1528,7 @@ static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl) opt.strategy = cl->ovl_strategy; opt.priority2 = cl->priority2+1; + opt.pad = 0; opt.penalty = (cl->penalty*1000)/HZ; RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt); return skb->len; @@ -1563,6 +1564,8 @@ static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl) if (cl->police) { opt.police = cl->police; + opt.__res1 = 0; + opt.__res2 = 0; RTA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt); } return skb->len; diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 2ec0320..c44bf41 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -102,9 +102,9 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, /* Set up the base timeout information. */ ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = - SCTP_DEFAULT_TIMEOUT_T1_COOKIE; + msecs_to_jiffies(sp->rtoinfo.srto_initial); ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = - SCTP_DEFAULT_TIMEOUT_T1_INIT; + msecs_to_jiffies(sp->rtoinfo.srto_initial); ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = msecs_to_jiffies(sp->rtoinfo.srto_initial); ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; @@ -117,12 +117,9 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD] = 5 * msecs_to_jiffies(sp->rtoinfo.srto_max); - ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = - SCTP_DEFAULT_TIMEOUT_HEARTBEAT; - ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = - SCTP_DEFAULT_TIMEOUT_SACK; - ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = - sp->autoclose * HZ; + ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; + ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = sctp_sack_timeout; + ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ; /* Use SCTP specific send buffer space queues. */ ep->sndbuf_policy = sctp_sndbuf_policy; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 5135e1a..e7f37fa 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1050,7 +1050,10 @@ SCTP_STATIC __init int sctp_init(void) sctp_sndbuf_policy = 0; /* HB.interval - 30 seconds */ - sctp_hb_interval = 30 * HZ; + sctp_hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; + + /* delayed SACK timeout */ + sctp_sack_timeout = SCTP_DEFAULT_TIMEOUT_SACK; /* Implementation specific variables. */ diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 7fc3184..dc48934 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -47,6 +47,8 @@ static ctl_handler sctp_sysctl_jiffies_ms; static long rto_timer_min = 1; static long rto_timer_max = 86400000; /* One day */ +static long sack_timer_min = 1; +static long sack_timer_max = 500; static ctl_table sctp_table[] = { { @@ -187,6 +189,17 @@ static ctl_table sctp_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_SCTP_SACK_TIMEOUT, + .procname = "sack_timeout", + .data = &sctp_sack_timeout, + .maxlen = sizeof(long), + .mode = 0644, + .proc_handler = &proc_doulongvec_ms_jiffies_minmax, + .strategy = &sctp_sysctl_jiffies_ms, + .extra1 = &sack_timer_min, + .extra2 = &sack_timer_max, + }, { .ctl_name = 0 } }; diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 0ec0fde..a63b691 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -103,7 +103,6 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, /* Set up the heartbeat timer. */ init_timer(&peer->hb_timer); - peer->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; peer->hb_timer.function = sctp_generate_heartbeat_event; peer->hb_timer.data = (unsigned long)peer; |