From: Planet-Lab Support Date: Mon, 8 Aug 2005 21:03:49 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch 'vserver'. X-Git-Tag: vserver-2_6_11_7-vs2_0-pre4~2 X-Git-Url: http://git.onelab.eu/?p=linux-2.6.git;a=commitdiff_plain;h=27c597220375df29763c4fecc5130a5d0054261e This commit was manufactured by cvs2svn to create branch 'vserver'. --- diff --git a/Documentation/DocBook/stylesheet.xsl b/Documentation/DocBook/stylesheet.xsl new file mode 100644 index 000000000..e14c21dda --- /dev/null +++ b/Documentation/DocBook/stylesheet.xsl @@ -0,0 +1,5 @@ + + +1 +ansi + diff --git a/Documentation/aoe/udev-install.sh b/Documentation/aoe/udev-install.sh new file mode 100644 index 000000000..6449911c6 --- /dev/null +++ b/Documentation/aoe/udev-install.sh @@ -0,0 +1,30 @@ +# install the aoe-specific udev rules from udev.txt into +# the system's udev configuration +# + +me="`basename $0`" + +# find udev.conf, often /etc/udev/udev.conf +# (or environment can specify where to find udev.conf) +# +if test -z "$conf"; then + if test -r /etc/udev/udev.conf; then + conf=/etc/udev/udev.conf + else + conf="`find /etc -type f -name udev.conf 2> /dev/null`" + if test -z "$conf" || test ! -r "$conf"; then + echo "$me Error: no udev.conf found" 1>&2 + exit 1 + fi + fi +fi + +# find the directory where udev rules are stored, often +# /etc/udev/rules.d +# +rules_d="`sed -n '/^udev_rules=/{ s!udev_rules=!!; s!\"!!g; p; }' $conf`" +if test -z "$rules_d" || test ! -d "$rules_d"; then + echo "$me Error: cannot find udev rules directory" 1>&2 + exit 1 +fi +sh -xc "cp `dirname $0`/udev.txt $rules_d/60-aoe.rules" diff --git a/Documentation/arm/Samsung-S3C24XX/H1940.txt b/Documentation/arm/Samsung-S3C24XX/H1940.txt new file mode 100644 index 000000000..d6b1de92b --- /dev/null +++ b/Documentation/arm/Samsung-S3C24XX/H1940.txt @@ -0,0 +1,40 @@ + HP IPAQ H1940 + ============= + +http://www.handhelds.org/projects/h1940.html + +Introduction +------------ + + The HP H1940 is a S3C2410 based handheld device, with + bluetooth connectivity. + + +Support +------- + + A variety of information is available + + handhelds.org project page: + + http://www.handhelds.org/projects/h1940.html + + handhelds.org wiki page: + + http://handhelds.org/moin/moin.cgi/HpIpaqH1940 + + Herbert Pötzl pages: + + http://vserver.13thfloor.at/H1940/ + + +Maintainers +----------- + + This project is being maintained and developed by a variety + of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl. + + Thanks to the many others who have also provided support. + + +(c) 2005 Ben Dooks \ No newline at end of file diff --git a/Documentation/arm/Samsung-S3C24XX/SMDK2440.txt b/Documentation/arm/Samsung-S3C24XX/SMDK2440.txt new file mode 100644 index 000000000..32e1eae6a --- /dev/null +++ b/Documentation/arm/Samsung-S3C24XX/SMDK2440.txt @@ -0,0 +1,56 @@ + Samsung/Meritech SMDK2440 + ========================= + +Introduction +------------ + + The SMDK2440 is a two part evaluation board for the Samsung S3C2440 + processor. It includes support for LCD, SmartMedia, Audio, SD and + 10MBit Ethernet, and expansion headers for various signals, including + the camera and unused GPIO. + + +Configuration +------------- + + To set the default configuration, use `make smdk2440_defconfig` which + will configure the common features of this board, or use + `make s3c2410_config` to include support for all s3c2410/s3c2440 machines + + +Support +------- + + Ben Dooks' SMDK2440 site at http://www.fluff.org/ben/smdk2440/ which + includes linux based USB download tools. + + Some of the h1940 patches that can be found from the H1940 project + site at http://www.handhelds.org/projects/h1940.html can also be + applied to this board. + + +Peripherals +----------- + + There is no current support for any of the extra peripherals on the + base-board itself. + + +MTD +--- + + The NAND flash should be supported by the in kernel MTD NAND support, + NOR flash will be added later. + + +Maintainers +----------- + + This board is being maintained by Ben Dooks, for more info, see + http://www.fluff.org/ben/smdk2440/ + + Many thanks to Dimitry Andric of TomTom for the loan of the SMDK2440, + and to Simtec Electronics for allowing me time to work on this. + + +(c) 2004 Ben Dooks \ No newline at end of file diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop new file mode 100644 index 000000000..a50c70f9c --- /dev/null +++ b/Documentation/dvb/README.flexcop @@ -0,0 +1,205 @@ +This README escorted the skystar2-driver rewriting procedure. It describes the +state of the new flexcop-driver set and some internals are written down here +too. + +This document hopefully describes things about the flexcop and its +device-offsprings. Goal was to write an easy-to-write and easy-to-read set of +drivers based on the skystar2.c and other information. + +Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been +touched and rewritten. + +History & News +============== + 2005-04-01 - correct USB ISOC transfers (thanks to Vadim Catana) + + + + +General coding processing +========================= + +We should proceed as follows (as long as no one complains): + +0) Think before start writing code! + +1) rewriting the skystar2.c with the help of the flexcop register descriptions +and splitting up the files to a pci-bus-part and a flexcop-part. +The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the +device-specific part and b2c2-flexcop.ko for the common flexcop-functions. + +2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c +and other pci drivers) + +3) make some beautification (see 'Improvements when rewriting (refactoring) is +done') + +4) Testing the new driver and maybe substitute the skystar2.c with it, to reach +a wider tester audience. + +5) creating an usb-bus-part using the already written flexcop code for the pci +card. + +Idea: create a kernel-object for the flexcop and export all important +functions. This option saves kernel-memory, but maybe a lot of functions have +to be exported to kernel namespace. + + +Current situation +================= + +0) Done :) +1) Done (some minor issues left) +2) Done +3) Not ready yet, more information is necessary +4) next to be done (see the table below) +5) USB driver is working (yes, there are some minor issues) + +What seems to be ready? +----------------------- + +1) Rewriting +1a) i2c is cut off from the flexcop-pci.c and seems to work +1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c +1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c +1e) eeprom (reading MAC address) +1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me)) +1f) misc. register accesses for reading parameters (e.g. resetting, revision) +1g) pid/mac filter (flexcop-hw-filter.c) +1i) dvb-stuff initialization in flexcop.c (done) +1h) dma stuff (now just using the size-irq, instead of all-together, to be done) +1j) remove flexcop initialization from flexcop-pci.c completely (done) +1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO') +1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from +non-static where possible, moved code to proper places) + +2) Search for errors in the leftover of flexcop-pci.c (partially done) +5a) add MAC address reading +5c) feeding of ISOC data to the software demux (format of the isochronous data +and speed optimization, no real error) (thanks to Vadim Catana) + +What to do in the near future? +-------------------------------------- +(no special order here) + +5) USB driver +5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting) + +Testing changes +--------------- + +O = item is working +P = item is partially working +X = item is not working +N = item does not apply here + = item need to be examined + + | PCI | USB +item | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312 +-------+-------+---------+---------+-------+-------+---------+---------+------- +1a) | O | | | | N | N | N | N +1b) | O | | | | | | O | +1c) | N | N | | | N | N | O | +1d) | O | O +1e) | O | O +1f) | P +1g) | O +1h) | P | +1i) | O | N +1j) | O | N +1l) | O | N +2) | O | N +5a) | N | O +5b)* | N | +5c) | N | O + +* - not done yet + +Known bugs and problems and TODO +-------------------------------- + +1g/h/l) when pid filtering is enabled on the pci card + +DMA usage currently: + The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first + address and triggers an IRQ when it's full and starts writing to the second + address. When the second address is full, the IRQ is triggered again, and + the flexcop writes to first address again, and so on. + The buffersize of each address is currently 640*188 bytes. + + Problem is, when using hw-pid-filtering and doing some low-bandwidth + operation (like scanning) the buffers won't be filled enough to trigger + the IRQ. That's why: + + When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ + is triggered. Is the current write address of DMA1 different to the one + during the last IRQ, then the data is passed to the demuxer. + + There is an additional DMA-IRQ-method: packet count IRQ. This isn't + implemented correctly yet. + + The solution is to disable HW PID filtering, but I don't know how the DVB + API software demux behaves on slow systems with 45MBit/s TS. + +Solved bugs :) +-------------- +1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't +working) +SOLUTION: also index 0 was affected, because net_translation is done for +these indexes by default + +5b) isochronous transfer does only work in the first attempt (for the Sky2PC +USB, Air2PC is working) SOLUTION: the flexcop was going asleep and never really +woke up again (don't know if this need fixes, see +flexcop-fe-tuner.c:flexcop_sleep) + +NEWS: when the driver is loaded and unloaded and loaded again (w/o doing +anything in the while the driver is loaded the first time), no transfers take +place anymore. + +Improvements when rewriting (refactoring) is done +================================================= + +- split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control + (enable sleeping for other demods than dvb-s) +- add support for CableStar (stv0297 Microtune 203x/ALPS) (almost done, incompatibilities with the Nexus-CA) + +Debugging +--------- +- add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it + with this flexcop, this is important, because i2c is now using the + flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for + that, please tell us so). + +Everything which is identical in the following table, can be put into a common +flexcop-module. + + PCI USB +------------------------------------------------------------------------------- +Different: +Register access: accessing IO memory USB control message +I2C bus: I2C bus of the FC USB control message +Data transfer: DMA isochronous transfer +EEPROM transfer: through i2c bus not clear yet + +Identical: +Streaming: accessing registers +PID Filtering: accessing registers +Sram destinations: accessing registers +Tuner/Demod: I2C bus +DVB-stuff: can be written for common use + +Acknowledgements (just for the rewriting part) +================ + +Bjarne Steinsbo thought a lot in the first place of the pci part for this code +sharing idea. + +Andreas Oberritter for providing a recent PCI initialization template +(pluto2.c). + +Boleslaw Ciesielski for pointing out a problem with firmware loader. + +Vadim Catana for correcting the USB transfer. + +comments, critics and ideas to linux-dvb@linuxtv.org. diff --git a/Documentation/i2c/busses/i2c-ali1535 b/Documentation/i2c/busses/i2c-ali1535 new file mode 100644 index 000000000..0db3b4c74 --- /dev/null +++ b/Documentation/i2c/busses/i2c-ali1535 @@ -0,0 +1,42 @@ +Kernel driver i2c-ali1535 + +Supported adapters: + * Acer Labs, Inc. ALI 1535 (south bridge) + Datasheet: Now under NDA + http://www.ali.com.tw/eng/support/datasheet_request.php + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Mark D. Studebaker , + Dan Eaton , + Stephen Rousset + +Description +----------- + +This is the driver for the SMB Host controller on Acer Labs Inc. (ALI) +M1535 South Bridge. + +The M1535 is a South bridge for portable systems. It is very similar to the +M15x3 South bridges also produced by Acer Labs Inc. Some of the registers +within the part have moved and some have been redefined slightly. +Additionally, the sequencing of the SMBus transactions has been modified to +be more consistent with the sequencing recommended by the manufacturer and +observed through testing. These changes are reflected in this driver and +can be identified by comparing this driver to the i2c-ali15x3 driver. For +an overview of these chips see http://www.acerlabs.com + +The SMB controller is part of the M7101 device, which is an ACPI-compliant +Power Management Unit (PMU). + +The whole M7101 device has to be enabled for the SMB to work. You can't +just enable the SMB alone. The SMB and the ACPI have separate I/O spaces. +We make sure that the SMB is enabled. We leave the ACPI alone. + + +Features +-------- + +This driver controls the SMB Host only. This driver does not use +interrupts. diff --git a/Documentation/i2c/busses/i2c-ali1563 b/Documentation/i2c/busses/i2c-ali1563 new file mode 100644 index 000000000..99ad4b9bc --- /dev/null +++ b/Documentation/i2c/busses/i2c-ali1563 @@ -0,0 +1,27 @@ +Kernel driver i2c-ali1563 + +Supported adapters: + * Acer Labs, Inc. ALI 1563 (south bridge) + Datasheet: Now under NDA + http://www.ali.com.tw/eng/support/datasheet_request.php + +Author: Patrick Mochel + +Description +----------- + +This is the driver for the SMB Host controller on Acer Labs Inc. (ALI) +M1563 South Bridge. + +For an overview of these chips see http://www.acerlabs.com + +The M1563 southbridge is deceptively similar to the M1533, with a few +notable exceptions. One of those happens to be the fact they upgraded the +i2c core to be SMBus 2.0 compliant, and happens to be almost identical to +the i2c controller found in the Intel 801 south bridges. + +Features +-------- + +This driver controls the SMB Host only. This driver does not use +interrupts. diff --git a/Documentation/i2c/busses/i2c-ali15x3 b/Documentation/i2c/busses/i2c-ali15x3 new file mode 100644 index 000000000..ff28d381b --- /dev/null +++ b/Documentation/i2c/busses/i2c-ali15x3 @@ -0,0 +1,112 @@ +Kernel driver i2c-ali15x3 + +Supported adapters: + * Acer Labs, Inc. ALI 1533 and 1543C (south bridge) + Datasheet: Now under NDA + http://www.ali.com.tw/eng/support/datasheet_request.php + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Mark D. Studebaker + +Module Parameters +----------------- + +* force_addr: int + Initialize the base address of the i2c controller + + +Notes +----- + +The force_addr parameter is useful for boards that don't set the address in +the BIOS. Does not do a PCI force; the device must still be present in +lspci. Don't use this unless the driver complains that the base address is +not set. + +Example: 'modprobe i2c-ali15x3 force_addr=0xe800' + +SMBus periodically hangs on ASUS P5A motherboards and can only be cleared +by a power cycle. Cause unknown (see Issues below). + + +Description +----------- + +This is the driver for the SMB Host controller on Acer Labs Inc. (ALI) +M1541 and M1543C South Bridges. + +The M1543C is a South bridge for desktop systems. +The M1541 is a South bridge for portable systems. +They are part of the following ALI chipsets: + + * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and + 100MHz CPU Front Side bus + * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz + CPU Front Side bus + Some Aladdin V motherboards: + Asus P5A + Atrend ATC-5220 + BCM/GVC VP1541 + Biostar M5ALA + Gigabyte GA-5AX (** Generally doesn't work because the BIOS doesn't + enable the 7101 device! **) + Iwill XA100 Plus + Micronics C200 + Microstar (MSI) MS-5169 + + * "Aladdin IV" includes the M1541 Socket 7 North bridge + with host bus up to 83.3 MHz. + +For an overview of these chips see http://www.acerlabs.com. At this time the +full data sheets on the web site are password protected, however if you +contact the ALI office in San Jose they may give you the password. + +The M1533/M1543C devices appear as FOUR separate devices on the PCI bus. An +output of lspci will show something similar to the following: + + 00:02.0 USB Controller: Acer Laboratories Inc. M5237 (rev 03) + 00:03.0 Bridge: Acer Laboratories Inc. M7101 <= THIS IS THE ONE WE NEED + 00:07.0 ISA bridge: Acer Laboratories Inc. M1533 (rev c3) + 00:0f.0 IDE interface: Acer Laboratories Inc. M5229 (rev c1) + +** IMPORTANT ** +** If you have a M1533 or M1543C on the board and you get +** "ali15x3: Error: Can't detect ali15x3!" +** then run lspci. +** If you see the 1533 and 5229 devices but NOT the 7101 device, +** then you must enable ACPI, the PMU, SMB, or something similar +** in the BIOS. +** The driver won't work if it can't find the M7101 device. + +The SMB controller is part of the M7101 device, which is an ACPI-compliant +Power Management Unit (PMU). + +The whole M7101 device has to be enabled for the SMB to work. You can't +just enable the SMB alone. The SMB and the ACPI have separate I/O spaces. +We make sure that the SMB is enabled. We leave the ACPI alone. + +Features +-------- + +This driver controls the SMB Host only. The SMB Slave +controller on the M15X3 is not enabled. This driver does not use +interrupts. + + +Issues +------ + +This driver requests the I/O space for only the SMB +registers. It doesn't use the ACPI region. + +On the ASUS P5A motherboard, there are several reports that +the SMBus will hang and this can only be resolved by +powering off the computer. It appears to be worse when the board +gets hot, for example under heavy CPU load, or in the summer. +There may be electrical problems on this board. +On the P5A, the W83781D sensor chip is on both the ISA and +SMBus. Therefore the SMBus hangs can generally be avoided +by accessing the W83781D on the ISA bus only. + diff --git a/Documentation/i2c/busses/i2c-amd756 b/Documentation/i2c/busses/i2c-amd756 new file mode 100644 index 000000000..67f30874d --- /dev/null +++ b/Documentation/i2c/busses/i2c-amd756 @@ -0,0 +1,25 @@ +Kernel driver i2c-amd756 + +Supported adapters: + * AMD 756 + * AMD 766 + * AMD 768 + * AMD 8111 + Datasheets: Publicly available on AMD website + + * nVidia nForce + Datasheet: Unavailable + +Authors: + Frodo Looijaard , + Philip Edelbrock + +Description +----------- + +This driver supports the AMD 756, 766, 768 and 8111 Peripheral Bus +Controllers, and the nVidia nForce. + +Note that for the 8111, there are two SMBus adapters. The SMBus 1.0 adapter +is supported by this driver, and the SMBus 2.0 adapter is supported by the +i2c-amd8111 driver. diff --git a/Documentation/i2c/busses/i2c-i810 b/Documentation/i2c/busses/i2c-i810 new file mode 100644 index 000000000..0544eb332 --- /dev/null +++ b/Documentation/i2c/busses/i2c-i810 @@ -0,0 +1,46 @@ +Kernel driver i2c-i810 + +Supported adapters: + * Intel 82810, 82810-DC100, 82810E, and 82815 (GMCH) + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Kyösti Mälkki , + Ralph Metzler , + Mark D. Studebaker + +Main contact: Mark Studebaker + +Description +----------- + +WARNING: If you have an '810' or '815' motherboard, your standard I2C +temperature sensors are most likely on the 801's I2C bus. You want the +i2c-i801 driver for those, not this driver. + +Now for the i2c-i810... + +The GMCH chip contains two I2C interfaces. + +The first interface is used for DDC (Data Display Channel) which is a +serial channel through the VGA monitor connector to a DDC-compliant +monitor. This interface is defined by the Video Electronics Standards +Association (VESA). The standards are available for purchase at +http://www.vesa.org . + +The second interface is a general-purpose I2C bus. It may be connected to a +TV-out chip such as the BT869 or possibly to a digital flat-panel display. + +Features +-------- + +Both busses use the i2c-algo-bit driver for 'bit banging' +and support for specific transactions is provided by i2c-algo-bit. + +Issues +------ + +If you enable bus testing in i2c-algo-bit (insmod i2c-algo-bit bit_test=1), +the test may fail; if so, the i2c-i810 driver won't be inserted. However, +we think this has been fixed. diff --git a/Documentation/i2c/busses/i2c-parport-light b/Documentation/i2c/busses/i2c-parport-light new file mode 100644 index 000000000..287436478 --- /dev/null +++ b/Documentation/i2c/busses/i2c-parport-light @@ -0,0 +1,11 @@ +Kernel driver i2c-parport-light + +Author: Jean Delvare + +This driver is a light version of i2c-parport. It doesn't depend +on the parport driver, and uses direct I/O access instead. This might be +prefered on embedded systems where wasting memory for the clean but heavy +parport handling is not an option. The drawback is a reduced portability +and the impossibility to daisy-chain other parallel port devices. + +Please see i2c-parport for documentation. diff --git a/Documentation/i2c/busses/i2c-pca-isa b/Documentation/i2c/busses/i2c-pca-isa new file mode 100644 index 000000000..6fc8f4c27 --- /dev/null +++ b/Documentation/i2c/busses/i2c-pca-isa @@ -0,0 +1,23 @@ +Kernel driver i2c-pca-isa + +Supported adapters: +This driver supports ISA boards using the Philips PCA 9564 +Parallel bus to I2C bus controller + +Author: Ian Campbell , Arcom Control Systems + +Module Parameters +----------------- + +* base int + I/O base address +* irq int + IRQ interrupt +* clock int + Clock rate as described in table 1 of PCA9564 datasheet + +Description +----------- + +This driver supports ISA boards using the Philips PCA 9564 +Parallel bus to I2C bus controller diff --git a/Documentation/i2c/busses/i2c-prosavage b/Documentation/i2c/busses/i2c-prosavage new file mode 100644 index 000000000..703687902 --- /dev/null +++ b/Documentation/i2c/busses/i2c-prosavage @@ -0,0 +1,23 @@ +Kernel driver i2c-prosavage + +Supported adapters: + + S3/VIA KM266/VT8375 aka ProSavage8 + S3/VIA KM133/VT8365 aka Savage4 + +Author: Henk Vergonet + +Description +----------- + +The Savage4 chips contain two I2C interfaces (aka a I2C 'master' or +'host'). + +The first interface is used for DDC (Data Display Channel) which is a +serial channel through the VGA monitor connector to a DDC-compliant +monitor. This interface is defined by the Video Electronics Standards +Association (VESA). The standards are available for purchase at +http://www.vesa.org . The second interface is a general-purpose I2C bus. + +Usefull for gaining access to the TV Encoder chips. + diff --git a/Documentation/i2c/busses/i2c-savage4 b/Documentation/i2c/busses/i2c-savage4 new file mode 100644 index 000000000..6ecceab61 --- /dev/null +++ b/Documentation/i2c/busses/i2c-savage4 @@ -0,0 +1,26 @@ +Kernel driver i2c-savage4 + +Supported adapters: + * Savage4 + * Savage2000 + +Authors: + Alexander Wold , + Mark D. Studebaker + +Description +----------- + +The Savage4 chips contain two I2C interfaces (aka a I2C 'master' +or 'host'). + +The first interface is used for DDC (Data Display Channel) which is a +serial channel through the VGA monitor connector to a DDC-compliant +monitor. This interface is defined by the Video Electronics Standards +Association (VESA). The standards are available for purchase at +http://www.vesa.org . The DDC bus is not yet supported because its register +is not directly memory-mapped. + +The second interface is a general-purpose I2C bus. This is the only +interface supported by the driver at the moment. + diff --git a/Documentation/i2c/busses/i2c-sis5595 b/Documentation/i2c/busses/i2c-sis5595 new file mode 100644 index 000000000..cc47db7d0 --- /dev/null +++ b/Documentation/i2c/busses/i2c-sis5595 @@ -0,0 +1,59 @@ +Kernel driver i2c-sis5595 + +Authors: + Frodo Looijaard , + Mark D. Studebaker , + Philip Edelbrock + +Supported adapters: + * Silicon Integrated Systems Corp. SiS5595 Southbridge + Datasheet: Publicly available at the Silicon Integrated Systems Corp. site. + +Note: all have mfr. ID 0x1039. + + SUPPORTED PCI ID + 5595 0008 + + Note: these chips contain a 0008 device which is incompatible with the + 5595. We recognize these by the presence of the listed + "blacklist" PCI ID and refuse to load. + + NOT SUPPORTED PCI ID BLACKLIST PCI ID + 540 0008 0540 + 550 0008 0550 + 5513 0008 5511 + 5581 0008 5597 + 5582 0008 5597 + 5597 0008 5597 + 5598 0008 5597/5598 + 630 0008 0630 + 645 0008 0645 + 646 0008 0646 + 648 0008 0648 + 650 0008 0650 + 651 0008 0651 + 730 0008 0730 + 735 0008 0735 + 745 0008 0745 + 746 0008 0746 + +Module Parameters +----------------- + +* force_addr=0xaddr Set the I/O base address. Useful for boards + that don't set the address in the BIOS. Does not do a + PCI force; the device must still be present in lspci. + Don't use this unless the driver complains that the + base address is not set. + +Description +----------- + +i2c-sis5595 is a true SMBus host driver for motherboards with the SiS5595 +southbridges. + +WARNING: If you are trying to access the integrated sensors on the SiS5595 +chip, you want the sis5595 driver for those, not this driver. This driver +is a BUS driver, not a CHIP driver. A BUS driver is used by other CHIP +drivers to access chips on the bus. + diff --git a/Documentation/i2c/busses/i2c-sis630 b/Documentation/i2c/busses/i2c-sis630 new file mode 100644 index 000000000..9aca6889f --- /dev/null +++ b/Documentation/i2c/busses/i2c-sis630 @@ -0,0 +1,49 @@ +Kernel driver i2c-sis630 + +Supported adapters: + * Silicon Integrated Systems Corp (SiS) + 630 chipset (Datasheet: available at http://amalysh.bei.t-online.de/docs/SIS/) + 730 chipset + * Possible other SiS chipsets ? + +Author: Alexander Malysh + +Module Parameters +----------------- + +* force = [1|0] Forcibly enable the SIS630. DANGEROUS! + This can be interesting for chipsets not named + above to check if it works for you chipset, but DANGEROUS! + +* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default, + what your BIOS use). DANGEROUS! This should be a bit + faster, but freeze some systems (i.e. my Laptop). + + +Description +----------- + +This SMBus only driver is known to work on motherboards with the above +named chipsets. + +If you see something like this: + +00:00.0 Host bridge: Silicon Integrated Systems [SiS] 630 Host (rev 31) +00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 + +or like this: + +00:00.0 Host bridge: Silicon Integrated Systems [SiS] 730 Host (rev 02) +00:01.0 ISA bridge: Silicon Integrated Systems [SiS] 85C503/5513 + +in your 'lspci' output , then this driver is for your chipset. + +Thank You +--------- +Philip Edelbrock +- testing SiS730 support +Mark M. Hoffman +- bug fixes + +To anyone else which I forgot here ;), thanks! + diff --git a/Documentation/i2c/busses/i2c-via b/Documentation/i2c/busses/i2c-via new file mode 100644 index 000000000..55edfe1a6 --- /dev/null +++ b/Documentation/i2c/busses/i2c-via @@ -0,0 +1,34 @@ +Kernel driver i2c-via + +Supported adapters: + * VIA Technologies, InC. VT82C586B + Datasheet: Publicly available at the VIA website + +Author: Kyösti Mälkki + +Description +----------- + +i2c-via is an i2c bus driver for motherboards with VIA chipset. + +The following VIA pci chipsets are supported: + - MVP3, VP3, VP2/97, VPX/97 + - others with South bridge VT82C586B + +Your lspci listing must show this : + + Bridge: VIA Technologies, Inc. VT82C586B ACPI (rev 10) + + Problems? + + Q: You have VT82C586B on the motherboard, but not in the listing. + + A: Go to your BIOS setup, section PCI devices or similar. + Turn USB support on, and try again. + + Q: No error messages, but still i2c doesn't seem to work. + + A: This can happen. This driver uses the pins VIA recommends in their + datasheets, but there are several ways the motherboard manufacturer + can actually wire the lines. + diff --git a/Documentation/i2c/busses/i2c-voodoo3 b/Documentation/i2c/busses/i2c-voodoo3 new file mode 100644 index 000000000..62d90a454 --- /dev/null +++ b/Documentation/i2c/busses/i2c-voodoo3 @@ -0,0 +1,62 @@ +Kernel driver i2c-voodoo3 + +Supported adapters: + * 3dfx Voodoo3 based cards + * Voodoo Banshee based cards + +Authors: + Frodo Looijaard , + Philip Edelbrock , + Ralph Metzler , + Mark D. Studebaker + +Main contact: Philip Edelbrock + +The code is based upon Ralph's test code (he did the hard stuff ;') + +Description +----------- + +The 3dfx Voodoo3 chip contains two I2C interfaces (aka a I2C 'master' or +'host'). + +The first interface is used for DDC (Data Display Channel) which is a +serial channel through the VGA monitor connector to a DDC-compliant +monitor. This interface is defined by the Video Electronics Standards +Association (VESA). The standards are available for purchase at +http://www.vesa.org . + +The second interface is a general-purpose I2C bus. The intent by 3dfx was +to allow manufacturers to add extra chips to the video card such as a +TV-out chip such as the BT869 or possibly even I2C based temperature +sensors like the ADM1021 or LM75. + +Stability +--------- + +Seems to be stable on the test machine, but needs more testing on other +machines. Simultaneous accesses of the DDC and I2C busses may cause errors. + +Supported Devices +----------------- + +Specifically, this driver was written and tested on the '3dfx Voodoo3 AGP +3000' which has a tv-out feature (s-video or composite). According to the +docs and discussions, this code should work for any Voodoo3 based cards as +well as Voodoo Banshee based cards. The DDC interface has been tested on a +Voodoo Banshee card. + +Issues +------ + +Probably many, but it seems to work OK on my system. :') + + +External Device Connection +-------------------------- + +The digital video input jumpers give availability to the I2C bus. +Specifically, pins 13 and 25 (bottom row middle, and bottom right-end) are +the I2C clock and I2C data lines, respectively. +5V and GND are probably +also easily available making the addition of extra I2C/SMBus devices easy +to implement. diff --git a/Documentation/kref.txt b/Documentation/kref.txt new file mode 100644 index 000000000..42fe28445 --- /dev/null +++ b/Documentation/kref.txt @@ -0,0 +1,216 @@ + +krefs allow you to add reference counters to your objects. If you +have objects that are used in multiple places and passed around, and +you don't have refcounts, your code is almost certainly broken. If +you want refcounts, krefs are the way to go. + +To use a kref, add one to your data structures like: + +struct my_data +{ + . + . + struct kref refcount; + . + . +}; + +The kref can occur anywhere within the data structure. + +You must initialize the kref after you allocate it. To do this, call +kref_init as so: + + struct my_data *data; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + kref_init(&data->refcount); + +This sets the refcount in the kref to 1. + +Once you have an initialized kref, you must follow the following +rules: + +1) If you make a non-temporary copy of a pointer, especially if + it can be passed to another thread of execution, you must + increment the refcount with kref_get() before passing it off: + kref_get(&data->refcount); + If you already have a valid pointer to a kref-ed structure (the + refcount cannot go to zero) you may do this without a lock. + +2) When you are done with a pointer, you must call kref_put(): + kref_put(&data->refcount, data_release); + If this is the last reference to the pointer, the release + routine will be called. If the code never tries to get + a valid pointer to a kref-ed structure without already + holding a valid pointer, it is safe to do this without + a lock. + +3) If the code attempts to gain a reference to a kref-ed structure + without already holding a valid pointer, it must serialize access + where a kref_put() cannot occur during the kref_get(), and the + structure must remain valid during the kref_get(). + +For example, if you allocate some data and then pass it to another +thread to process: + +void data_release(struct kref *ref) +{ + struct my_data *data = container_of(ref, struct my_data, refcount); + kfree(data); +} + +void more_data_handling(void *cb_data) +{ + struct my_data *data = cb_data; + . + . do stuff with data here + . + kref_put(data, data_release); +} + +int my_data_handler(void) +{ + int rv = 0; + struct my_data *data; + struct task_struct *task; + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + kref_init(&data->refcount); + + kref_get(&data->refcount); + task = kthread_run(more_data_handling, data, "more_data_handling"); + if (task == ERR_PTR(-ENOMEM)) { + rv = -ENOMEM; + kref_put(&data->refcount, data_release); + goto out; + } + + . + . do stuff with data here + . + out: + kref_put(&data->refcount, data_release); + return rv; +} + +This way, it doesn't matter what order the two threads handle the +data, the kref_put() handles knowing when the data is not referenced +any more and releasing it. The kref_get() does not require a lock, +since we already have a valid pointer that we own a refcount for. The +put needs no lock because nothing tries to get the data without +already holding a pointer. + +Note that the "before" in rule 1 is very important. You should never +do something like: + + task = kthread_run(more_data_handling, data, "more_data_handling"); + if (task == ERR_PTR(-ENOMEM)) { + rv = -ENOMEM; + goto out; + } else + /* BAD BAD BAD - get is after the handoff */ + kref_get(&data->refcount); + +Don't assume you know what you are doing and use the above construct. +First of all, you may not know what you are doing. Second, you may +know what you are doing (there are some situations where locking is +involved where the above may be legal) but someone else who doesn't +know what they are doing may change the code or copy the code. It's +bad style. Don't do it. + +There are some situations where you can optimize the gets and puts. +For instance, if you are done with an object and enqueuing it for +something else or passing it off to something else, there is no reason +to do a get then a put: + + /* Silly extra get and put */ + kref_get(&obj->ref); + enqueue(obj); + kref_put(&obj->ref, obj_cleanup); + +Just do the enqueue. A comment about this is always welcome: + + enqueue(obj); + /* We are done with obj, so we pass our refcount off + to the queue. DON'T TOUCH obj AFTER HERE! */ + +The last rule (rule 3) is the nastiest one to handle. Say, for +instance, you have a list of items that are each kref-ed, and you wish +to get the first one. You can't just pull the first item off the list +and kref_get() it. That violates rule 3 because you are not already +holding a valid pointer. You must add locks or semaphores. For +instance: + +static DECLARE_MUTEX(sem); +static LIST_HEAD(q); +struct my_data +{ + struct kref refcount; + struct list_head link; +}; + +static struct my_data *get_entry() +{ + struct my_data *entry = NULL; + down(&sem); + if (!list_empty(&q)) { + entry = container_of(q.next, struct my_q_entry, link); + kref_get(&entry->refcount); + } + up(&sem); + return entry; +} + +static void release_entry(struct kref *ref) +{ + struct my_data *entry = container_of(ref, struct my_data, refcount); + + list_del(&entry->link); + kfree(entry); +} + +static void put_entry(struct my_data *entry) +{ + down(&sem); + kref_put(&entry->refcount, release_entry); + up(&sem); +} + +The kref_put() return value is useful if you do not want to hold the +lock during the whole release operation. Say you didn't want to call +kfree() with the lock held in the example above (since it is kind of +pointless to do so). You could use kref_put() as follows: + +static void release_entry(struct kref *ref) +{ + /* All work is done after the return from kref_put(). */ +} + +static void put_entry(struct my_data *entry) +{ + down(&sem); + if (kref_put(&entry->refcount, release_entry)) { + list_del(&entry->link); + up(&sem); + kfree(entry); + } else + up(&sem); +} + +This is really more useful if you have to call other routines as part +of the free operations that could take a long time or might claim the +same lock. Note that doing everything in the release routine is still +preferred as it is a little neater. + + +Corey Minyard + +A lot of this was lifted from Greg Kroah-Hartman's 2004 OLS paper and +presentation on krefs, which can be found at: + http://www.kroah.com/linux/talks/ols_2004_kref_paper/Reprint-Kroah-Hartman-OLS2004.pdf +and: + http://www.kroah.com/linux/talks/ols_2004_kref_talk/ + diff --git a/Documentation/scsi/ChangeLog.lpfc b/Documentation/scsi/ChangeLog.lpfc new file mode 100644 index 000000000..ae3f962a7 --- /dev/null +++ b/Documentation/scsi/ChangeLog.lpfc @@ -0,0 +1,1865 @@ +Known issues : + * Please read the associated RELEASE-NOTES file !!! + * This source release intended for upstream kernel releases only! + +Changes from 20050323 to 20050413 + + * Changed version number to 8.0.28 + * Fixed build warning for 2.6.12-rc2 kernels: mempool_alloc now + requires a function which takes an unsigned int for gfp_flags. + * Removed pci dma sync calls to coherent/consistent pci memory. + * Merged patch from Christoph Hellwig : split helpers + for fabric and nport logins out of lpfc_cmpl_els_flogi. + * Removed sysfs attributes that are used to dump the various + discovery lists. + * Fix for issue where not all luns are seen. Search all lists + other than unmap list in lpfc_find_target(). Otherwise INQUIRY + to luns on nodes in NPR or other relevant states (PLOGI, + PRLI...) are errored back and scan() terminates. + * Removed FC_TRANSPORT_PATCHESxxx defines. They're in 2.6.12-rc1. + * Compare return value of lpfc_scsi_tgt_reset against SCSI + midlayer codes SUCCESS/FAILED which that function returns rather + than SLI return code. + * Removed extraneous calls to lpfc_sli_next_iotag which should + only be called from lpfc_sli_submit_iocb. Also make + lpfc_sli_next_iotag static. + * Added PCI ID for LP10000-S. + * Changes in lpfc_abort_handler(): Return SUCCESS if we did not + find command in both TX and TX completion queues. Return ERROR + if we timed out waiting for command to complete after abort was + issued. + * Zero-out response sense length in lpfc_scsi_prep_cmnd to prevent + interpretation of stale sense length when the command completes + - was causing spurious 0710 messages. + * Moved clearing of host_scribble inside host_lock in IO + completion path. + * Fixed a bunch of mixed tab/space indentation. + * Allow hex format numbers in sysfs attribute setting. Fix + application hang when invalid numbers are used in sysfs + settings. + * Removed extra iotag allocation by lpfc_abort_handler. + * Clear host_scribble in the scsi_cmnd structure when failing in + queuecommand. + * Changed logic at top of lpfc_abort_handler so that if the + command's host_scibble field is NULL, return SUCCESS because the + driver has already returned the command to the midlayer. + +Changes from 20050308 to 20050323 + + * Changed version number to 8.0.27 + * Changed a few lines from patch submitted by Christoph Hellwig + (3/19). MAILBOX_WSIZE * (uint32_t) is replaced with an + equivalent MAILBOX_CMDSIZE macro. + * Merged patch from Christoph Hellwig (3/19): some misc patches + against the latest drivers: + - stop using volatile. if you need special ordering use memory + barriers but that doesn't seem to be the case here + - switch lpfc_sli_pcimem_bcopy to take void * arguments. + - remove typecast for constants - a U postfix marks them + unsigned int in C + - add a MAILBOX_CMD_SIZE macro, as most users of + MAILBOX_CMD_WSIZE didn't really want the word count + - kill struct lpfc_scsi_dma_buf and embedded the two members + directly in struct lpfc_scsi_buf + - don't call dma_sync function on allocations from + pci_pool_alloc - it's only for streaming mappings (pci_map_*) + * Merged patch from Christoph Hellwig (3/19) - nlp_failMask isn't + ever used by the driver, just reported to userspace (and that in + a multi-value file which is against the sysfs guidelines). + * Change pci_module_init to pci_register_module() with appropriate + ifdefs. + * Added #include as required by the DMA + 32bit and 64bit defines on some archs. + * Merged patch from Christoph Hellwig (03/19) - fix initialization + order - scsi_add_host must happen last from scsi POV. Also some + minor style/comment fixups. + * Fixed use of TRANSPORT_PATCHES_V2 by changing to + FC_TRANSPORT_PATCHES_V2. + +Changes from 20050223 to 20050308 + + * Changed version number to 8.0.26 + * Revise TRANSPORT_PATCHES_V2 so that lpfc_target is removed and + rport data is used instead. Removed device_queue_hash[]. + * Changed RW attributes of scan_down, max_luns and fcp_bind_method + to R only. + * Fixed RSCN handling during initial link initialization. + * Fixed issue with receiving PLOGI handling when node is on NPR + list and marked for ADISC. + * Fixed RSCN timeout issues. + * Reduced severity of "SCSI layer issued abort device" message to + KERN_WARNING. + * Feedback from Christoph Hellwig (on 2/5) - In the LPFC_EVT_SCAN + case the caller already has the target ID handly, so pass that + one in evt_arg1. + * Fix compile warning/resultant panic in + lpfc_register_remote_port(). + +Changes from 20050215 to 20050223 + + * Changed version number to 8.0.25 + * Add appropriate comments to lpfc_sli.c. + * Use DMA_64BIT_MASK and DMA_32BIT_MASK defines instead of + 0xffffffffffffffffULL & 0xffffffffULL respectively. Use pci + equivalents instead of dma_set_mask and also modify condition + clause to actually exit on error condition. + * Restart els timeout handler only if txcmplq_cnt. On submission, + mod_timer the els_tmofunc. This prevents the worker thread from + waking up the els_tmo handler un-necessarily. The thread was + being woken up even when there were no pending els commands. + * Added new typedefs for abort and reset functions. + * Collapsed lpfc_sli_abort_iocb_xxx into a single function. + * Collapsed lpfc_sli_sum_iocb_xxx into a single function. + * Removed TXQ from all abort and reset handlers since it is never + used. + * Fixed Oops panic in 8.0.23 (reported on SourceForge). The + driver was not handling LPFC_IO_POLL cases correctly in + fast_ring_event and was setting the tgt_reset timeout to 0 in + lpfc_reset_bus_handler. This 0 timeout would not allow the FW + to timeout ABTS's on bad targets and allow the driver to have an + iocb on two lists. Also split the lpfc_sli_ringtxcmpl_get + function into two routines to match the fast and slow completion + semantics - ELS completions worked for the wrong reasons. Also + provided new log message number - had two 0326 entries. + * Removed unused #define LPFC_SCSI_INITIAL_BPL_SIZE. + * Removed unused struct lpfc_node_farp_pend definition. + * Removed unused #define LPFC_SLIM2_PAGE_AREA. + * Changed zeros used as pointers to NULL. + * Removed unneeded braces around single line in lpfc_do_work. + * Close humongous memory leak in lpfc_sli.c - driver was losing 13 + iocbq structures per LIP. + * Removed last of GFP_ATOMIC allocations. + * Locks are not taken outside of nportdisc, hbadisc, els and most + of the init, sli, mbox and ct groups of functions + * Fix comment for lpfc_sli_iocb_cmd_type to fit within 80 columns. + * Replaced wait_event() with wait_event_interruptible(). + wait_event() puts the woker thread in an UNINTERRUPTIBLE state + causing it to figure in load average calculations. Also add a + BUG_ON to the ret code of wait_event_interruptible() since the + premise is that the worker thread is signal-immune. + +Changes from 20050208 to 20050215 + + * Changed version number to 8.0.24 + * Fixed a memory leak of iocbq structure. For ELS solicited iocbs + sli layer now frees the response iocbs after processing it. + * Closed large memory leak -- we were losing 13 iocbq structures + per LIP. + * Changing EIO and ENOMEM to -EIO and -ENOMEM respectively. + * Cleanup of lpfc_sli_iocb_cmd_type array and typing of iocb type. + * Implemented Christoph Hellwig's feedback from 02/05: Remove + macros putLunHigh, putLunLow. Use lpfc_put_lun() inline instead. + * Integrated Christoph Hellwig's feedback from 02/05: Instead of + cpu_to_be32(), use swab16((uint16_t)lun). This is the same as + "swab16() on LE" and "<<16 on BE". + * Added updates for revised FC remote port patch (dev_loss_tmo + moved to rport, hostdata renamed dd_data, add fc_remote_host() + on shutdown). + * Removed unnecessary function prototype. + * Added code to prevent waking up worker thread after the exit of + worker thread. Fixes panic seen with insmod/rmmod testing with + 70 disks. + * Integrated Christoph Hellwig's patch from 1/30: Make some + variables/code static (namely lpfcAlpaArray and + process_nodev_timeout()). + * Integrated Christoph Hellwig's patch from 1/30: Use + switch...case instead of if...else if...else if while decoding + JDEC id. + +Changes from 20050201 to 20050208 + + * Changed version number to 8.0.23 + * Make lpfc_work_done, lpfc_get_scsi_buf, + lpfc_mbx_process_link_up, lpfc_mbx_issue_link_down and + lpfc_sli_chipset_init static. + * Cleaned up references to list_head->next field in the driver. + * Replaced lpfc_discq_post_event with lpfc_workq_post_event. + * Implmented Christoph Hellwig's review from 2/5: Check for return + values of kmalloc. + * Integrated Christoph Hellwig's patch from 1/30: Protecting + scan_tmo and friends in !FC_TRANSPORT_PATCHES_V2 && + !USE_SCAN_TARGET. + * Integrated Christoph Hellwig's patch from 1/30: Some fixes in + the evt handling area. + * Integrated Christoph Hellwig's patch from 1/30: Remove usage of + intr_inited variable. The interrupt initilization from OS side + now happens in lpfc_probe_one(). + * Integrated Christoph Hellwig's patch from 1/30: remove shim + lpfc_alloc_transport_attr - remove shim lpfc_alloc_shost_attrs - + remove shim lpfc_scsi_host_init - allocate phba mem in scsi's + hostdata readjust code so that they are no use after free's + (don't use after scsi_host_put) - make lpfc_alloc_sysfs_attr + return errors + * Fixed panic in lpfc_probe_one(). Do not delete in a list + iterator that is not safe. + * Clean up fast lookup array of the fcp_ring when aborting iocbs. + * Following timeout handlers moved to the lpfc worker thread: + lpfc_disc_timeout, lpfc_els_timeout, lpfc_mbox, lpfc_fdmi_tmo, + lpfc_nodev_timeout, lpfc_els_retry_delay. + * Removed unused NLP_NS_NODE #define. + * Integrated Christoph Hellwig's patch from 1/30: remove unused + lpfc_hba_list; remove unused lpfc_rdrev_wd30; remove + lpfc_get_brd_no and use Linux provided IDR. + * Changed board reset procedure so that lpfc_sli_send_reset() + writes the INITFF bit and leaves lpfc_sli_brdreset() to clear + the bit. + * Removed outfcpio sysfs device attribute. + * VPD changes: 1) Modify driver to use the model name and + description from the VPD data if it exists 2) Rework use of DUMP + mailbox command to support HBAs with 256 bytes of SLIM. + * Fixed compile error for implicit definition of struct + scsi_target + +Changes from 20050124 to 20050201 + + * Changed version number to 8.0.22 + * Moved discovery timeout handler to worker thread. There are + function calls in this function which are not safe to call from + HW interrupt context. + * Removed free_irq from the error path of HBA initialization. + This will fix the free of uninitialised IRQ when config_port + fails. + * Make sure function which processes unsolicited IOCBs on ELS ring + still is called with the lock held. + * Clear LA bit from work_ha when we are not supposed to handle LA. + * Fix double locking bug in the error handling part of + lpfc_mbx_cmpl_read_la. + * Implemented fast IOCB processing for FCP ring. + * Since mboxes are now unconditionally allocated outside of the + lock, free them in cases where they are not used. + * Moved out a couple of GFP_ATOMICs in lpfc_disc_timeout, to + before locks so that they can GFP_KERNEL instead. Also cleaned + up code. + * Collapsed interrupt handling code into one function. + * Removed event posting and handling of solicited and unsolicited + iocbs. + * Remove ELS ring handling leftovers from the lpfc_sli_inter(). + * ELS ring (any slow ring) moved from the lpfc_sli_inter() into a + worker thread. Link Attention, Mbox Attention, and Error + Attention, as well as slow rings' attention is passed to the + worker thread via worker thread copy of Host Attention + register. Corresponding events are removed from the event queue + handling. + * Add entries to hba structure to delegate some functionality from + the lpfc_sli_inter() to a worker thread. + * Reduced used of GFP_ATOMIC for memory allocations. + * Moved locks deeper in order to change GFP_ATOMIC to GFP_KERNEL. + * IOCB initialization fix for Raw IO. + * Removed qcmdcnt, iodonecnt, errcnt from lpfc_target and from + driver. + * Added call to lpfc_els_abort in lpfc_free_node. Modified + lpfc_els_abort to reset txq and txcmplq iterator after a + iocb_cmpl call. + * Fixed a use after free issue in lpfc_init.c. + * Defined default mailbox completion routine and removed code in + the sli layer which checks the mbox_cmpl == 0 to free mail box + resources. + * In lpfc_workq_post_event, clean up comment formatting and remove + unneeded cast of kmalloc's return. + * Removed loop which calls fc_remote_port_unblock and + fc_remote_port_delete for every target as this same effect is + accomplished by the scsi_remove_host call. + * Minor cleanup of header files. Stop header files including + other header files. Removed sentinels which hide multiple + inclusions. Removed unneeded #include directives. + * Fixed memory leaks in mailbox error paths. + * Moved lock from around of lpfc_work_done to lpfc_work_done + itself. + * Removed typedef for LPFC_WORK_EVT_t and left just struct + lpfc_work_evt to comply with linux_scsi review coding style. + * Fixed some trailing whitespaces, spaces used for indentation and + ill-formatting multiline comments. + * Bug fix for Raw IO errors. Reuse of IOCBs now mandates setting + of ulpPU and fcpi_parm to avoid incorrect read check of Write IO + and incorrect read length. + +Changes from 20050110 to 20050124 + + * Changed version number to 8.0.21 + * Removed unpleasant casting in the definition and use of + lpfc_disc_action function pointer array. + * Makefile cleanup. Use ?= operator for setting default + KERNELVERSION and BASEINCLUDE values. Use $(PWD) consistently. + * Removed call to lpfc_sli_intr from lpfc_config_port_post. All + Linux systems will service hardware interrupts while bringing up + the driver. + * Christoph Hellwig change request: Reorg of contents of + lpfc_hbadisc.c, lpfc_scsi.h, lpfc_init.c, lpfc_sli.c, + lpfc_attr.c, lpfc_scsi.c. + * Renamed discovery thread to lpfc_worker thread. Moved handling + of error attention and link attention and mbox event handler to + lpfc_worker thread. + * Removed .proc_info and .proc_name from the driver template and + associated code. + * Removed check of FC_UNLOADING flag in lpfc_queuecommand to + determine what result to return. + * Move modification of FC_UNLOADING flag under host_lock. + * Fix IOERR_RCV_BUFFER_WAITING handling for CT and ELS subsystem. + * Workaround firmware bug for IOERR_RCV_BUFFER_WAITING on ELS + ring. + * Fixed a couple lpfc_post_buffer problems in lpfc_init.c. + * Add missing spaces to the parameter descriptions for + lpfc_cr_delay, lpfc_cr_count and lpfc_discovery_threads. + * Lock before calling lpfc_sli_hba_down(). + * Fix leak of "host" in the error path in the remove_one() path. + * Fix comment for lpfc_cr_count. It defaults to 1. + * Fix issue where we are calling lpfc_disc_done() recursively from + lpfc_linkdown(), but list_for_each_entry_safe() is not safe for + such use. + * Bump lpfc_discovery_threads (count of outstading ELS commands in + discovery) to 32 + * If the SCSI midlayer tries to recover from an error on a lun + while the corresponding target is in the NPR state, lpfc driver + will reject all the resets. This will cause the target to be + moved to offline state and block all the I/Os. The fix for this + is to delay the lun reset to a target which is not in MAPPED + state until the target is rediscovered or nodev timeout is + fired. + +Changes from 20041229 to 20050110 + + * Changed version number to 8.0.20 + * rport fix: use new fc_remote_port_rolechg() function instead of + direct structure change + * rport fix: last null pointer check + * Phase II of GFP_ATOMIC effort. Replaced iocb_mem_pool and + scsibuf_mem_pool with kmalloc and linked list. Inserted list + operations for mempool_alloc calls. General code cleanup. All + abort and reset routines converted. Handle_ring_event + converted. + * If the mbox_cmpl == lpfc_sli_wake_mbox_wait in + lpfc_sli_handle_mb_event, pmb->context1 points to a waitq. Do + not free the structure. + * rport fixes: fix for rmmod crash + * rport fixes: when receiving PRLI's, set node/rport role values + * rport fixes: fix for unload and for fabric port deletes + * VPD info bug fix. + * lpfc_linkdown() should be able to process all outstanding events + by calling lpfc_disc_done() even if it is called from + lpfc_disc_done() Moving all events from phba->dpc_disc to local + local_dpc_disc prevents those events from being processed. + Removing that queue. From now on we should not see "Illegal + State Transition" messages. + * Release host lock and enable interrupts when calling + del_timer_sync() + * All related to rports: Clean up issues with rport deletion + Convert to using block/unblock on list remove (was del/add) + Moved rport delete to freenode - so rport tracks node. + * rport fixes: for fport, get maxframe and class support + information + * Added use of wait_event to work with kthread interface. + * Ensure that scsi_transport_fc.h is always pulled in by + lpfc_scsiport.c + * In remote port changes: no longer nulling target->pnode when + removing from mapped list. Pnode get nulled when the node is + freed (after nodev tmo). This bug was causing i/o recieved in + the small window while the device was blocked to be errored w/ + did_no_connect. With the fix, it returns host_busy + (per the pre-remote port changes). + * Merge in support for fc transport remote port use. This removes + any consistent bindings within the driver. All scanning is now + on a per-target basis driven by the discovery engine. + +Changes from 20041220 to 20041229 + + * Changed version number to 8.0.19 + * Fixed bug for handling RSCN type 3. Terminate RSCN mode + properly after ADISC handling completes. + * Add list_remove_head macro. Macro cleans up memory allocation + list handling. Also clean up lpfc_reset_bus_handler - routine + does not need to allocate its own scsi_cmnd and scsi_device + structures. + * Fixed potential discovery bug, nlp list corrutpion fix potential + memory leak + * Part 1 of the memory allocation rework request by linux-scsi. + This effort fixes the number of bdes per scsi_buf to 64, makes + the scatter-gather count a module parameter, builds a linked + list of scsi_bufs, and removes all dependencies on lpfc_mem.h. + * Reverted lpfc_do_dpc, probe_one, remove_one to original + implementation. Too many problems (driver not completing + initial discovery, and IO not starting to disks). Backs out + kthread patch. + * Fix race condition in lpfc_do_dpc. If wake_up interrupt occurs + while lpfc_do_dpc is running disc_done and the dpc list is + empty, the latest insertion is missed and the schedule_timeout + does not wakeup. The sleep interval is MAX_SCHEDULE_TIMEOUT + defined as ~0UL >> 1, a very large number. Hacked it to 5*HZ + for now. + * Fixed bug introduced when discovery thread implementation was + moved to kthread. kthread_stop() is not able to wake up thread + waiting on a semaphore and "modprobe -r lpfc" is not always + (most of the times) able to complete. Fix is in not using + semaphore for the interruptable sleep. + * Small Makefile cleanup - Remove remnants of 2.4 vs. 2.6 + determination. + +Changes from 20041213 to 20041220 + + * Changed version number to 8.0.18 + * Janitorial cleanup after removal of sliinit and ringinit[] ring + statistic is owned by the ring and SLI stats are in sli + structure. + * Integrated patch from Christoph Hellwig Kill + compile warnings on 64 bit platforms: %variables for %llx format + specifiers must be caste to long long because %(u)int64_t can + just be long on 64bit platforms. + * Integrated patch from Christoph Hellwig Removes + dead code. + * Integrated patch from Christoph Hellwig : use + kthread interface. + * Print LPFC_MODULE_DESC banner in module init routine. + * Removed sliinit structure and ringinit[] array. + * Changed log message number from 324 to 326 in lpfc_sli.c. + * Wait longer for commands to complete in lpfc_reset_bus_handler + and lpfc_reset_bus_handler. Also use schedule_timeout() instead + of msleep() and add error message in lpfc_abort_handler() + * When setting lpfc_nodev_tmo, from dev_loss set routine, make 1 + sec minimum value. + * Functions which assume lock being held were called without lock + and kernel complained about unlocking lock which is not locked. + * Added code in linkdown to unreg if we know login session will be + terminated. + * Removed automap config parameter and fixed up use_adisc logic to + include FCP2 devices. + +Changes from 20041207 to 20041213 + + * Changed version number to 8.0.17 + * Fix sparse warnings by adding __iomem markers to lpfc_compat.h. + * Fix some sparse warnings -- 0 used as NULL pointer. + * Make sure there's a space between every if and it's (. + * Fix some overly long lines and make sure hard tabs are used for + indentation. + * Remove all trailing whitespace. + * Integrate Christoph Hellwig's patch for 8.0.14: if + pci_module_init fails we need to release the transport template. + (also don't print the driver name at startup, linux drivers can + be loaded without hardware present, and noise in the log for + that case is considered unpolite, better print messages only for + hardware actually found). + * Integrate Christoph Hellwig's patch for 8.0.14: Add missing + __iomem annotations, remove broken casts, mark functions static. + Only major changes is chaning of some offsets from word-based to + byte-based so we cans simply do void pointer arithmetics (gcc + extension) instead of casting to uint32_t. + * Integrate Christoph Hellwig's patch for 8.0.14: flag is always + LPFC_SLI_ABORT_IMED, aka 0 - remove dead code. + * Modified preprocessor #ifdef, #if, #ifndef to reflect upstream + kernel submission. Clean build with make clean;make and make + clean;make ADVANCED=1 on SMP x86, 2.6.10-rc2 on RHEL 4 Beta + 1. IO with a few lips and a long cable pull behaved accordingly. + * Implement full VPD support. + * Abort handler will try to wait for abort completion before + returning. Fixes some panics in iocb completion code path. + +Changes from 20041130 to 20041207 + + * Changed version number to 8.0.16 + * Hung dt session fix. When the midlayer calls to abort a scsi + command, make sure the driver does not complete post-abort + handler. Just NULL the iocb_cmpl callback handler and let SLI + take over. + * Add Read check that uses SLI option to validate all READ data + actually received. + + +Changes from 20041123 to 20041130 + + * Changed version number to 8.0.15 + * Ifdef'd unused "binary" attributes by DFC_DEBUG for clean + compiles + * Stop DID_ERROR from showing up along with QUEUE_FULL set by the + Clarion array (SCSI error ret. val. 0x70028) There is no need + for driver to hard fail command which was failed by the target + device. + * Fix for Scsi device scan bug reported on SourceForge. Driver + was returning a DID_ERROR in lpfc_handle_fcp_error causing + midlayer to mark report luns as failing even though it + succeeded. + * Don't ignore SCSI status on underrun conditions for inquiries, + test unit ready's, etc. This was causing us to lose + reservation conflicts, etc + +Changes from 20041018 to 20041123 + + * Changed version number to 8.0.14 + * Added new function "iterator" lpfc_sli_next_iocb_slot() which + returns pointer to iocb entry at cmdidx if queue is not full. + It also updates next_cmdidx, and local_getidx (but not cmdidx) + * lpfc_sli_submit_iocb() copies next_cmdidx into cmdidx. Now it is + the only place were we are updating cmdidx. + * lpfc_sli_update_ring() is split in to two -- + lpfc_sli_update_ring() and lpfc_sli_update_full_ring(). + * lpfc_sli_update_ring() don't to read back correct value of + cmdidx. + * Simplified lpfc_sli_resume_iocb() and its use. + * New static function lpfc_sli_next_iocb(phba, pring, &piocb) to + iterate through commands in the TX queue and new command (at the + end). + * Reduced max_lun to 256 (due to issues reported to some arrays). + Fixed comment, and macro values so def=256, min=1, max=32768. + * Fix an obvious typo/bug: kfree was used to free lpfc_scsi_buf + instead of mempool_free in lpfc_scsiport.c. + * Suppress nodev_tmo message for FABRIC nodes. + * Fixed some usage of plain integer as NULL pointer. + * Bug fix for FLOGI cmpl, lpfc_els_chk_latt error path code + cleanup. + * Fixup lpfc_els_chk_latt() to have Fabric NPorts go thru + discovery state machine as well. + * Fixes to lpfc_els_chk_latt(). + * Use DID not SCSI target id as a port_id and add some missing + locks in lpfc_fcp.c. + * Changed eh_abort_handler to return FAILED if command is not + found in driver. + * Fix crash: paging request at virtual address 0000000000100108 - + a result of removing from the txcmpl list item which was already + removed (100100 is a LIST_POISON1 value from the next pointer + and 8 is an offset of the "prev") Driver runs out of iotags and + does not handle that case well. The root of the proble is in the + initialization code in lpfc_sli.c + * Changes to work with proposed linux kernel patch to support + hotplug. + * Zero out seg_cnt in prep_io failure path to prevent double sg + unmap calls. + * Fix setting of upper 32 bits for Host Group Ring Pointers if in + SLIM. Old code was inappropriately masking off low order bits. + * Use scsi_[activate|deactivate]_tcq calls provided in scsi_tcq.h. + * Integrated patch from Christoph Hellwig (hch@lst.de): don't call + pci_dma_sync_* on coherent memory. pci_dma_sync_* is need and + must be used only with streaming dma mappings pci_map_*, not + coherent mappings. Note: There are more consistent mappings + that are using pci_dma_sync calls. Probably these should be + removed as well. + * Modified lpfc_free_scsi_buf to accomodate all three scsi_buf + free types to alleviate miscellaneous panics with cable pull + testing. + * Set hotplug to default 0 and lpfc_target_remove to not remove + devices unless hotplug is enabled. + * Fixed discovery bug: plogi cmpl uses ndlp after its freed. + * Fixed discovery bug: rnid acc cmpl, can potentially use ndlp + after its freed. + * Modularize code path in lpfc_target_remove(). + * Changes to support SCSI hotplug (ifdef'ed out because they need + kernel support USE_SCAN_TARGET requires kernel support to export + the interface to scsi_scan_target and to move the SCAN_WILD_CARD + define to a general scsi header file. USE_RESCAN_HOST requires + kernel support to export an interface to scan_scsi_host() with + the rescan flag turned on). + * Removed redundant variable declaration of lpfc_linkdown_tmo. + * Fix for large port count remove test. + * Added check to see if BAR1 register is valid before using BAR1 + register for programming config_port mail box command. + * Added lpfc_scsi_hotplug to enable/disable driver support of SCSI + hotplug. + * Changed lpfc_disc_neverdev() to lpfc_disc_illegal() and changed + lpfc_disc_nodev() to lpfc_disc_noop(). Adjusted appropriate + events to use these routines. + * Add support for SCSI device hotplug. + * Take dummy lpfc_target's into account for lpfc_slave_destroy(). + * Bug fix to store WWPN / WWNN in NameServer / FDMI lpfc_nodelist + entries. + * Added slavecnt in lpfc_target for diagnostic purposes. + * Added lpfc_hba load/unload flags to take care of special cases + for add/remove device. + * Have target add/remove delay before scanning. + * Have rmmod path cleanup blocked devices before scsi_remove_host. + * Added a #define for msleep for 2.6.5 kernels. + * In reset bus handler if memory allocation fails, return FAILED + and not SUCCESS. + * Have lpfc eh handlers, bus_reset and lun_reset, wait for all + associated I/Os to complete before returning. + * Fix memset byte count in lpfc_hba_init so that + LP1050 would initialize correctly. + * Backround nodev_timeout processing to DPC This enables us to + unblock (stop dev_loss_tmo) when appopriate. + * Fix array discovery with multiple luns. The max_luns was 0 at + the time the host structure was intialized. lpfc_cfg_params + then set the max_luns to the correct value afterwards. + * Remove unused define LPFC_MAX_LUN and set the default value of + lpfc_max_lun parameter to 512. + * Reduced stack usage of lpfc_hba_init. + * Cleaned up the following warning generated by + scripts/checkincludes.pl lpfc_fcp.c: scsi/scsi_cmnd.h is + included more than once. + * Replaced "set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(timeout)" with "msleep(timeout)". + * Fixnode was loosing starget when rediscovered. We saw messages + like: lpfc 0000:04:02.0: 0:0263 Cannot block scsi target as a + result. Moved starget field into struct lpfc_target which is + referenced from the node. + * Add additional SLI layer logging in lpfc_sli.c. + * Ignore more unexpected completions in lpfc_nportdisc.c. + * Can not call lpfc_target_unblock from the soft interrupt + context. It seems to be not nessasery to unblock target from + nodev timeout. + * Introduce and use less lethal event handler for unexpected + events in lpfc_nportdisc.c. + * Can not call fc_target_(un)block() functions with interrupts + disabled in lpfc_scsiport.c. + * Added new configuration parameter, lpfc_max_luns range 1-32768, + default 32768. + * Allow lpfc_fcp.c to call lpfc_get_hba_sym_node_name(). + * Increase nodev timeout from 20 seconds to 30 seconds. + * Replace some kfree((void*)ptr) with kfree(ptr). + * Make 3 functions static: lpfc_get_hba_sym_node_name, + lpfc_intr_prep and lpfc_setup_slim_access. Move lpfc_intr_prep + and lpfc_setup_slim_access so they're defined before being used. + * Remove an unecessary list_del() in lpfc_hbadisc.c. + * Set nlp_state before calling lpfc_nlp_list() since this will + potentially call fc_target_unblock which may cause a race in + queuecommand by releasing host_lock. + * Since lpfc_nodev_tmo < dev_loss_tmo remove queuecommand + DID_BAD_TARGET return for now. + * Fix a problem with rcv logo. + * Remove unused portstatistics_t structure. + * Remove #if 0 and unnecessary checks in lpfc_fcp.c. + * Simplify lpfc_issue_lip: Extra layer of protection removed. + * Grab lock before calling lpfc_sli_issue_mbox(phba, pmb, + MBX_NOWAIT) in lpfc_sli_issue_mbox_wait(). + +Changes from 20040920 to 20041018 + + * Changed version number to 8.0.13 + * Hide some attributes using #ifndef DFC_DEBUG ... #endif. + * Modify Makefile to (1) make BUILD_NO_DEBUG=1 will hide some + (binary) attributes (2) make BUILD_FC_TRANS=0 will build driver + for 2.6.5 kernel with block/unblock patch. + * Modified #ifdef names. + * Added support for proposed FC transport host attributes (which + replaces some of the attributes we had local to the driver). + Removed the binary statistics sysfs attribute. + * Added extra ELS verbose logging for ELS responses. + * Added recognition for BUILD_FC_TRANS=2 to Makefile to define + FC_TRANS_VER2. + * Add a pointer for link stats allocation. + * Exported lpfc_get_hba_sym_node_name for use by FC_TRANS_VER2 + sysfs routines. + * Fix discovery problem in lip testing: if device sends an ELS cmd + (i.e. LOGO) before our FLOGI completes it should be LS_RJT'ed. + * Moved #defines around to provide target_add/remove for upstream + kernel deliverables only not SLES9. Provided ifdefs to #include + target_block/unblock only if FC_TRANS_VER1. + * Add sanity check in lpfc_nlp_list move setting nlp_Target + outside #ifdef. + * Added a blocked member to the lpfc_target structure for + block/unblock. This member allows the driver to know when to + unblock for pci_remove_one or pci_add_one. #ifdef'd some more + block/unblock stuff and removed some defensive checks from + target_block/unblock. + * Moved + 5 second window to dev_loss_tmo setting and updated + comments. + * Removed NULL target check from target_block/unblock and fixed up + a few comments. + * Enable sysfs attributes on 2.6.5 kernels and remove extra + compatibility code. + * Remove any and all trailing whitespace. + * Added message 0718 and return error when dma_map_single fails. + * Changed the fcpCntl2 commands to include an FCP_ prefix to get + rid of build warnings on later 2.6.9-rc kernels. Build + conflicts with scsi/scsi.h. Remove inclusions of scsi/scsi.h + from hbadisc.c, sli.c, and fcp.c since these modules had no + dependencies on scsi.h. + * Fixed a bug with RSCN handling. A RSCN received on one device, + shouldn't affect other devices not referenced by the RSCN. + * Moved #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,6) to include + lpfc_jedec_to_ascii to prevent warning in SLES 9. + * Update Makefile to account for SLES 9 and scsi-target upstream + kernel. + * This checkin provides block/unblock hooks for the upstream scsi + target kernel and 2.6.5 on SLES9 SP1 with the block/unblock + patch. + * Discovery changes regarding setting targetp->pnode and + ndlp->nlp_Target Ensure fc_target_* routines are called properly + from discovery. Remove list_del's from lpfc_cleanup(). Ensure + all the lpfc_consistent_bind_* routines don't set any driver + structure objects. + * Fix for timeout of READ_LA or READ_SPARAM mailbox command + causing panic. + * Cleanup list_del()'s for Discovery ndlp lists. + * Bug fixes for some insmod/rmmod crashes, link down crashes and + device loss crashes. + * Removed NLP_SEARCH_DEQUE. + * Call lpfc_target_unblock only if the targetp is nonNull and with + the host_lock held. + * Added qcmdcnt back along with misc bug fixes to discovery. + * Changed tgt_io to outfcpio lpfc_fcp.c. + * Fixed errors caused by LIP and cable pulls both with and without + block/unblock patch. + * For now we have to call fc_target_unblock and fc_target_block + with interrupts enabled. + * Save seg_cnt from dma_map_sg. Save scatter-gather start address + and pass back to dma_unmap_sg in error with seg_cnt. + * Incorporating block/unblock calls into driver with ifdefs. This + change is supported by scsi-target-2.6 kernel and forward only. + * Merged in some discovery bug fixes and added tgt io counters. + * Added sysfs attributes/interfaces: read only attribute + "management_version" and write only attribute "issue_lip". + * Fix build on big endian machines: while #if was OK with + __BIG_ENDIAN which defined as 4321, __BIG_ENDIAN_BITFIELD has to + be tested with #ifdef because it does not have any value, it is + either defined or not. + * Add fabric_name and port_type attributes. + * Change mdelay to msleep. mdelay works, but wastefully uses cpu + resources without a lock held. Revert to msleep. Tested with + sg_reset for bus and three attached targets. + * Added the customary #ifndef...#define...#endif to + lpfc_version.h. + * Integrate patches from Christoph Hellwig: two new helpers common + to lpfc_sli_resume_iocb and lpfc_sli_issue_iocb - singificant + cleanup of those two functions - the unused SLI_IOCB_USE_TXQ is + gone - lpfc_sli_issue_iocb_wait loses it's flags argument + totally. + * Fix in lpfc_sli.c: we can not store a 5 bit value in a 4-bit + field. + * Moved some routines out of lpfc_fcp.c into more appropriate + files. + * Whitespace cleanup: remove all trailing whitespace. + * Make lpfc_disc_ndlp_show static to lpfc_fcp.c. + * Remove leftover printk and replace some with + printk(KERN_WARNING) + * Trivial: fix a few long lines and a soft tab. + * Remove warnings generated by Sparse against driver (make + C=1). Mostly these are "using integer as pointer warnings" + i.e. use NULL instead of 0. + * Integrated patch from Christoph Hellwig: Quite a lot of changes + here, the most notable is that the phba->slim2p lpfc_dmabuf goes + away in favour of a typede pointer and a dma_addr_t. Due to the + typed pointer lots of the cast mess can go away, and while at it + I also replaced the messy SLI2_SLIM_t with a simple struct + lpfc2_sli2_slim that only contains the part of the union we care + about while using SLI2_SLIM_SIZE for all size calculations + directly. + * Integrated patch from Christoph Hellwig: This streamlines the + I/O completion path a little more, especially taking care of + fast-pathing the non-error case. Also removes tons of dead + members and defines from lpfc_scsi.h - e.g. lpfc_target is down + to nothing more then the lpfc_nodelist pointer. + * Added binary sysfs file to issue mbox commands + * Replaced #if __BIG_ENDIAN with #if __BIG_ENDIAN_BITFIELD for + compatibility with the user space applications. + * Decrease the amount of data in proc_info. + * Condense nodelist flag members. + * Expand INFO for discovery sysfs shost entries. + * Notify user if information exceeds 4k sysfs limit. + * Removed a bunch of unused #defines. + * Added initial sysfs discovery shost attributes. + * Remove unused #defines lpfc_disc.h. + * Fixed failMask nodelist settings. + * Cleanup some old comments / unused variables. + * Add LP101 to list of recognized adapters. + +Changes from 20040908 to 20040920 + + * Changed version number to 8.0.12 + * Removed used #defines: DEFAULT_PCI_LATENCY_CLOCKS and + PCI_LATENCY_VALUE from lpfc_hw.h. + * Changes to accomodate rnid. + * Fix RSCN handling so RSCN NS queries only effect NPorts found in + RSCN data. + * If we rcv a plogi on a NPort queued up for discovery, clear the + NLP_NPR_2B_DISC bit since rcv plogi logic will force NPort thru + discovery. + * Ensure lpfc_target is also cleaned up in lpfc_cleanup(). + * Preliminary changes for block/unblock kernel API extensions in + progress with linux-scsi list. These are name changes and + prototype changes only. + * Added send_abts flag to lpfc_els_abort. For rcv LOGO when ADISC + sent, the XRI of the LOGO rcv'ed is the same as the ADISC + sent. Thus we cannot ABTS the ADISC before sending the LOGO ACC. + * Weed out some unused fc_flags. Add FC_DISC_TMO. + * board_online sysfs attribute added to support libdfc functions + InitDiagEnv and SetBrdEnv. + * Streamline code in lpfc_els_retry fixup abort case in + lpfc_els_timeout_handler(). + * Flush discovery/ELS events when we bring SLI layer down. + * ctlreg and slimem binary attributes added to support libdfc + read/write mem/ctl functions. + * Integrated Christoph Hellwig's patch: Cleanup + lpfc_sli_ringpostbuf_get. + * Modified lpfc_slave_alloc and lpfc_slave_destroy to allocate and + free a dummy target pointer. This allows queuecommand to skip + the NULL target pointer check and avoid the console spam when + slave_alloc fails. + * Fix cfg_scan_down logic, it was reversed. + * Init list head ctrspbuflist. + * Change name of lpfc_driver_abort to lpfc_els_abort since it is + only valid for ELS ring. + * Remove unused third argument for lpfc_consistent_bind_get(). + * Fix up iotag fields in lpfc_prep_els_iocb(). + * Remove log message on code path triggered by lpfc_els_abort(). + * Set host->unique_id in lpfc_fcp.c. + * Removed deadwood: lpfc_target.pHba not necessary anymore. + * Integrated patch from Christoph Hellwig: remove dead + SLI_IOCB_POLL handling. + * Integrated patch from Christoph Hellwig: Streamline I/O + submission and completion path a little. + * Remove unnecessary lpfc_brd_no. Ensure brd_no assignment is + unique. + * Removed unused MAX_FCP_LUN. + * Use mod_timer instead of add_timer for fdmi in lpfc_ct.c. + * Fixed misc discovery problems. + * Move stopping timers till just before lpfc_mem_free() call. + * Fix up NameServer reglogin error path. + * Cleanup possible outstanding discovery timers on rmmod. + * Fix discovery NPort to NPort pt2pt problem. + * Get rid of ip_tmofunc / scsi_tmofunc. + * Integrated patch from Christoph Hellwig: + lpfc_disc_done/lpfc_do_dpc cleanup - lpfc_disc_done can return + void - move lpfc_do_dpc and lpfc_disc_done to lpfc_hbadisc.c - + remove checking of list emptiness before calling lpfc_disc_done, + it handles the emtpy list case just fine and the additional + instructions cost less then the bustlocked spinlock operations. + * Integrated patch from Christoph Hellwig: This adds a new 64bit + counter instead, brd_no isn't reused anymore. Also some tiny + whitespace cleanups in surrounding code. + * Reorder functions in lpfc_els.c to remove need for prototypes. + * Removed unsed prototypes from lpfc_crtn.h - + lpfc_ip_timeout_handler, lpfc_read_pci and lpfc_revoke. + * Removed some unused prototypes from lpfc_crtn.h - + lpfc_scsi_hba_reset, lpfc_scsi_issue_inqsn, + lpfc_scsi_issue_inqp0, lpfc_scsi_timeout_handler. + * Integrated patch from Christoph Hellwig: remove TRUE/FALSE + usage. + * Integrated patch from Christoph Hellwig: Remove unused function + prototypes lpfc_set_pkt_len and lpfc_get_pkt_data from + lpfc_crtn.h - fixes build warnings. + * Removed unused struct lpfc_dmabufip definition from lpfc_mem.h. + * Removed pre-2.6.5 MODULE_VERSION macro from lpfc_compat.h. + * Fixing missing static and removing dead code. + * Adding nodewwn, portwwn and portfcid shost attributes. + * Initial support for CT via sysfs. request payloads of size less + than PAGE_SIZE and rsp payloads of size PAGE_SIZE are supported. + Driver maintains a list of rsp's and passes back rsp's + corresponding to the pid of the calling process. + * Support for RefreshInformation, GetAdapterAttributes, + GetPortStatistics. + * Make nodev-tmo default to 20 seconds. + * Fix up some DSM error cases, unreg_login rpi where needed. + * Fix up comments for fc_target_block / fc_target_unblock. + * Fix up code for scsi_block_requests / scsi_unblock_requests. + * Add NLP_FCP_TARGET for nodeinfo support. + * Move suspend/resume in lpfc_nlp_list under appropriate case - + Used host_lock for DPC to avoid race (remove dpc_lock) + * Fix some corner cases for PLOGI receive - simplify error case + for cmpl_reglogin_reglogin_issue. + * Bug fix for ppc64 EEH MMIO panic - always do readl after + writel's of HBA registers to force flush. + * Get rid of initial static routine declarations in lpfc_hbadisc.c + and lpfc_els.c. + * Updates to discovery processing. + +Changes from 20040823 to 20040908 + + * Changed version number to 8.0.11 + * Removed persistent binding code. + * Display both ASC and ASCQ info. + * Fixed link down->up transitions when linkdown tmo expires. Fix + was in the defensive error checking at the start of + queuecommand. + * Removed lpfc_scsi_timeout_handler as this timer is no longer + required. The midlayer will exhaust retries and then call + lpfc_abort_handler, lpfc_reset_lun_handler, and + lpfc_reset_target_handler. + * Minimal support for SCSI flat space addressing/volume set + addressing. Use 16 bits of LUN address so that flat + addressing/VSA will work. + * Changed 2 occurences of if( 1 != f(x)) to if(f(x) != 1) + * Drop include of lpfc_cfgparm.h. + * Reduce stack usage of lpfc_fdmi_cmd in lpfc_ct.c. + * Add minimum range checking property to /sys write/store + functions. + * Fix display of node_name and port_name via fc transport + attr. + * Removed biosparam code. + * Removed range checking. phba->config[] array elements are now + embedded into the hba struct. lpfc_config_setup() has been + removed. + * Collapsed lpfc_scsi_cmd_start into lpfc_queuecommand and cleaned + up combined routines. + * Removed unused prototypes myprint and + lpfc_sched_service_high_priority_queue. + * Removed unused function lpfc_nodev. + * Removed scsi_cmnd->timeout_per_command cancelation. SCSI midlayer + now times out all commands - FW is instructed to not timeout. + * Removed polling code from lpfc_scsi_cmd_start. Reorganized + queuecommand and cmd_start some. + +Changes from 20040810 to 20040823 + + * Changed version number to 8.0.10 + * Additional timer changes as per Arjan / Christoph's comments. + * Used mod_timer() instead of del_timer_sync() where appropriate. + * Fixed a use after free case (panic on 2.6.8.1 with + CONFIG_DEBUG_SLAB set). + * Fix compile warning in lpfc_fcp.c. + * Minor fix for log message, that prints unassigned brdno which is + zero. + * Move scsi_host_alloc() to the beginning of probe_one(). This + ensures that host_lock is available at later stages and also + avoids tons of unnecessary initializing if host_alloc() + fails. + * Removed else clause from lpfc_slave_configure that set + sdev->queue_depth. The driver informs the midlayer of its + setting in the template and only overrides if queue tagging is + enabled. + * Added PCI_DEVICE_ID_ZEPHYR and PCI_DEVICE_ID_ZFLY (Junior + Zephyr) support + +Changes from 20040730 to 20040810 + + * Changed version number to 8.0.9 + * Removed per HBA driver lock. Driver now uses the host->host_lock + * Restored support for the 2.6.5 kernel for those linux distributions + shipped with the 2.6.5 kernel. + * Applied patch from Christoph Hellwig (hch@infradead.org) as follows + "[PATCH] use scsi host private data in ->proc_info. + * Applied patch from Christoph Hellwig (hch@infradead.org) as follows + "Re: [Emulex] Ready for next round. This patch cleans up the memory + allocation routines a little and fixes a missing mempool_destroy and + some missing error handling." + * Changed pointers assignments from 0 to NULL. + * Added fixes to the lpfc_reset_lun_handler and lpfc_reset_bus_handler + entry points that caused kernel to Oops or hang. + * Added fixes to targetless hosts that caused modprobe and insmod to hang. + * Ongoing cleanup to many files + +Changes from 20040723 to 20040730 + + * Changed version number to 8.0.8 + * Removed unused LPFN_DRIVER_VERSION #define. + * Folded lpfc_findnode_scsiid into lpfc_find_target, its only + caller. + * Removed 2 unneeded arguments to lpfc_find_target (lun and + create_flag). + * Make lpfc_sli_reset_on_init = 1 + * Minor cleanup to quieten sparse. + * Removed missing function = 0 in tmo routine in lpfc_els.c. + * Moved additional binding parameters into lpfc_defaults.c: + lpfc_automap / lpfc_fcp_bind_method + * Use msecs_to_jiffies() where applicable. + * Only use queue depth attribute only after SLI HBA setup was + completed. + * Put in memory barriers for PPC + * Added PCI_DEVICE_ID_HELIOS and PCI_DEVICE_ID_JFLY (Junior + Helios) support + * Added 4&10 gigabit choices in user option link_speed + * Updated timer logic: Set timer data after init_timer use + timer_pending() instead of expires. + * Removed some remnants of IP over FC support from Kconfig and + Makefile. + * Remove redundant prototypes for lpfc_handle_eratt, + lpfc_handle_latt and lpfc_read_pci. + * Ongoing cleanup of lpfc_init.c. + * Changed LPFC_CFG_DFT_HBA_Q_DEPTH -> LPFC_CFG_HBA_Q_DEPTH. + * Another cleanup stab at lpfc_ct.c. Remove castings, structure + code sanely, remove redundant code, reorganize code so that + functions are invoked after definition. + +Changes from 20040716 to 20040723 + + * Changed version number to 8.0.7 + * Cleanup of lpfc_ct.c. Removed number of casts, removed tons of + dead/redundant code, cleaned up badly and poorly written code, + cleaned up return values. + * Fixed Persistent binding implementation + * Removed all references to lpfc_scsi_req_tmo + * Removed last references to lun_skip config parameter. + * Removed LPFC_DEV_RPTLUN node failure bit because we don't issue + REPORT_LUNS from the driver anymore. + * Removed LUN-tracking in driver. Removed lpfc_lun struct and + moved any functionality we still need to lpfc_target. + * Added new lpfc_jedec_to_ascii() call and replace two instances + of duplicate code with calls to this function. + * Removed Volume Set Addressing handling on LUN IDs. + * Applied patch from Christoph Hellwig (hch@infradead.org) that + removes dead code belonging to lpfc_build_scsi_cmnd() and its + call path. This is related to the recently removed report_lun + code. + +Changes from 20040709 to 20040716 + + * Changed version number to 8.0.6 + * Removed internal report LUNs usage. Removed functions: + lpfc_disc_issue_rptlun, lpfc_disc_cmpl_rptlun, + lpfc_disc_retry_rptlun and their use. + * Removed usused scheduler prototypes in lpfc_crtn.h + * Replace lpfc_geportname() with generic memcmp(). + * Rearrange code in lpfc_rcv_plogi_plogi_issue() to make it a + little more readable. + * Remove redundant port_cmp != 2 check in if + (!port_cmp) { .... if (port_cmp != 2).... } + * Clock changes: removed struct clk_data and timerList. + * Clock changes: seperate nodev_tmo and els_retry_delay into 2 + seperate timers and convert to 1 argument changed + LPFC_NODE_FARP_PEND_t to struct lpfc_node_farp_pend convert + ipfarp_tmo to 1 argument convert target struct tmofunc and + rtplunfunc to 1 argument * cr_count, cr_delay and + discovery_threads are only needed to be module_params and not + visible via sysfs. + +Changes from 20040614 to 20040709 + + * Changed version number to 8.0.5 + * Make lpfc_info static. + * Make lpfc_get_scsi_buf static. + * Print a warning if pci_set_mwi returns an error. + * Changed SERV_PARM to struct serv_parm. + * Changed LS_RJT to struct ls_rjt. + * Changed CSP to struct csp. + * Changed CLASS_PARMS to struct class_parms. + * Some cosmetic coding style cleanups to lpfc_fcp.c. + * Providing a sysfs interface that dumps the last 32 + LINK_[UP|DOWN] and RSCN events. + * Get rid of delay_iodone timer. + * Remove qfull timers and qfull logic. + * Convert mbox_tmo, nlp_xri_tmo to 1 argment clock handler + * Removed duplicate extern defs of the bind variables. + * Streamline usage of the defines CLASS2 and CLASS3, removing + un-necessary checks on config[LPFC_CFG_FCP_CLASS]. + * Moving the persistent binding variables to new file + lpfc_defaults.c + * Changed LPFC_SCSI_BUF_t to struct lpfc_scsi_buf. + * Moved config specific code from probe_one() into + config_setup(). Removing a redundant check on scandown value + from bind_setup() as this is already done in config_setup(). + * Changed LPFC_SLI_t to struct lpfc_sli. + * Changed FCP_CMND to struct fcp_cmnd. + * Changed FCP_RSP to struct fcp_rsp. + * Remove the need for buf_tmo. + * Changed ULP_BDE64 to struct ulp_bde64. + * Changed ULP_BDE to struct ulp_bde. + * Cleanup lpfc_os_return_scsi_cmd() and it's call path. + * Removed lpfc_no_device_delay. + * Consolidating lpfc_hba_put_event() into lpfc_put_event(). + * Removed following attributes and their functionality: + lpfc_extra_io_tmo, lpfc_nodev_holdio, lpfc_delay_rsp_err, + lpfc_tgt_queue_depth and lpfc_check_cond_err. + * Clock changes consolidating timers, just in the struct lpfc_hba, + to get rid of clkData and pass only one argument to timeout + routine. Also, removing need for outstanding clock linked list + to stop these timers at rmmod. + * Move lpfc.conf contents into lpfc_fcp.c. Removing per adapter + attributes in favor of global attributes. + * Fix a potential null pointer reference of pmbuf in lpfc_ct.c. + * On reset_lun, issue LUN_RESET as opposed to ABORT_TASK_SET. + * Removed SCSI_REQ_TMO related code. + * Introducing two new defines LPFC_ATTR_R and LPFC_ATTR_RW that do + a module_param, MODULE_PARM_DESC, lpfc_param_show, + [lpfc_param_store] and CLASS_DEVICE_ATTRIBUTE. + * Properly clean up when allocation of a linked BDE fails in the + SCSI queuecommand path. + * Fail SCSI command if dma_map_sg call fails. + * Remove unused macros SWAP_ALWAYS and SWAP_ALWAYS16. + * Reset context2 to 0 on exit in + lpfc_sli_issue_iocb_wait_high_priority() and + lpfc_sli_issue_iocb_wait(). + * Arranging lpfc_scsiport.c to follow style of use after + definition. This removes the need for the cruft of forward + declarations. Also removing a redundant #define ScsiResult as it + already available elsewhere. + * Applying "Streamline lpfc error handling" patch from Christoph + Hellwig (hch@infradead.org) with following modifications: fix + mem leaks, remove some misplaced code that need not be there, + print a message on exit (old code prints two (entry/exit)), make + ret values consistent (either 1/0 or SUCCESS/FAILURE), keep all + eh routines in a single file (lpfc_scsiport.c). + * Move contents of lpfc_module_param.h into lpfc_fcp.c. + * Changed sysfs attributes to CLASS_DEVICE_ATTRIBUTES (previously + DEVICE_ATTRIBUTES). They now appear in + /sys/class/scsi_host/hostx (previously in + /sys/bus/pci/drivers/lpfc/devx). + * Removed lpfc_syfs.h and lpfc_sysfs.c. + * Cleanup of config params. Throttle params have been removed. + max_lun has been removed. max_target is replaced with a #define, + lun_skip is removed. Remove ipfc config params and related + code. + * Changed DMABUF_t usage to struct lpfc_dmabuf. + * Downsizing iCfgParam structure to include a_string, a_low, a_hi + and a_default values only. + * Free SCSI buf safety memory pool on shutdown to eliminate memory + leak. + * Change lpfc_printf_log to a #define. Also include phba->brd_no + and newline in the print string rather than in the #define. + * Remove code that optionally locates Host Group Pointers in host + memory SLIM since this is no longer needed for PPC64, once + CONFIG_PORT uses HBA's view of its BAR0. + * Removed the forward declarations of the sli functions and + rearranging the code in lpfc_sli.c. + * Removed the preamble functionality from logging. + * Make lpfc_sli_hba_setup() return negative error codes on error + and correct the comment left over in lpfc_fcp.c + * Removed the lpfc_loadtime variable. + * Put a space between all ifs and their open parens '('. + * Change Studly_Caps LPFC_SCSI_BUF_t to struct lpfc_scsi_buf. + * Fixed insmod hang after hardware error. + * Relocated scsi_host alloc to before we enable the interrupt + handler + * Add .tmp_versions directory to Makefile clean target. This + directory is created in the 2.6.5+ build process (with Red Hat + kernels at least). + * Changing phba->config to kmalloc lpfc_icfgparam and not + *phba->config. This is manifesting itself as a panic in + pci_release_region(). + * Fix for firmware download / board reset problem. + * Integrated patch from Christoph Hellwig (hch@infradead.org) to + reorganize and cleanup lpfc_fcp.c + * Don't abort commands immediately when there is an RSCN event to + give driver time to rediscover targets before the midlayer + retries the SCSI commands. + +Changes from 20040604 to 20040614 + + * Changed version number to 8.0.4 + * Removed lpfc_valid_lun function. + * Added scsi_buf safety pool to address scsi_buf failures in + queuecommand under low memory conditions. Allocations now come + from kmalloc initially, but if kmalloc fails, the allocation + comes from the safety pool. + * Modified lpfc_slave_alloc to only set the scsi_device->hostdata + pointer if the driver has discovered the target. This routine + always returns success now as well since no error ever occurs in + the alloc routine. + * Mask only info and warning messages. Print all error messages + irrespective of mask. + * Removing lpfc_log_chk_msg_disabled() + * Changed lpfc_printf_log to take struct lpfc_hba * directly + instead of a "board number". + * Convert dma_sync_single to pci_dma_sync_single_for_{device/cpu}. + * Implemented new style log messages. The message strings are now + embedded in the call to lpfc_printf_log. + * Decreased FLOGI discovery timeout to 20 seconds. + * On error in lpfc_pci_probe_one() return -1 and not 1. + * Allow for board numbers that are not sequential, paving the way + for hotplug support. + * scsi_add_host() can fail, so wrap it around in an if(). Also + initiate scsi_scan_host() after attaching the sysfs attributes. + * lpfc_release_version is used only in lpfc_ct.c, so move it there + and mark it as static. + * Removed lpfc_sleep_ms and replaced with mdelay or schedule calls + directly + * Removed all (struct list_head *) casts from clkData-related list + handling in list_add, list_del macros. + * Removed EXPORT_SYMBOLs. + * Removed LPFC_MIN_QFULL and lpfc_qthrottle_up. + * Replace LPFCSCSITARGET_t with struct lpfc_target. + * Replace LPFCSCSILUN_t with struct lpfc_lun. + * Remove unused struct declarations (fcPathId and fcRouteId) from + lpfc_scsi.h. + * Rewrite use of FC transport attributes. + * Fix crash when link is lost. This was due to lpfc_delay_iodone + calling list_del on an object that was never put on a list. + * Remove trailing spaces at the end of all lines. + * Set MAX_FCP_TARGET to 256 from 0xff. Set MAX_FCP_LUN and + MAX_FCP_CMDS to their decimal equivalents and updated + documentation. + +Changes from 20040526 to 20040604 + + * Changed version number to 8.0.3 + * Completed sysfs FC transport support. + * Removed unused fields in SCSI LUN and SCSI Target structures: + void *pTargetProto; void *pTargetOSEnv; void *pLunOSEnv; + * Modified list_for_each to list_for_each_entry. Modified + list_for_each_safe to list_for_each_entry_safe. + * Remove lpfc_dfc.h file. + * Changed pHba->phba, pCommand->pcmd + * Changed plogi_ndlp -> plogindlp, pos_tmp->postmp, pRsp->prsp, + pCmd->pcmd + * Changed pText -> ptext + * Changed p_tmp_buff -> ptmpbuff + * Changed pBufList -> pbuflist, pRsp -> prsp, pCmd -> pcmd + * Changed *pos_tmp -> *postmp, *p_mbuf -> *pmbuf + * Following changes are made to the SCSI fast path: Added + DMA_BUF_t member to the lpfc_scsi_buf_t. This will reduce a + memory allocation in the scsi fast path. Added check for + targetp == NULL in the scsi fast path. Increased number of + scatter gather entries in lpfc_scsi_dma_ext to 4 from 3 and + changed the size of lpfc_scsi_dma_ext to 264 + * Fixing some missing static lpfc_nportdisc.c. + * Reordered #include lines so that lpfc.h doesn't have to #include + other header files. + * Remove lpfc_get_hba_sym_node_name() as a global EXPORT and make + it static. + * Move struct clk_data definition from lpfc_hw.h to lpfc_sli.h. + * Changed LPFC_IOCBQ_t to struct lpfc_iocbq. + * Changed LPFC_SLI_RING_t to struct lpfc_sli_ring. + * Changed LPFC_NODELIST_t to struct lpfc_nodelist. + * Rearranged lpfc_nportdisc.c by moving state machine array + (lpfc_disc_action) and the one function that uses it, + lpfc_disc_state_machine, to the end of the file, removing the + need for the raft of prototypes at the top. + * Changed LPFC_BINDLIST_t to struct lpfc_bindlist. + * Removed lpfc_issue_ct_rsp(), lpfc_sleep(), lpfc_add_bind(), + lpfc_del_bind(), lpfc_sli_wake_mbox_wait() and + lpfc_sli_issue_mbox_wait(). + * Fixed a large number of overly-long lines. + * Fixed some discovery problems: Introduced deferred ndlp removal + when in DSM to avoid panic when in nested DMSs Fix NportId + fffc01 handling to not relogin after LOGO fixed handling of LOGO + on PLOGI issue. + * Changed SLI_CT_REQUEST to lpfc_sli_ct_request. + * Changed NAME_TYPE to struct lpfc_name. + * Changed lpfcCfgParam_t to struct lpfc_cfgparam. + * Changed LPFC_STAT_t to struct lpfc_stats. + * Changed HBAEVT_t to struct lpfc_hba_event. + * Changed Studly_Caps lpfcHBA_t to struct lpfc_hba. + * Removed no longer used tasklet_running flag. + * Removing *PSOME_VAR typedefs and using SOME_VAR* directly. + * Changing .use_clustering to ENABLE_CLUSTERING. + * Modify lpfc_queuecommand to return SCSI_MLQUEUE_HOST_BUSY when + it can't queue a SCSI command. Also, remove cmnds_in_flight + member of struct lpfcHBA for 2.6 kernels as it was only needed + to determine what to return from queuecommand. + * Change return type of lpfc_evt_iocb_free to void as it doesn't + return anything. + * Remove unused cmnd_retry_list and in_retry members in struct + lpfcHBA. + * Remove some instances of unneeded casting of kmalloc's return in + lpfc_scsiport.c + * Remove lpfc_linux_attach() and lpfc_linux_detach(). Integrate + them into lpfc_probe_one() and lpfc_release_one() respectively. + * Remove lpfc_num_iocbs, lpfc_num_bufs module parameters + * Remove #defines for NUM_NODES, NUM_BUFS and NUM_IOCBS + +Changes from 20040515 to 20040526 + + * Changing version number to 8.0.2. + * Including dma-mapping.h as one of the include headers. Also + rearrange the #include order. + * Make functions static as appropriate. + * queuecommand() will now return SCSI_MLQUEUE_HOST_BUSY instead of + 1 to backpressure midlayer. + * Removed function prototypes for lpfc_start_timer() and + lpfc_stop_timer() + * Changed timer support to be inline. Clk_data is now declared + right next to the corresponding timer_list entry so we don't + have to allocate these clk_data dynamically. + * Add readls after writels to PCI space to flush the writes. + * Fix misspelled word "safety" in function names. + * Fix up comments in lpfc.conf for per HBA parameters to reflect + new implementation. + * Change lpfc_proc_info handler to get the Nodename from + fc_nodename and not fc_portname. + * Fix up some comments and whitespace in lpfc_fcp.c. + * Formatting changes: get rid of leading spaces in code + * Move discovery processing from tasklet to a kernel thread. + * Move ndlp node from unmap list to map list if ADISC completed + successfully. + * Flush all the ELS IOCBs when there is a link event. + * LP9802 qdepth is twice the LP9802DC qdepth. Delay + elx_sched_init after READ_CONFIG to get max_xri from the + firmware. Reset ELX_CFG_DFT_HBA_Q_DEPTH to max_xri after + READ_CONFIG + * Fix fc_get_cfg_parm() to be more robust and support embedded hex + values. The lpfc_param's are now defined as: + lpfc_log_verbose="lpfc:0,lpfc0:0x10,lpfc1:4,lpfc100:0xffff" The + "," delimter does not matter. It can be anything or not exist at + all. ie param = "lpfc:0lpfc0:0x10.lpfc1:4txtlpfc100:0xffff" will + also work. Additionally the string is treated as case + insensitive. + * Changed all usage of lpfc_find_lun_device() to lpfc_find_lun(). + * Removed unnecessary wrappers lpfc_find_lun_device() and + lpfc_tran_find_lun(). + * Switch from using internal bus/id/lun to similar data from + scsi_device structure. + * Eliminate one-line function lpfc_find_target() + * Added slave_alloc, slave_destory + * lpfc_scsi_cmd_start can now acquire lun pointer from + scsi_device->hostdata, which is setup in slave_alloc. + * Eliminate unnecessary checking on every cmd just to see if we + are accessing the device the first time. + * Remove assumption in lpfc_reset_lun_handler that a valid + lpfc_scsi_buf is hung off of linux's scsi_cmnd->host_scribble + when our reset is called. + +Changes from 20040507 to 20040515 + + * Changed version to 8.0.1 + * Fixed crash on driver rmmod after error injection tests and + lpfc_tasklet deadlock. + * Modified lpfc.conf to remove limit on number of support hosts + * Removed HBAAPI + * Removed duplication of SCSI opcodes from lpfc_fcp.h that are + available in scsi/scsi.h + * Rework module_param usage + * Added MODULE_PARAM_DESC for various module_params + * Removed #define EXPORT_SYMTAB + * Removed #includes of if_arp.h and rtnetlink.h + * Removed string "Open Source" from MODULE_DESC + * Cleanup duplicated string definitions used by MODULE_DESC + * Renamed lpfc_pci_[detect|release] to lpfc_pci_[probe|remove]_one + * Fix formatting of lpfc_driver + * Remove unnecessary memset to 0 of lpfcDRVR + * Attach driver attributes always unless pci_module_init failed + * Remove all one-line wrappers from lpfc_mem. + * Remove lpfc_sysfs_set_[show|store] as it is no longer needed + * Redo lpfc_sysfs_params_[show|store] to one value per attribute rule + * Breakdown lpfc_sysfs_info_show into smaller one value per attribute + * Use device attributes instead of driver attributes where appropriate + * Remove no longer needed EXPORT_SYMBOLs + * Remove some unused code (1600 msg's related) + +Changes from 20040429 to 20040507 + + * Change version to 8.0.0 + * Fix the number of cmd / rsp ring entries in lpfc_fcp.c to match + the divisions setup in lpfc_hw.h. + * Remove phba->iflag reference. + * Several locking improvements. + * Remove functions lpfc_drvr_init_lock, lpfc_drvr_lock, + lpfc_drvr_unlock and lpfc_hipri_*. + * Remove LPFC_DRVR_LOCK and LPFC_DRVR_UNLOCK macros. + * Make lpfc_info() use lpfc_get_hba_model_desc() instead of + rewriting almost identical code. + * Fix 1 overly long line in each of lpfc_cfgparm.h, lpfc_ftp.c and + lpfc_sli.c. + * Fix build for Red Hat 2.6.3 kernel by #defining MODULE_VERSION + only if it isn't already defined. + * Change elx_sli_issue_mbox_wait to return correct error code to + the caller. + * In some of the els completion routines, after calling + lpfc_elx_chk_latt, driver ignores the return code of the + lpfc_elx_chk_latt. This will prevent the discovery state machine + restarting correctly when there are link events in the middle of + discovery state machine running. Fix this by exiting discovery + state machine if lpfc_els_chk_latt returns a non zero value. + * Removed MAX_LPFC_BRDS from lpfc_diag.h + * Removed unused first_check. + * Remove some unused fields and defines. + * Change lpfc-param names to lpfc_param. + * Add use of MODULE_VERSION macro for 2.6 kernels. + * Shorten length of some of the comment lines to make them more + readable. + * Move FCP_* definitions to their own header file, lpfc_fcp.h. + * Remove unused prototypes from lpfc_crtn.h: fcptst, iptst, + lpfc_DELAYMS. + * Remove duplicated prototypes from lpfc_crtn.h: + lpfc_config_port_prep, lpfc_config_port_post, + lpfc_hba_down_prep. + * Removed some unused export_symbols. + * Install driver files into */drivers/scsi/lpfc instead of + */drivers/scsi. + +Changes from 20040426 to 20040429 + + * Declared export symbol lpfc_page_alloc and lpfc_page_free + * Changed lpfc version number to 6.98.3 + * Move the definition of MAX_LPFC_BRDS to the only header file + that uses it (lpfc_diag.h). + * Change lpfc_sli_wake_iocb_wait to do a regular wake_up since + lpfc_sli_issue_iocb_wait now sleeps uninterruptible. + * Replace list_for_each() with list_for_each_safe() when a list + element could be deleted. + * Fix IOCB memory leak + +Changes from 20040416 to 20040426 + + * Change lpfc_config_port_prep() to interpret word 4 of the DUMP + mbox response as a byte-count + * Add info attribute to sysfs + * Minor formatting (spaces to tabs) cleanup in lpfc_sched.h + * Remove unused log message number 732 + * Completing MODULE_PARM -> module_param changes + * Removed unused targetenable module parameter + * Removed locks from lpfc_sli_issue_mbox_wait routine + * Removed code that retry 29,00 check condition + * Removed code that manipulates rspSnsLen. + * Fix use of lun-q-depth config param + * Fix severity inconsistency with log message 249 + * Removed lpfc_max_target from lpfc_linux_attach + * Replace references to lpfcDRVR.pHba[] with lpfc_get_phba_by_inst() + * Change lpfc_param to lpfc-param + * Partially removed 32 HBA restriction within driver. Incorported + lpfc_instcnt, lpfc_instance[], and pHba[] into lpfcDRVR + structure Added routines lpfc_get_phba_by_inst() + lpfc_get_inst_by_phba() lpfc_check_valid_phba() + * Turn on attributes "set" & "params" by default. + * Further formatting/whitespace/line length cleanup on: lpfc_ct.c + lpfc_els.c lpfc_fcp.c lpfc_hbadisc.c lpfc_init.c lpfc_ipport.c + lpfc_mbox.c lpfc_nportdisc.c lpfc_sched.c lpfc_sched.h + lpfc_scsi.h lpfc_scsiport.c lpfc_sli.c and lpfc_sli.h + * Add log message 249 to log any unsupported device addressing + modes encountered. + * Add support for 256 targets and 256 LUNs + * Fixed panic in lpfc_linkdown. + * Removed (struct list_head*) casting in several calls to list_del + * Free irq reservation and kill running timers when insmod or + modprobe are killed via ctrl-c + * Remove drivers/scsi from include path + * Wrap use of log message 311 in macro + * Detect failure return from pci_map_sg call in lpfc_os_prep_io + * Fix use-after-free of IOCB in lpfc_sli_process_sol_iocb which + was causing an Oops on 2.6.5 kernel. + * Cleanup use of several gotos not used for error exit. + * Replace memcpy_toio() and memcpy_toio() with endian-dependent + lpfc_memcpy_to_slim() and lpfc_memcpy_from_slim() so that for + big endian hosts like PPC64, the SLIM is accessed 4 bytes at a + time instead of as a byte-stream. + +Changes from 20040409 to 20040416 + + * The scsi_register and scsi_alloc_host OS calls can fail and + return a zero-valued host pointer. A ctrl-C on 2.6 kernels + during driver load will cause this and the driver to panic. + Fixed this bug. Also found a bug in the error_x handling with + lpfc_sli_hba_down - it was in the wrong place and the driver + lock was not held, but needed to be (in lpfc_linux_attach) Fixed + both. Did some minor comment clean up. + * Removed unwanted (void *) castings. + * Replace define of INVALID_PHYS, with kernel 2.6.5's + dma_mapping_error() and add a inline function for earlier + kernels. Remove lpfc_bad_scatterlist(). + * Clean up formatting in hbaapi.h, lpfc.h, lpfc_cfgparm.h, + lpfc_crtn.h, lpfc_ct.c, lpfc_diag.h, lpfc_disc.h, lpfc_els.c, + lpfc_fcp.c, lpfc_hbadisc.c, lpfc_hw.h, lpfc_init.c, + lpfc_ipport.c, lpfc_logmsg.c, lpfc_logmsg.h and lpfc_scsiport.c + - mostly replacing groups of 8 spaces with hard tabs and keeping + lines to 80 column max.. + * Removed LPFC_DRVR_LOCK call from lpfc_unblock_requests for 2.4 + kernels. The lpfc_scsi_done routine already unlocks the driver + lock since it expects this lock to be held. + * Removed global lock capabilities from driver lock routines + * Remove SA_INTERRUPT flag from request_irq + * Move dma_addr_t cast inside of getPaddr macro as everywhere + getPaddr is used, the return is cast to dma_addr_t. + * Clean up formatting in lpfc_sli.c and lpfc_sysfs.c - mostly + replacing groups of 8 spaces with hard tabs and keeping lines + to 80 column max. + * Fix build for RHEL 2.1 BOOT kernels by always #including + interrupt.h in lpfc.h. + * Fix RHEL 3 build by #defining EXPORT_SYMTAB. + * Replace sprintf with snprintf in lpfc_proc_info. + * Fix build warnings on 2.6 kernels - remove no longer used calls + to character device initialization. + * Initial support code for discovery in tasklet conversion. + * Removing char interface and ioctl code. + * Change all elx prefixes to lpfc + * Replace lpfc_write_slim() & lpfc_read_slim() with memcpy_toio(), + memcpy_fromio(), writel() & readl(). + +Changes from 20040402 to 20040409 + + * Replaced lpfc_read_hbaregs_plus_offset and + lpfc_write_hbaregs_plus_offset functions with readl and writel. + * Get rid of long mdelay's in insmod path + * Changed the way our pci_device_id structures are initialized + * Replace lpfc_read/write_CA/HA/HC/HS with calls to readl() & + writel() directly. + * Increase SLI2_SLIM to 16K Increase cmd / rsp IOCBs accordingly + * Removed lpfc_els_chk_latt from the lpfc_config_post function. + lpfc_els_chk_latt will enable the link event interrupts when + flogi is pending which causes two discovery state machines + running parallely. + * Add pci_disable_device to unload path. + * Move lpfc_sleep_event from lpfc_fcp.c to lpfc_util_ioctl.c + * Call dma_map_single() & pci_map_single() directly instead of via + macro lpfc_pci_map(). Allow address 0 for PPC64. + * Change sleep to uninterruptible in lpfc_sli_issue_icob_wait + because this function doesn't handle signals. + * Move lpfc_wakeup_event from lpfc_fcp.c to lpfc_ioctl.c + * Remove unneeded #include + * Remove unused clock variables lpfc_clkCnt and lpfc_sec_clk. + * Get rid of capitalization of function names. + * Removed lpfc_addr_sprintf. + * Implemented gotos in lpfc_linux_attach for error cases. + * Replace mlist->dma.list = dmp->dma.list; to mlist = dmp. + * Remove functions lpfc_get_OsNameVersion and elx_wakeup. Change + elx_wakeup to wake_up_interruptible + * Add function lpfc_get_os_nameversion and change + lpfc_get_OsNameVersion to lpfc_get_os_nameversion. + * Remove lpfc_get_OsNameVersion + * Change driver name to a consistent lpfc in every visible place. + * Fix build warning: removed unused variable ret in lpfc_fdmi_tmo. + * Remove lpfc_utsname_nodename_check function + * Remove functions lpfc_register_intr and lpfc_unregister_intr + * Fill in owner field in lpfc_ops file_operations struct and + remove now unnecessary open and close entry points. + * Change function name prefixes from elx_ to lpfc_ + * Remove special case check for TUR in elx_os_prep_io() + * Renamed elx_scsi.h to lpfc_scsi.h + * Renamed elx_sched.h to lpfc_sched.h + * Renamed elx_mem.h to lpfc_mem.h + * Renamed elx_sli.h to lpfc_sli.h + * Renamed elx_logmsg.h to lpfc_logmsg.h + * Renamed elx.h to lpfc.h + * Renamed elx_sli.c to lpfc_sli.c + * Renamed elx_sched.c to lpfc_sched.c + * Renamed elx_mem.c to lpfc_mem.c + * Renamed elx_logmsg.c to lpfc_logmsg.c + * Renamed lpfcLINUXfcp.c lpfc_fcp.c + * Renamed elx_clock.c to lpfc_clock.c + * Reduce stack usage in lpfc_info(). + * Move lpip_stats structure from lpfc_hba.h to lpfc_ip.h. + * Move lpfc_stats and HBAEVT_t structures from lpfc_hba.h to + lpfc.h + * Remove lpfc_hba.h + * Remove duplicate rc definitions from + * Removed code which used next pointer to store mbox structure. + * Cleaned up list iterations. + * Removed non list manipulation of the next pointers. + * Change list_del()/INIT_LIST_HEAD sequences to list_del_init() + * In ELX_IOCBQ_t: Moved hipri_trigger field to iocb_flag. Combined + hipri_wait_queue and rsp_iocb in union + * Replaced casting from list_head with list_entry macro. + * Added ct_ndlp_context field to the ELX_IOCBQ_t. + * Do not use DMABUf_t list to store ndlp context + * Return 0 from lpfc_process_iotcl_util() when ELX_INITBRDS + succeeds. + * remove elx_os_scsiport.h + * Do not use DMABUf_t list to hold rpi context + * Replace elx_cfg_* names with lpfc_cfg-* + * Moved FCP activity to ring 0. Moved ELS/CT activity to ring 2. + * Clean up formatting of elx_sli.h (tabs for indents, 80 column + lines). + * Remove unused elxclock declaration in elx_sli.h. + * Since everywhere IOCB_ENTRY is used, the return value is cast, + move the cast into the macro. + * Split ioctls out into seperate files + +Changes from 20040326 to 20040402 + + * Updated ChangeLog for 20040402 SourceForge drop. + * Use safe list iterator for ndlp list + * Added code to return NLP_STE_FREED_NODE from the discovery + state machine functions if the node is freed from the + function. + * Fixes to DMABUF_t handling + * Fix for load error in discovery + * Remove loop_cnt variable from lpfc_rcv_plogi_unused_node. + * Remove nle. reference. + * Remove support for building 2.4 drivers + * Remove elx_util.h and replace elx_disc.h with lpfc_disc.h + * Implemented the Linux list macros in the discovery code. + Also moved elx_disc.h contents into lpfc_disc.h + * Unused variable cleanup + * Use Linux list macros for DMABUF_t + * Break up ioctls into 3 sections, dfc, util, hbaapi + rearranged code so this could be easily seperated into a + differnet module later All 3 are currently turned on by + defines in lpfc_ioctl.c LPFC_DFC_IOCTL, LPFC_UTIL_IOCTL, + LPFC_HBAAPI_IOCTL + * Misc cleanup: some goto's; add comments; clarify function + args + * Added code to use list macro for ELXSCSITARGET_t. + * New list implementation for ELX_MBOXQ_t + * Cleaned up some list_head casting. + * Put IPFC ifdef around two members of struct lpfc_nodelist. + * Cleaned up iocb list using list macros and list_head data + structure. + * lpfc_online() was missing some timer routines that were + started by lpfc_linux_attach(). These routines are now also + started by lpfc_online(). lpfc_offline() only stopped + els_timeout routine. It now stops all timeout routines + associated with that hba. + * Replace seperate next and prev pointers in struct + lpfc_bindlist with list_head type. In elxHBA_t, replace + fc_nlpbind_start and _end with fc_nlpbind_list and use + list_head macros to access it. + * Fix ulpStatus for aborting I/Os overlaps with newer firmware + ulpStatus values + * Rework params_show/store to be consistent as the other + routines. Remove generic'ness and rely on set attribute. + * Remove unused log message. + * Collapse elx_crtn.h and prod_crtn.h into lpfc_crtn.h + * Ifdef Scheduler specific routines + * Removed following ununsed ioclt's: ELX_READ_IOCB + ELX_READ_MEMSEG ELX_READ_BINFO ELX_READ_EINVAL ELX_READ_LHBA + ELX_READ_LXHBA ELX_SET ELX_DBG LPFC_TRACE + * Removed variable fc_dbg_flg + * Fixed a bug where HBA_Q_DEPTH was set incorrectly for + 3-digit HBAs. Also changed can_queue so midlayer will only + send (HBA_Q_DEPTH - 10) cmds. + * Clean up code in the error path, check condition. Remove + ununsed sense-related fields in lun structure. + * Added code for safety pools for following objects: mbuf/bpl, + mbox, iocb, ndlp, bind + * Wrapped '#include ' in '#ifdef USE_SCHEDULER'. + * Fixed 'make clean' target. + * Build now ignores elx_sched.o, and includes lpfc_sysfs.o. + * Wrapped lpfndd.o target in BUILD_IPFC ifdef. + * Removed elx_os.h inclusion in implementation files. + * Removed ELX_OS_IO_t data structure and put data direction + and non scatter/gather physical address into the scsi buffer + structure directly. Moved DRVR_LOCK, putPaddr, getPaddr + macros and some defines into elx.h since they are required + by the whole driver. + * Migrated following ioctls (debug) ELX_DISPLAY_PCI_ALL + ELX_DEVP ELX_READ_BPLIST ELX_RESET_QDEPTH ELX_STAT. + * Step 1 of attempt to move all Debug ioctls to sysfs. + Implemented the following IOCTLs in sysfs: ELX_WRITE_HC + ELX_WRITE_HS ELX_WRITE_HA ELX_WRITE_CA ELX_READ_HC + ELX_READ_HS ELX_READ_HA ELX_READ_CA ELX_READ_MB ELX_RESET + ELX_READ_HBA ELX_INSTANCE ELX_LIP. Also introduced + attribute "set" to be used in conjuction with the above + attributes. + * Removed DLINK, enque and deque declarations now that clock + doesn't use them anymore + * Separated install rule so that BUILD_IPFC has to be set when + make is called in order for the install rule to attempt to + copy the lpfndd.o driver. This change fixes a bug that + occurs because the install rule by default attempted to + install lpfndd.o, whereas the default make rule did not by + default build lpfndd.o. + * Keep track if hbaapi index numbers need to be refreshed. + * Removed prod_os.h from include list. + * Removed LPFC_LOCK and LPFC_UNLOCK macros. Added OS calls + into elx_os_scsiport.c. This file is now empty. + * Added spin_lock_irqsave and spin_unlock_irqrestore calls + into code directly and removed LPFC_LOCK_ and _UNLOCK_ + macros + * Remove references to "elx_clock.h" + * Added utsname.h to include list. The previous checkin to + elx_os.h removed its inclusion of utsname.h since there is + precious little in the file. However, lpfcLINUXfcp.c needs + it and now has it. + * Removed some commented-out code + * Removed elx_lck_t data structure, stray elxDRVR_t type, and + include from file. No longer used. + * Removed two PCI Sync defines. Removed includes - not + needed. Cleaned up macro lines. + * Added two functions from elxLINUXfcp.c. These functions + were IPFC specific. + * Removed hipri lock abstractions and added OS call into code. + Removed elx_lck_t and added spinlock_t directly. Moved two + IPFC functions into lpfc_ipport.c + * Moved IP specific structures to lpfc_ip.h file. + * lpfc_ipfarp_timeout() uses system timer. Remove all usages + of old internal clock support. + * Made changes to compile without IPFC support for the default + build. Added ifdef IPFC for all lpfc_ip.h includes. + * Patched elx_free_scsi_buf + * Removed elx_sched.o from 2.6 dependencies + * Reworked lpfc_pcimap. + * Use Linux swap macros to replace ELX swapping macros + (SWAP_SHORT, SWAP_LONG, SWAP_DATA, SWAP_DATA16, + PCIMEM_SHORT, PCIMEM_LONG, PCIMEM_DATA). + * move in_interrupt() check inside of elx_sleep_ms() + * Moved location of pci.h include. + * Restored elx_lck_t types in elxHBA_t. + * Removed elx_pci_dma_sync call. Also removed some PCI + defines from elx_hw.h and removed the spinlock_t locks that + are no longer used in elx.h + * elx_iodone() now uses system timer. + * elx_qfull_retry() now uses system timer. + * lpfc_put_buf(), lpfc_ip_xri_timeout() and + lpfc_ip_timeout_handler() now use system timer. + * lpfc_fdmi_tmo() and lpfc_qthrottle_up() now use system + timer. + * Removed num_bufs and num_iocbs configuration parameters. + * Fixed a memory corruption bug. This was caused by a memory + write to ndlp structure from lpfc_cmpl_els_acc function. + This ndlp structure was freed from lpfc_els_unsol_event. + * lpfc_disc_timeout() and lpfc_establish_link_tmo() now use + system timer. Also update lpfc_els_retry_delay() to do a + single lock release at the end. + * Remove use of PAN (pseudo adapter number). + * Reintroduced usage of the cross compiler for building on + ppc64 to remove build errors that were cropping up when + using the standard gcc compiler. + * Fix no-unlock-before return in lpfc_els_retry_delay which was + causing a deadlock on insmod in some environments. + * Minor format changes fix up comments + * Create utility clock function elx_start_timer() and + elx_stop_timer(). All timeout routines now use these common + routines. + * Minor formating changes fix up comments + * Minor formatting changes get rid of failover defines for + syntax checking + * Minor formatting changes remove ISCSI defines. + * Fix typo in install target for 2.4 kernels. + * Removed unused elx_scsi_add_timer extern function + declaration. + * Cleanup casting around DMA masks. + * Comment out lpfndd.o modules_install section as lpfndd.o is + not generated if CONFIG_NET_LPFC is not set. Also refer to + BASEINCLUDE only in out of kernel source module builds as it + will not exist otherwise. + * Removed unused malloc counters from lpfcLINUXfcp.c. + * Remove some unnecessary #includes in lpfcLINUXfcp.c + * Remove unncessary #includes in elxLINUXfcp.c + * Minor formatting cleanups in Makefile to avoid some + linewrapping. + * Removed unused elx_mem_pool data structure. + * Remove several unnecessary #includes. + * Moving fix for memory leak in ioctl lip area to sysfs's lip. + * Removed unused elx_dma_handle_t elx_acc_handle_t + FC_MAX_SEGSZ and FC_MAX_POOL. + * Rewrite of Makefile. Fixes breakages with make -j4 during + kernel compile. Does not recompile all files on every + build. Uses the kernel build's definitions of CFLAGS, + MODFLAGS etc. Removed "make rpm" option. + * Removed unused #defines CLOSED, DEAD, OPENED, NORMAL_OPEN + and unneeded #include of elx_sched.h in elx.h. + * Several log message updates + * Add PCI_DEVICE_ID_FIREFLY for LP6000 + * Fixed known issues in 20040326: driver crashes on rmmod in + both 2.4 and 2.6 kernels + + +Changes from 20040319 to 20040326 + + * Updated ChangeLog for 20040326 SourceForge drop. + * remove lpfc_isr / lpfc_tmr logic fixed up 8 spaces from + previous checkins with tabs + * replace elx_in_intr() with in_interrupt() + * Remove unused messages 1602 and 1603. + * Fix the following issues with log messages: Remove unused + messages 406, 407, 409, 927, 928, 1201, 1202, 1204, 1205, 1206 + and 1207. Create a new message 738 to fix duplicate instances + of 736. + * Removed remaining pci interface abstractions from elxLINUXfcp.c. + Implemented OS calls directly in all remaining files and cleaned + up modules. Removed prototypes as well. + * Removed following functions/structures elx_mem_dmapool + elx_idx_dmapool elx_size_dmapool elx_kmem_lock dfc_data_alloc + dfc_data_free dfc_mem struct mbuf_info elx_acc_handle_t + data_handle elx_dma_handle_t dma_handle struct elx_memseg + MEMSEG_t + * lpfc_els_timeout_handler() now uses system timer. + * Further cleanup of #ifdef powerpc + * lpfc_scsi_timeout_handler() now uses system timer. + * Replace common driver's own defines for endianess w/ Linux's + __BIG_ENDIAN etc. + * Added #ifdef IPFC for all IPFC specific code. + * lpfc_disc_retry_rptlun() now uses system timer. + * lpfc_npr_timeout() now uses system timer. + * Modified detect code, on insmod, to only wait a max of 2 secs if + link comes up and there are no devices. + * Move remaining message logging functions into + elx_logmsg.c/elx_logmsg.h. + * Added code to clear link attention bit when there is a pending + link event and the memory allocation for read_la mail box + command fails. + * Removed function calls for mapping bar registers and allocating + kernel virtual memory mappings to the mapped bars Removed + prototypes, lpfc_driver_cache_line, and pci_bar1_map rename to + pci_bar2_map. + * Allocate mbox only if the hba_state is in ready state. + * Complete lip support via sysfs. To lip, echo brdnum > + /sys/bus/pci/drivers/lpfc/lip. + * moving sysfs show/store implementations to lpfc_sysfs.c. Also add + support for lip. + * Add files: lpfc_sysfs.c, lpfc_sysfs.h + * move LPFC_DRIVER_NAME and LPFC_MODULE_DESC out of lpfcLINUXfcp.c + to lpfc_version.h, since it is now needed in lpfc_sysfs.c + * elx_mbox_timeout now uses system timer + * Changed lpfc_nodev_timeout, lpfc_els_retry_delay and + lpfc_linkdown_timeout to use the system timer instead of + internal clock support. + * Move remaining message logging functions in elx_util.c to + elx_logmsg.c. + * Remove some unnecessary typecasting. + * Remove log message that is no longer used (was used by + elx_str_atox). + * Replaced DLINK_t and SLINK_t by standard Linux list_head + * Removed deque macro + * Replaced ELX_DLINK_t ans ELX_SLINK_t by Linux struct list_head + (except for clock) + * Removed following functions from code: linux_kmalloc linux_kfree + elx_alloc_bigbuf elx_free_bigbuf + * Removed following abstract functions from the code. elx_malloc + elx_free elx_ip_get_rcv_buf elx_ip_free_rcv_buf + elx_mem_alloc_dmabuf elx_mem_alloc_dmabufext elx_mem_alloc_dma + elx_mem_alloc_buf lpfc_bufmap + * Removed custom PCI configuration #defines and replaced with + OS-provided #defines. Also added linux/pci.h to *.c files. + * Remove elx_str_ctox. Replace elx_str_atox with sscanf. + * Many indentation/whitespace fixes. + * Replace elx_str_ctox with isxdigit where it was only used to + check the value of a character. + * Removed following functions from the code. elx_kmem_free + elx_kmem_alloc elx_kmem_zalloc + * Change use of 2.4 SCSI typedef Scsi_Host_Template to struct + scsi_host_template for 2.6 kernels. + * Change use of 2.4 SCSI typedefs (Scsi_Device, Scsi_Cmnd, + Scsi_Request) the their real struct names. + * Move 2.6 compatibility irqreturn definitions to lpfc_compat.h. + Protect these definitions from conflicting with similar ones in + later 2.4 kernels. + * Remove unused definitions: LINUX_TGT_t, LINUX_LUN_t, + LINUX_BUF_t, elx_lun_t, SET_ADAPTER_STATUS. + * Convert pci_ calls to linux 2.6 dma_ equivalents. + * Removed unused types: struct buf, struct sc_buf, T_SCSIBUF + typedef. + * Fix Makefile so that 2.4 drivers don't always rebuild all files. + * Remove unused _static_ and fc_lun_t definitions. + * Cleaned up some memory pool implementation code. + * Fix panic with char dev changes. Turns out that 2.6.4 code does + the same in kernel space with the 2.4 interface style + definitions. So remove the new char dev code altogether. + * Remove typecasting from fc_get_cfg_param and consolidate + multiple instances of the parameter switch into a single + instance. + * Use lpfc_is_LC_HBA() macro that tests pcidev->device directly + instead of saving a private copy that undergoes varied shifting + & casting. + * Removed usage of all memory pools. + +Changes from 20040312 to 20040319 + + * Use dev_warn instead of printk for 2.6 kernels + * Correct Iocbq completion routine for 2.6 kernel case + * Change void *pOSCmd to Scsi_Smnd *pCmd + * Change void *pOScmd to struct sk_buff *pCmd + * Remove data directon code. + * Removed memory pool for buf/bpl buffers and use kmalloc/kfree + pci_pool_alloc/free directly. + * Move PPC check for DMA address 0 in scatter-gather list, into + lpfc_compat.h + * Always use pci_unmap_single() instead of pci_unmap_page() + * Clean up the 2.6 vs 2.4 #if blocks. + * Conditionalize Scheduler + * Add a comment to explain a little what the first Makefile + section does. + * Removed lpfc_intr_post + * Sysfs new display format. Also added write functionality. You + can [ echo "0 log_verbose 3" > + /sys/bus/pci/drivers/lpfc/params]. Hex support yet to be added. + * Removed several #ifdef powerpc, including for a discovery issue + in lpfc_ValidLun() + * Change elx_printf_log to use vsprintf. + * Added lpfc_compat.h provides macros to aid compilation in the + Linux 2.4 kernel over various platform architectures. Initially + support mapping to a DMA address. + * Removed memory pool for nlp/bind buffers and use kmalloc/kfree + directly. + * Removed memory pool for iocb buffers and use kmalloc/kfree + directly. + * Removed memory pool for mailbox buffers and use kmalloc/kfree + directly. + * Cleaned up back and forth casts + * Initial support for sysfs for 2.6 kernel. + * Changed elx_dma_addr_t to dma_addr_t + * Fix a 2.6 kernel check to be >= 2.6.0 instead of > (was missing + 2.6.0). + * Remove elx_printf and elx_str_sprintf. Replace elx_print with + printk. + * Replace elx_printf with printk. + * Replace elx_str_sprintf with sprintf. + * Removed the mem_lock, its prototype, function, macro, and + iflags. + * Use kmalloc/kfree for ELX_SCSI_BUF_t + * Use linux pci_pools for SCSI_DMA_EXT + * Use linux pci_pools for BPLs. + * Minor cleanup of DFC args for PPC64. + * Several small indentation cleanups. + * New Linux 2.6 style of char device registration. + * Migrated members of LPFCHBA_t and LINUX_HBA_t into elxHBA_t + * Use strcpy, strncmp, isdigit, strlen instead of abstractions + * Cleanup of driver_template. + * Facilitate compile time turn on/off of lpfc_network_on. + * Split large source files into smaller, better named ones. + +Changes from 2.10a to 20040312 + + * Fix build for 2.4 kernels + * Move driver version macros into lpfc_version.h file. + * Fixed data miscompare with LIP. + * Removed elx_sli, elx_ioc, elx_disc, elx_sch routines, + prototypes, and reference points. + * Correct the space insertions with hardtabs + * Remove routine call pointers in ELX_SLI_INIT_t struct. + * Removed module locks except for drvr, mem, and clock. + * Removed unused module locks from sourcebase. Kept drvr_lock, + mem_lock, and clock_lock. + * Change NULL to 0 diff --git a/Documentation/scsi/lpfc.txt b/Documentation/scsi/lpfc.txt new file mode 100644 index 000000000..4dbe41370 --- /dev/null +++ b/Documentation/scsi/lpfc.txt @@ -0,0 +1,83 @@ + +LPFC Driver Release Notes: + +============================================================================= + + + IMPORTANT: + + Starting in the 8.0.17 release, the driver began to be targeted strictly + toward the upstream kernel. As such, we removed #ifdefs for older kernels + (pre 2.6.10). The 8.0.16 release should be used if the driver is to be + run on one of the older kernels. + + The proposed modifications to the transport layer for FC remote ports + and extended attribute support is now part of the upstream kernel + as of 2.6.12. We no longer need to provide patches for this support, + nor a *full* version which has old an new kernel support. + + The driver now requires a 2.6.12 (if pre-release, 2.6.12-rc1) or later + kernel. + + Please heed these dependencies.... + + + ******************************************************************** + + +The following information is provided for additional background on the +history of the driver as we push for upstream acceptance. + +Cable pull and temporary device Loss: + + In older revisions of the lpfc driver, the driver internally queued i/o + received from the midlayer. In the cases where a cable was pulled, link + jitter, or a device temporarily loses connectivity (due to its cable + being removed, a switch rebooting, or a device reboot), the driver could + hide the disappearance of the device from the midlayer. I/O's issued to + the LLDD would simply be queued for a short duration, allowing the device + to reappear or link come back alive, with no inadvertant side effects + to the system. If the driver did not hide these conditions, i/o would be + errored by the driver, the mid-layer would exhaust its retries, and the + device would be taken offline. Manual intervention would be required to + re-enable the device. + + The community supporting kernel.org has driven an effort to remove + internal queuing from all LLDDs. The philosophy is that internal + queuing is unnecessary as the block layer already performs the + queuing. Removing the queues from the LLDD makes a more predictable + and more simple LLDD. + + As a potential new addition to kernel.org, the 8.x driver was asked to + have all internal queuing removed. Emulex complied with this request. + In explaining the impacts of this change, Emulex has worked with the + community in modifying the behavior of the SCSI midlayer so that SCSI + devices can be temporarily suspended while transport events (such as + those described) can occur. + + The proposed patch was posted to the linux-scsi mailing list. The patch + is contained in the 2.6.10-rc2 (and later) patch kits. As such, this + patch is part of the standard 2.6.10 kernel. + + By default, the driver expects the patches for block/unblock interfaces + to be present in the kernel. No #define needs to be set to enable support. + + +Kernel Support + + This source package is targeted for the upstream kernel only. (See notes + at the top of this file). It relies on interfaces that are slowing + migrating into the kernel.org kernel. + + At this time, the driver requires the 2.6.12 (if pre-release, 2.6.12-rc1) + kernel. + + If a driver is needed for older kernels please utilize the 8.0.16 + driver sources. + + +Patches + + Thankfully, at this time, patches are not needed. + + diff --git a/Documentation/sound/alsa/VIA82xx-mixer.txt b/Documentation/sound/alsa/VIA82xx-mixer.txt new file mode 100644 index 000000000..1b0ac06ba --- /dev/null +++ b/Documentation/sound/alsa/VIA82xx-mixer.txt @@ -0,0 +1,8 @@ + + VIA82xx mixer + ============= + +On many VIA82xx boards, the 'Input Source Select' mixer control does not work. +Setting it to 'Input2' on such boards will cause recording to hang, or fail +with EIO (input/output error) via OSS emulation. This control should be left +at 'Input1' for such cards. diff --git a/Documentation/sound/alsa/hda_codec.txt b/Documentation/sound/alsa/hda_codec.txt new file mode 100644 index 000000000..e9d07b8f1 --- /dev/null +++ b/Documentation/sound/alsa/hda_codec.txt @@ -0,0 +1,299 @@ +Notes on Universal Interface for Intel High Definition Audio Codec +------------------------------------------------------------------ + +Takashi Iwai + + +[Still a draft version] + + +General +======= + +The snd-hda-codec module supports the generic access function for the +High Definition (HD) audio codecs. It's designed to be independent +from the controller code like ac97 codec module. The real accessors +from/to the controller must be implemented in the lowlevel driver. + +The structure of this module is similar with ac97_codec module. +Each codec chip belongs to a bus class which communicates with the +controller. + + +Initialization of Bus Instance +============================== + +The card driver has to create struct hda_bus at first. The template +struct should be filled and passed to the constructor: + +struct hda_bus_template { + void *private_data; + struct pci_dev *pci; + const char *modelname; + struct hda_bus_ops ops; +}; + +The card driver can set and use the private_data field to retrieve its +own data in callback functions. The pci field is used when the patch +needs to check the PCI subsystem IDs, so on. For non-PCI system, it +doesn't have to be set, of course. +The modelname field specifies the board's specific configuration. The +string is passed to the codec parser, and it depends on the parser how +the string is used. +These fields, private_data, pci and modelname are all optional. + +The ops field contains the callback functions as the following: + +struct hda_bus_ops { + int (*command)(struct hda_codec *codec, hda_nid_t nid, int direct, + unsigned int verb, unsigned int parm); + unsigned int (*get_response)(struct hda_codec *codec); + void (*private_free)(struct hda_bus *); +}; + +The command callback is called when the codec module needs to send a +VERB to the controller. It's always a single command. +The get_response callback is called when the codec requires the answer +for the last command. These two callbacks are mandatory and have to +be given. +The last, private_free callback, is optional. It's called in the +destructor to release any necessary data in the lowlevel driver. + +The bus instance is created via snd_hda_bus_new(). You need to pass +the card instance, the template, and the pointer to store the +resultant bus instance. + +int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp, + struct hda_bus **busp); + +It returns zero if successful. A negative return value means any +error during creation. + + +Creation of Codec Instance +========================== + +Each codec chip on the board is then created on the BUS instance. +To create a codec instance, call snd_hda_codec_new(). + +int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, + struct hda_codec **codecp); + +The first argument is the BUS instance, the second argument is the +address of the codec, and the last one is the pointer to store the +resultant codec instance (can be NULL if not needed). + +The codec is stored in a linked list of bus instance. You can follow +the codec list like: + + struct list_head *p; + struct hda_codec *codec; + list_for_each(p, &bus->codec_list) { + codec = list_entry(p, struct hda_codec, list); + ... + } + +The codec isn't initialized at this stage properly. The +initialization sequence is called when the controls are built later. + + +Codec Access +============ + +To access codec, use snd_codec_read() and snd_codec_write(). +snd_hda_param_read() is for reading parameters. +For writing a sequence of verbs, use snd_hda_sequence_write(). + +To retrieve the number of sub nodes connected to the given node, use +snd_hda_get_sub_nodes(). The connection list can be obtained via +snd_hda_get_connections() call. + +When an unsolicited event happens, pass the event via +snd_hda_queue_unsol_event() so that the codec routines will process it +later. + + +(Mixer) Controls +================ + +To create mixer controls of all codecs, call +snd_hda_build_controls(). It then builds the mixers and does +initialization stuff on each codec. + + +PCM Stuff +========= + +snd_hda_build_pcms() gives the necessary information to create PCM +streams. When it's called, each codec belonging to the bus stores +codec->num_pcms and codec->pcm_info fields. The num_pcms indicates +the number of elements in pcm_info array. The card driver is supposed +to traverse the codec linked list, read the pcm information in +pcm_info array, and build pcm instances according to them. + +The pcm_info array contains the following record: + +/* PCM information for each substream */ +struct hda_pcm_stream { + unsigned int substreams; /* number of substreams, 0 = not exist */ + unsigned int channels_min; /* min. number of channels */ + unsigned int channels_max; /* max. number of channels */ + hda_nid_t nid; /* default NID to query rates/formats/bps, or set up */ + u32 rates; /* supported rates */ + u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */ + unsigned int maxbps; /* supported max. bit per sample */ + struct hda_pcm_ops ops; +}; + +/* for PCM creation */ +struct hda_pcm { + char *name; + struct hda_pcm_stream stream[2]; +}; + +The name can be passed to snd_pcm_new(). The stream field contains +the information for playback (SNDRV_PCM_STREAM_PLAYBACK = 0) and +capture (SNDRV_PCM_STREAM_CAPTURE = 1) directions. The card driver +should pass substreams to snd_pcm_new() for the number of substreams +to create. + +The channels_min, channels_max, rates and formats should be copied to +runtime->hw record. They and maxbps fields are used also to compute +the format value for the HDA codec and controller. Call +snd_hda_calc_stream_format() to get the format value. + +The ops field contains the following callback functions: + +struct hda_pcm_ops { + int (*open)(struct hda_pcm_stream *info, struct hda_codec *codec, + snd_pcm_substream_t *substream); + int (*close)(struct hda_pcm_stream *info, struct hda_codec *codec, + snd_pcm_substream_t *substream); + int (*prepare)(struct hda_pcm_stream *info, struct hda_codec *codec, + unsigned int stream_tag, unsigned int format, + snd_pcm_substream_t *substream); + int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec, + snd_pcm_substream_t *substream); +}; + +All are non-NULL, so you can call them safely without NULL check. + +The open callback should be called in PCM open after runtime->hw is +set up. It may override some setting and constraints additionally. +Similarly, the close callback should be called in the PCM close. + +The prepare callback should be called in PCM prepare. This will set +up the codec chip properly for the operation. The cleanup should be +called in hw_free to clean up the configuration. + +The caller should check the return value, at least for open and +prepare callbacks. When a negative value is returned, some error +occurred. + + +Proc Files +========== + +Each codec dumps the widget node information in +/proc/asound/card*/codec#* file. This information would be really +helpful for debugging. Please provide its contents together with the +bug report. + + +Power Management +================ + +It's simple: +Call snd_hda_suspend() in the PM suspend callback. +Call snd_hda_resume() in the PM resume callback. + + +Codec Preset (Patch) +==================== + +To set up and handle the codec functionality fully, each codec may +have a codec preset (patch). It's defined in struct hda_codec_preset: + + struct hda_codec_preset { + unsigned int id; + unsigned int mask; + unsigned int subs; + unsigned int subs_mask; + unsigned int rev; + const char *name; + int (*patch)(struct hda_codec *codec); + }; + +When the codec id and codec subsystem id match with the given id and +subs fields bitwise (with bitmask mask and subs_mask), the callback +patch is called. The patch callback should initialize the codec and +set the codec->patch_ops field. This is defined as below: + + struct hda_codec_ops { + int (*build_controls)(struct hda_codec *codec); + int (*build_pcms)(struct hda_codec *codec); + int (*init)(struct hda_codec *codec); + void (*free)(struct hda_codec *codec); + void (*unsol_event)(struct hda_codec *codec, unsigned int res); + #ifdef CONFIG_PM + int (*suspend)(struct hda_codec *codec, pm_message_t state); + int (*resume)(struct hda_codec *codec); + #endif + }; + +The build_controls callback is called from snd_hda_build_controls(). +Similarly, the build_pcms callback is called from +snd_hda_build_pcms(). The init callback is called after +build_controls to initialize the hardware. +The free callback is called as a destructor. + +The unsol_event callback is called when an unsolicited event is +received. + +The suspend and resume callbacks are for power management. + +Each entry can be NULL if not necessary to be called. + + +Generic Parser +============== + +When the device doesn't match with any given presets, the widgets are +parsed via th generic parser (hda_generic.c). Its support is +limited: no multi-channel support, for example. + + +Digital I/O +=========== + +Call snd_hda_create_spdif_out_ctls() from the patch to create controls +related with SPDIF out. In the patch resume callback, call +snd_hda_resume_spdif(). + + +Helper Functions +================ + +snd_hda_get_codec_name() stores the codec name on the given string. + +snd_hda_check_board_config() can be used to obtain the configuration +information matching with the device. Define the table with struct +hda_board_config entries (zero-terminated), and pass it to the +function. The function checks the modelname given as a module +parameter, and PCI subsystem IDs. If the matching entry is found, it +returns the config field value. + +snd_hda_add_new_ctls() can be used to create and add control entries. +Pass the zero-terminated array of snd_kcontrol_new_t. The same array +can be passed to snd_hda_resume_ctls() for resume. +Note that this will call control->put callback of these entries. So, +put callback should check codec->in_resume and force to restore the +given value if it's non-zero even if the value is identical with the +cached value. + +Macros HDA_CODEC_VOLUME(), HDA_CODEC_MUTE() and their variables can be +used for the entry of snd_kcontrol_new_t. + +The input MUX helper callbacks for such a control are provided, too: +snd_hda_input_mux_info() and snd_hda_input_mux_put(). See +patch_realtek.c for example. diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig new file mode 100644 index 000000000..692af6b5e --- /dev/null +++ b/arch/arm/common/Kconfig @@ -0,0 +1,24 @@ +config ICST525 + bool + +config ICST307 + bool + +config SA1111 + bool + select DMABOUNCE + +config DMABOUNCE + bool + +config TIMER_ACORN + bool + +config SHARP_LOCOMO + bool + +config SHARP_PARAM + bool + +config SHARP_SCOOP + bool diff --git a/arch/arm/common/sharpsl_param.c b/arch/arm/common/sharpsl_param.c new file mode 100644 index 000000000..c2c557a22 --- /dev/null +++ b/arch/arm/common/sharpsl_param.c @@ -0,0 +1,60 @@ +/* + * Hardware parameter area specific to Sharp SL series devices + * + * Copyright (c) 2005 Richard Purdie + * + * Based on Sharp's 2.4 kernel patches + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include + +/* + * Certain hardware parameters determined at the time of device manufacture, + * typically including LCD parameters are loaded by the bootloader at the + * address PARAM_BASE. As the kernel will overwrite them, we need to store + * them early in the boot process, then pass them to the appropriate drivers. + * Not all devices use all paramaters but the format is common to all. + */ +#ifdef ARCH_SA1100 +#define PARAM_BASE 0xe8ffc000 +#else +#define PARAM_BASE 0xa0000a00 +#endif +#define MAGIC_CHG(a,b,c,d) ( ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a ) + +#define COMADJ_MAGIC MAGIC_CHG('C','M','A','D') +#define UUID_MAGIC MAGIC_CHG('U','U','I','D') +#define TOUCH_MAGIC MAGIC_CHG('T','U','C','H') +#define AD_MAGIC MAGIC_CHG('B','V','A','D') +#define PHAD_MAGIC MAGIC_CHG('P','H','A','D') + +struct sharpsl_param_info sharpsl_param; + +void sharpsl_save_param(void) +{ + memcpy(&sharpsl_param, (void *)PARAM_BASE, sizeof(struct sharpsl_param_info)); + + if (sharpsl_param.comadj_keyword != COMADJ_MAGIC) + sharpsl_param.comadj=-1; + + if (sharpsl_param.phad_keyword != PHAD_MAGIC) + sharpsl_param.phadadj=-1; + + if (sharpsl_param.uuid_keyword != UUID_MAGIC) + sharpsl_param.uuid[0]=-1; + + if (sharpsl_param.touch_keyword != TOUCH_MAGIC) + sharpsl_param.touch_xp=-1; + + if (sharpsl_param.adadj_keyword != AD_MAGIC) + sharpsl_param.adadj=-1; +} + + diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S new file mode 100644 index 000000000..d7cb1bfa5 --- /dev/null +++ b/arch/arm/mm/abort-macro.S @@ -0,0 +1,42 @@ +/* + * The ARM LDRD and Thumb LDRSB instructions use bit 20/11 (ARM/Thumb) + * differently than every other instruction, so it is set to 0 (write) + * even though the instructions are read instructions. This means that + * during an abort the instructions will be treated as a write and the + * handler will raise a signal from unwriteable locations if they + * fault. We have to specifically check for these instructions + * from the abort handlers to treat them properly. + * + */ + + .macro do_thumb_abort + tst r3, #PSR_T_BIT + beq not_thumb + ldrh r3, [r2] @ Read aborted Thumb instruction + and r3, r3, # 0xfe00 @ Mask opcode field + cmp r3, # 0x5600 @ Is it ldrsb? + orreq r3, r3, #1 << 11 @ Set L-bit if yes + tst r3, #1 << 11 @ L = 0 -> write + orreq r1, r1, #1 << 11 @ yes. + mov pc, lr +not_thumb: + .endm + +/* + * We check for the following insturction encoding for LDRD. + * + * [27:25] == 0 + * [7:4] == 1101 + * [20] == 0 + */ + .macro do_ldrd_abort + tst r3, #0x0e000000 @ [27:25] == 0 + bne not_ldrd + and r2, r3, #0x000000f0 @ [7:4] == 1101 + cmp r2, #0x000000d0 + bne not_ldrd + tst r3, #1 << 20 @ [20] == 0 + moveq pc, lr +not_ldrd: + .endm + diff --git a/arch/frv/Kconfig.debug b/arch/frv/Kconfig.debug new file mode 100644 index 000000000..0034b6549 --- /dev/null +++ b/arch/frv/Kconfig.debug @@ -0,0 +1,74 @@ +menu "Kernel hacking" + +source "lib/Kconfig.debug" + +config EARLY_PRINTK + bool "Early printk" + depends on EMBEDDED && DEBUG_KERNEL + default n + help + Write kernel log output directly into the VGA buffer or to a serial + port. + + This is useful for kernel debugging when your machine crashes very + early before the console code is initialized. For normal operation + it is not recommended because it looks ugly and doesn't cooperate + with klogd/syslogd or the X server. You should normally N here, + unless you want to debug such a crash. + +config DEBUG_STACKOVERFLOW + bool "Check for stack overflows" + depends on DEBUG_KERNEL + +config DEBUG_PAGEALLOC + bool "Page alloc debugging" + depends on DEBUG_KERNEL + help + Unmap pages from the kernel linear mapping after free_pages(). + This results in a large slowdown, but helps to find certain types + of memory corruptions. + +config GDBSTUB + bool "Remote GDB kernel debugging" + depends on DEBUG_KERNEL + select DEBUG_INFO + select FRAME_POINTER + help + If you say Y here, it will be possible to remotely debug the kernel + using gdb. This enlarges your kernel ELF image disk size by several + megabytes and requires a machine with more than 16 MB, better 32 MB + RAM to avoid excessive linking time. This is only useful for kernel + hackers. If unsure, say N. + +choice + prompt "GDB stub port" + default GDBSTUB_UART1 + depends on GDBSTUB + help + Select the on-CPU port used for GDB-stub + +config GDBSTUB_UART0 + bool "/dev/ttyS0" + +config GDBSTUB_UART1 + bool "/dev/ttyS1" + +endchoice + +config GDBSTUB_IMMEDIATE + bool "Break into GDB stub immediately" + depends on GDBSTUB + help + If you say Y here, GDB stub will break into the program as soon as + possible, leaving the program counter at the beginning of + start_kernel() in init/main.c. + +config GDB_CONSOLE + bool "Console output to GDB" + depends on GDBSTUB + help + If you are using GDB for remote debugging over a serial port and + would like kernel messages to be formatted into GDB $O packets so + that GDB prints them as program output, say 'Y'. + +endmenu diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S new file mode 100644 index 000000000..9e77d1360 --- /dev/null +++ b/arch/i386/kernel/syscall_table.S @@ -0,0 +1,299 @@ +.data +ENTRY(sys_call_table) + .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ + .long sys_exit + .long sys_fork + .long sys_read + .long sys_write + .long sys_open /* 5 */ + .long sys_close + .long sys_waitpid + .long sys_creat + .long sys_link + .long sys_unlink /* 10 */ + .long sys_execve + .long sys_chdir + .long sys_time + .long sys_mknod + .long sys_chmod /* 15 */ + .long sys_lchown16 + .long sys_ni_syscall /* old break syscall holder */ + .long sys_stat + .long sys_lseek + .long sys_getpid /* 20 */ + .long sys_mount + .long sys_oldumount + .long sys_setuid16 + .long sys_getuid16 + .long sys_stime /* 25 */ + .long sys_ptrace + .long sys_alarm + .long sys_fstat + .long sys_pause + .long sys_utime /* 30 */ + .long sys_ni_syscall /* old stty syscall holder */ + .long sys_ni_syscall /* old gtty syscall holder */ + .long sys_access + .long sys_nice + .long sys_ni_syscall /* 35 - old ftime syscall holder */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir + .long sys_rmdir /* 40 */ + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* old prof syscall holder */ + .long sys_brk /* 45 */ + .long sys_setgid16 + .long sys_getgid16 + .long sys_signal + .long sys_geteuid16 + .long sys_getegid16 /* 50 */ + .long sys_acct + .long sys_umount /* recycled never used phys() */ + .long sys_ni_syscall /* old lock syscall holder */ + .long sys_ioctl + .long sys_fcntl /* 55 */ + .long sys_ni_syscall /* old mpx syscall holder */ + .long sys_setpgid + .long sys_ni_syscall /* old ulimit syscall holder */ + .long sys_olduname + .long sys_umask /* 60 */ + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid + .long sys_getpgrp /* 65 */ + .long sys_setsid + .long sys_sigaction + .long sys_sgetmask + .long sys_ssetmask + .long sys_setreuid16 /* 70 */ + .long sys_setregid16 + .long sys_sigsuspend + .long sys_sigpending + .long sys_sethostname + .long sys_setrlimit /* 75 */ + .long sys_old_getrlimit + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday + .long sys_getgroups16 /* 80 */ + .long sys_setgroups16 + .long old_select + .long sys_symlink + .long sys_lstat + .long sys_readlink /* 85 */ + .long sys_uselib + .long sys_swapon + .long sys_reboot + .long old_readdir + .long old_mmap /* 90 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod + .long sys_fchown16 /* 95 */ + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* old profil syscall holder */ + .long sys_statfs + .long sys_fstatfs /* 100 */ + .long sys_ioperm + .long sys_socketcall + .long sys_syslog + .long sys_setitimer + .long sys_getitimer /* 105 */ + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_uname + .long sys_iopl /* 110 */ + .long sys_vhangup + .long sys_ni_syscall /* old "idle" system call */ + .long sys_vm86old + .long sys_wait4 + .long sys_swapoff /* 115 */ + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn + .long sys_clone /* 120 */ + .long sys_setdomainname + .long sys_newuname + .long sys_modify_ldt + .long sys_adjtimex + .long sys_mprotect /* 125 */ + .long sys_sigprocmask + .long sys_ni_syscall /* old "create_module" */ + .long sys_init_module + .long sys_delete_module + .long sys_ni_syscall /* 130: old "get_kernel_syms" */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush + .long sys_sysfs /* 135 */ + .long sys_personality + .long sys_ni_syscall /* reserved for afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 + .long sys_llseek /* 140 */ + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_msync + .long sys_readv /* 145 */ + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam + .long sys_sched_getparam /* 155 */ + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max + .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_mremap + .long sys_setresuid16 + .long sys_getresuid16 /* 165 */ + .long sys_vm86 + .long sys_ni_syscall /* Old sys_query_module */ + .long sys_poll + .long sys_nfsservctl + .long sys_setresgid16 /* 170 */ + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn + .long sys_rt_sigaction + .long sys_rt_sigprocmask /* 175 */ + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend + .long sys_pread64 /* 180 */ + .long sys_pwrite64 + .long sys_chown16 + .long sys_getcwd + .long sys_capget + .long sys_capset /* 185 */ + .long sys_sigaltstack + .long sys_sendfile + .long sys_ni_syscall /* reserved for streams1 */ + .long sys_ni_syscall /* reserved for streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ + .long sys_lstat64 + .long sys_fstat64 + .long sys_lchown + .long sys_getuid + .long sys_getgid /* 200 */ + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid + .long sys_getgroups /* 205 */ + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid + .long sys_setresgid /* 210 */ + .long sys_getresgid + .long sys_chown + .long sys_setuid + .long sys_setgid + .long sys_setfsuid /* 215 */ + .long sys_setfsgid + .long sys_pivot_root + .long sys_mincore + .long sys_madvise + .long sys_getdents64 /* 220 */ + .long sys_fcntl64 +#ifdef CONFIG_TUX + .long __sys_tux +#else +# ifdef CONFIG_TUX_MODULE + .long sys_tux +# else + .long sys_ni_syscall +# endif +#endif + .long sys_ni_syscall + .long sys_gettid + .long sys_readahead /* 225 */ + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr + .long sys_getxattr + .long sys_lgetxattr /* 230 */ + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr + .long sys_flistxattr + .long sys_removexattr /* 235 */ + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_tkill + .long sys_sendfile64 + .long sys_futex /* 240 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_set_thread_area + .long sys_get_thread_area + .long sys_io_setup /* 245 */ + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel + .long sys_fadvise64 /* 250 */ + .long sys_ni_syscall + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 255 */ + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + .long sys_tgkill /* 270 */ + .long sys_utimes + .long sys_fadvise64_64 + .long sys_ni_syscall /* sys_vserver */ + .long sys_mbind + .long sys_get_mempolicy + .long sys_set_mempolicy + .long sys_mq_open + .long sys_mq_unlink + .long sys_mq_timedsend + .long sys_mq_timedreceive /* 280 */ + .long sys_mq_notify + .long sys_mq_getsetattr + .long sys_ni_syscall /* reserved for kexec */ + .long sys_waitid + .long sys_ni_syscall /* 285 */ /* available */ + .long sys_add_key + .long sys_request_key + .long sys_keyctl diff --git a/arch/i386/kernel/vsyscall-note.S b/arch/i386/kernel/vsyscall-note.S new file mode 100644 index 000000000..d4b5be4f3 --- /dev/null +++ b/arch/i386/kernel/vsyscall-note.S @@ -0,0 +1,25 @@ +/* + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. + * Here we can supply some information useful to userland. + */ + +#include +#include + +#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \ + .section name, flags; \ + .balign 4; \ + .long 1f - 0f; /* name length */ \ + .long 3f - 2f; /* data length */ \ + .long type; /* note type */ \ +0: .asciz vendor; /* vendor name */ \ +1: .balign 4; \ +2: + +#define ASM_ELF_NOTE_END \ +3: .balign 4; /* pad out section */ \ + .previous + + ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0) + .long LINUX_VERSION_CODE + ASM_ELF_NOTE_END diff --git a/arch/i386/lib/putuser.S b/arch/i386/lib/putuser.S new file mode 100644 index 000000000..a32d9f570 --- /dev/null +++ b/arch/i386/lib/putuser.S @@ -0,0 +1,87 @@ +/* + * __put_user functions. + * + * (C) Copyright 2005 Linus Torvalds + * + * These functions have a non-standard call interface + * to make them more efficient, especially as they + * return an error value in addition to the "real" + * return value. + */ +#include + + +/* + * __put_user_X + * + * Inputs: %eax[:%edx] contains the data + * %ecx contains the address + * + * Outputs: %eax is error code (0 or -EFAULT) + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +#define ENTER pushl %ebx ; GET_THREAD_INFO(%ebx) +#define EXIT popl %ebx ; ret + +.text +.align 4 +.globl __put_user_1 +__put_user_1: + ENTER + cmpl TI_addr_limit(%ebx),%ecx + jae bad_put_user +1: movb %al,(%ecx) + xorl %eax,%eax + EXIT + +.align 4 +.globl __put_user_2 +__put_user_2: + ENTER + movl TI_addr_limit(%ebx),%ebx + subl $1,%ebx + cmpl %ebx,%ecx + jae bad_put_user +2: movw %ax,(%ecx) + xorl %eax,%eax + EXIT + +.align 4 +.globl __put_user_4 +__put_user_4: + ENTER + movl TI_addr_limit(%ebx),%ebx + subl $3,%ebx + cmpl %ebx,%ecx + jae bad_put_user +3: movl %eax,(%ecx) + xorl %eax,%eax + EXIT + +.align 4 +.globl __put_user_8 +__put_user_8: + ENTER + movl TI_addr_limit(%ebx),%ebx + subl $7,%ebx + cmpl %ebx,%ecx + jae bad_put_user +4: movl %eax,(%ecx) +5: movl %edx,4(%ecx) + xorl %eax,%eax + EXIT + +bad_put_user: + movl $-14,%eax + EXIT + +.section __ex_table,"a" + .long 1b,bad_put_user + .long 2b,bad_put_user + .long 3b,bad_put_user + .long 4b,bad_put_user + .long 5b,bad_put_user +.previous diff --git a/arch/ia64/sn/kernel/xp_main.c b/arch/ia64/sn/kernel/xp_main.c new file mode 100644 index 000000000..3be52a34c --- /dev/null +++ b/arch/ia64/sn/kernel/xp_main.c @@ -0,0 +1,289 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * Cross Partition (XP) base. + * + * XP provides a base from which its users can interact + * with XPC, yet not be dependent on XPC. + * + */ + + +#include +#include +#include +#include +#include +#include + + +/* + * Target of nofault PIO read. + */ +u64 xp_nofault_PIOR_target; + + +/* + * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level + * users of XPC. + */ +struct xpc_registration xpc_registrations[XPC_NCHANNELS]; + + +/* + * Initialize the XPC interface to indicate that XPC isn't loaded. + */ +static enum xpc_retval xpc_notloaded(void) { return xpcNotLoaded; } + +struct xpc_interface xpc_interface = { + (void (*)(int)) xpc_notloaded, + (void (*)(int)) xpc_notloaded, + (enum xpc_retval (*)(partid_t, int, u32, void **)) xpc_notloaded, + (enum xpc_retval (*)(partid_t, int, void *)) xpc_notloaded, + (enum xpc_retval (*)(partid_t, int, void *, xpc_notify_func, void *)) + xpc_notloaded, + (void (*)(partid_t, int, void *)) xpc_notloaded, + (enum xpc_retval (*)(partid_t, void *)) xpc_notloaded +}; + + +/* + * XPC calls this when it (the XPC module) has been loaded. + */ +void +xpc_set_interface(void (*connect)(int), + void (*disconnect)(int), + enum xpc_retval (*allocate)(partid_t, int, u32, void **), + enum xpc_retval (*send)(partid_t, int, void *), + enum xpc_retval (*send_notify)(partid_t, int, void *, + xpc_notify_func, void *), + void (*received)(partid_t, int, void *), + enum xpc_retval (*partid_to_nasids)(partid_t, void *)) +{ + xpc_interface.connect = connect; + xpc_interface.disconnect = disconnect; + xpc_interface.allocate = allocate; + xpc_interface.send = send; + xpc_interface.send_notify = send_notify; + xpc_interface.received = received; + xpc_interface.partid_to_nasids = partid_to_nasids; +} + + +/* + * XPC calls this when it (the XPC module) is being unloaded. + */ +void +xpc_clear_interface(void) +{ + xpc_interface.connect = (void (*)(int)) xpc_notloaded; + xpc_interface.disconnect = (void (*)(int)) xpc_notloaded; + xpc_interface.allocate = (enum xpc_retval (*)(partid_t, int, u32, + void **)) xpc_notloaded; + xpc_interface.send = (enum xpc_retval (*)(partid_t, int, void *)) + xpc_notloaded; + xpc_interface.send_notify = (enum xpc_retval (*)(partid_t, int, void *, + xpc_notify_func, void *)) xpc_notloaded; + xpc_interface.received = (void (*)(partid_t, int, void *)) + xpc_notloaded; + xpc_interface.partid_to_nasids = (enum xpc_retval (*)(partid_t, void *)) + xpc_notloaded; +} + + +/* + * Register for automatic establishment of a channel connection whenever + * a partition comes up. + * + * Arguments: + * + * ch_number - channel # to register for connection. + * func - function to call for asynchronous notification of channel + * state changes (i.e., connection, disconnection, error) and + * the arrival of incoming messages. + * key - pointer to optional user-defined value that gets passed back + * to the user on any callouts made to func. + * payload_size - size in bytes of the XPC message's payload area which + * contains a user-defined message. The user should make + * this large enough to hold their largest message. + * nentries - max #of XPC message entries a message queue can contain. + * The actual number, which is determined when a connection + * is established and may be less then requested, will be + * passed to the user via the xpcConnected callout. + * assigned_limit - max number of kthreads allowed to be processing + * messages (per connection) at any given instant. + * idle_limit - max number of kthreads allowed to be idle at any given + * instant. + */ +enum xpc_retval +xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size, + u16 nentries, u32 assigned_limit, u32 idle_limit) +{ + struct xpc_registration *registration; + + + DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + DBUG_ON(payload_size == 0 || nentries == 0); + DBUG_ON(func == NULL); + DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit); + + registration = &xpc_registrations[ch_number]; + + if (down_interruptible(®istration->sema) != 0) { + return xpcInterrupted; + } + + /* if XPC_CHANNEL_REGISTERED(ch_number) */ + if (registration->func != NULL) { + up(®istration->sema); + return xpcAlreadyRegistered; + } + + /* register the channel for connection */ + registration->msg_size = XPC_MSG_SIZE(payload_size); + registration->nentries = nentries; + registration->assigned_limit = assigned_limit; + registration->idle_limit = idle_limit; + registration->key = key; + registration->func = func; + + up(®istration->sema); + + xpc_interface.connect(ch_number); + + return xpcSuccess; +} + + +/* + * Remove the registration for automatic connection of the specified channel + * when a partition comes up. + * + * Before returning this xpc_disconnect() will wait for all connections on the + * specified channel have been closed/torndown. So the caller can be assured + * that they will not be receiving any more callouts from XPC to their + * function registered via xpc_connect(). + * + * Arguments: + * + * ch_number - channel # to unregister. + */ +void +xpc_disconnect(int ch_number) +{ + struct xpc_registration *registration; + + + DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS); + + registration = &xpc_registrations[ch_number]; + + /* + * We've decided not to make this a down_interruptible(), since we + * figured XPC's users will just turn around and call xpc_disconnect() + * again anyways, so we might as well wait, if need be. + */ + down(®istration->sema); + + /* if !XPC_CHANNEL_REGISTERED(ch_number) */ + if (registration->func == NULL) { + up(®istration->sema); + return; + } + + /* remove the connection registration for the specified channel */ + registration->func = NULL; + registration->key = NULL; + registration->nentries = 0; + registration->msg_size = 0; + registration->assigned_limit = 0; + registration->idle_limit = 0; + + xpc_interface.disconnect(ch_number); + + up(®istration->sema); + + return; +} + + +int __init +xp_init(void) +{ + int ret, ch_number; + u64 func_addr = *(u64 *) xp_nofault_PIOR; + u64 err_func_addr = *(u64 *) xp_error_PIOR; + + + if (!ia64_platform_is("sn2")) { + return -ENODEV; + } + + /* + * Register a nofault code region which performs a cross-partition + * PIO read. If the PIO read times out, the MCA handler will consume + * the error and return to a kernel-provided instruction to indicate + * an error. This PIO read exists because it is guaranteed to timeout + * if the destination is down (AMO operations do not timeout on at + * least some CPUs on Shubs <= v1.2, which unfortunately we have to + * work around). + */ + if ((ret = sn_register_nofault_code(func_addr, err_func_addr, + err_func_addr, 1, 1)) != 0) { + printk(KERN_ERR "XP: can't register nofault code, error=%d\n", + ret); + } + /* + * Setup the nofault PIO read target. (There is no special reason why + * SH_IPI_ACCESS was selected.) + */ + if (is_shub2()) { + xp_nofault_PIOR_target = SH2_IPI_ACCESS0; + } else { + xp_nofault_PIOR_target = SH1_IPI_ACCESS; + } + + /* initialize the connection registration semaphores */ + for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++) { + sema_init(&xpc_registrations[ch_number].sema, 1); /* mutex */ + } + + return 0; +} +module_init(xp_init); + + +void __exit +xp_exit(void) +{ + u64 func_addr = *(u64 *) xp_nofault_PIOR; + u64 err_func_addr = *(u64 *) xp_error_PIOR; + + + /* unregister the PIO read nofault code region */ + (void) sn_register_nofault_code(func_addr, err_func_addr, + err_func_addr, 1, 0); +} +module_exit(xp_exit); + + +MODULE_AUTHOR("Silicon Graphics, Inc."); +MODULE_DESCRIPTION("Cross Partition (XP) base"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(xp_nofault_PIOR); +EXPORT_SYMBOL(xp_nofault_PIOR_target); +EXPORT_SYMBOL(xpc_registrations); +EXPORT_SYMBOL(xpc_interface); +EXPORT_SYMBOL(xpc_clear_interface); +EXPORT_SYMBOL(xpc_set_interface); +EXPORT_SYMBOL(xpc_connect); +EXPORT_SYMBOL(xpc_disconnect); + diff --git a/arch/ia64/sn/kernel/xp_nofault.S b/arch/ia64/sn/kernel/xp_nofault.S new file mode 100644 index 000000000..b77254305 --- /dev/null +++ b/arch/ia64/sn/kernel/xp_nofault.S @@ -0,0 +1,31 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2004-2005 Silicon Graphics, Inc. All Rights Reserved. + */ + + +/* + * The xp_nofault_PIOR function takes a pointer to a remote PIO register + * and attempts to load and consume a value from it. This function + * will be registered as a nofault code block. In the event that the + * PIO read fails, the MCA handler will force the error to look + * corrected and vector to the xp_error_PIOR which will return an error. + * + * extern int xp_nofault_PIOR(void *remote_register); + */ + + .global xp_nofault_PIOR +xp_nofault_PIOR: + mov r8=r0 // Stage a success return value + ld8.acq r9=[r32];; // PIO Read the specified register + adds r9=1,r9 // Add to force a consume + br.ret.sptk.many b0;; // Return success + + .global xp_error_PIOR +xp_error_PIOR: + mov r8=1 // Return value of 1 + br.ret.sptk.many b0;; // Return failure + diff --git a/arch/ppc/configs/hdpu_defconfig b/arch/ppc/configs/hdpu_defconfig new file mode 100644 index 000000000..956a17897 --- /dev/null +++ b/arch/ppc/configs/hdpu_defconfig @@ -0,0 +1,890 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11 +# Wed Mar 16 12:43:19 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_LOCK_KERNEL=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_HOTPLUG=y +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +# CONFIG_CPUSETS is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y + +# +# Processor +# +CONFIG_6xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E500 is not set +CONFIG_ALTIVEC=y +# CONFIG_TAU is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_PM is not set +CONFIG_PPC_STD_MMU=y +# CONFIG_NOT_COHERENT_CACHE is not set + +# +# Platform options +# +# CONFIG_PPC_MULTIPLATFORM is not set +# CONFIG_APUS is not set +# CONFIG_KATANA is not set +# CONFIG_WILLOW is not set +# CONFIG_CPCI690 is not set +# CONFIG_PCORE is not set +# CONFIG_POWERPMC250 is not set +# CONFIG_CHESTNUT is not set +# CONFIG_SPRUCE is not set +CONFIG_HDPU=y +# CONFIG_EV64260 is not set +# CONFIG_LOPEC is not set +# CONFIG_MCPN765 is not set +# CONFIG_MVME5100 is not set +# CONFIG_PPLUS is not set +# CONFIG_PRPMC750 is not set +# CONFIG_PRPMC800 is not set +# CONFIG_SANDPOINT is not set +# CONFIG_RADSTONE_PPC7D is not set +# CONFIG_ADIR is not set +# CONFIG_K2 is not set +# CONFIG_PAL4 is not set +# CONFIG_GEMINI is not set +# CONFIG_EST8260 is not set +# CONFIG_SBC82xx is not set +# CONFIG_SBS8260 is not set +# CONFIG_RPX8260 is not set +# CONFIG_TQM8260 is not set +# CONFIG_ADS8272 is not set +# CONFIG_PQ2FADS is not set +# CONFIG_LITE5200 is not set +# CONFIG_MPC834x_SYS is not set +CONFIG_MV64360=y +CONFIG_MV64X60=y + +# +# Set bridge options +# +CONFIG_MV64X60_BASE=0xf1000000 +CONFIG_MV64X60_NEW_BASE=0xf1000000 +# CONFIG_SMP is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_NR_CPUS is not set +CONFIG_PREEMPT=y +CONFIG_HIGHMEM=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="root=/dev/nfs ip=auto" + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +CONFIG_ADVANCED_OPTIONS=y +# CONFIG_HIGHMEM_START_BOOL is not set +CONFIG_HIGHMEM_START=0xfe000000 +# CONFIG_LOWMEM_SIZE_BOOL is not set +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START_BOOL=y +CONFIG_KERNEL_START=0x80000000 +# CONFIG_TASK_SIZE_BOOL is not set +CONFIG_TASK_SIZE=0x80000000 +# CONFIG_BOOT_LOAD_BOOL is not set +CONFIG_BOOT_LOAD=0x00800000 + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_START=0xfc000000 +CONFIG_MTD_PHYSMAP_LEN=0x04000000 +CONFIG_MTD_PHYSMAP_BANKWIDTH=4 + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_LBD is not set +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI Transport Attributes +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +CONFIG_SCSI_AIC7XXX=y +CONFIG_AIC7XXX_CMDS_PER_DEVICE=32 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000 +# CONFIG_AIC7XXX_DEBUG_ENABLE is not set +CONFIG_AIC7XXX_DEBUG_MASK=0 +# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +# CONFIG_NET_TULIP is not set +# CONFIG_HP100 is not set +# CONFIG_NET_PCI is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +CONFIG_MV643XX_ETH=y +CONFIG_MV643XX_ETH_0=y +# CONFIG_MV643XX_ETH_1 is not set +# CONFIG_MV643XX_ETH_2 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_MPSC=y +CONFIG_SERIAL_MPSC_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +CONFIG_FS_POSIX_ACL=y + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=y +CONFIG_UDF_NLS=y + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_FS_NOR_ECC is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +CONFIG_NFS_DIRECTIO=y +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_TCP=y +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_SERIAL_TEXT_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/configs/mpc834x_sys_defconfig b/arch/ppc/configs/mpc834x_sys_defconfig new file mode 100644 index 000000000..4a5522ca8 --- /dev/null +++ b/arch/ppc/configs/mpc834x_sys_defconfig @@ -0,0 +1,644 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11-rc4 +# Thu Feb 17 16:12:23 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +# CONFIG_KALLSYMS is not set +CONFIG_FUTEX=y +# CONFIG_EPOLL is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Processor +# +CONFIG_6xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E500 is not set +# CONFIG_CPU_FREQ is not set +CONFIG_PPC_GEN550=y +CONFIG_83xx=y + +# +# Freescale 83xx options +# +CONFIG_MPC834x_SYS=y +CONFIG_MPC834x=y +CONFIG_PPC_STD_MMU=y + +# +# Platform options +# +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_HIGHMEM is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_CMDLINE_BOOL is not set + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +# CONFIG_PCI is not set +# CONFIG_PCI_DOMAINS is not set + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# PC-card bridges +# + +# +# Advanced setup +# +# CONFIG_ADVANCED_OPTIONS is not set + +# +# Default settings for advanced configuration options are used +# +CONFIG_HIGHMEM_START=0xfe000000 +CONFIG_LOWMEM_SIZE=0x30000000 +CONFIG_KERNEL_START=0xc0000000 +CONFIG_TASK_SIZE=0x80000000 +CONFIG_BOOT_LOAD=0x00800000 + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_LBD is not set +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_SCSI is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# + +# +# IEEE 1394 (FireWire) support +# + +# +# I2O device support +# + +# +# Macintosh device drivers +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y + +# +# Ethernet (1000 Mbit) +# +CONFIG_GIANFAR=y +# CONFIG_GFAR_NAPI is not set + +# +# Ethernet (10000 Mbit) +# + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ISA is not set +CONFIG_I2C_MPC=y +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB_ARCH_HAS_HCD is not set +# CONFIG_USB_ARCH_HAS_OHCI is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +# CONFIG_CRC_CCITT is not set +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_SERIAL_TEXT_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/configs/radstone_ppc7d_defconfig b/arch/ppc/configs/radstone_ppc7d_defconfig new file mode 100644 index 000000000..7f6467e77 --- /dev/null +++ b/arch/ppc/configs/radstone_ppc7d_defconfig @@ -0,0 +1,956 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.11 +# Tue Mar 15 14:31:19 2005 +# +CONFIG_MMU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_HAVE_DEC_LOCK=y +CONFIG_PPC=y +CONFIG_PPC32=y +CONFIG_GENERIC_NVRAM=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_CLEAN_COMPILE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set +# CONFIG_HOTPLUG is not set +CONFIG_KOBJECT_UEVENT=y +# CONFIG_IKCONFIG is not set +CONFIG_EMBEDDED=y +CONFIG_KALLSYMS=y +CONFIG_KALLSYMS_EXTRA_PASS=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SHMEM=y +CONFIG_CC_ALIGN_FUNCTIONS=0 +CONFIG_CC_ALIGN_LABELS=0 +CONFIG_CC_ALIGN_LOOPS=0 +CONFIG_CC_ALIGN_JUMPS=0 +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_KMOD=y + +# +# Processor +# +CONFIG_6xx=y +# CONFIG_40x is not set +# CONFIG_44x is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set +# CONFIG_8xx is not set +# CONFIG_E500 is not set +CONFIG_ALTIVEC=y +# CONFIG_TAU is not set +# CONFIG_CPU_FREQ is not set +CONFIG_PPC_GEN550=y +# CONFIG_PM is not set +CONFIG_PPC_STD_MMU=y +# CONFIG_NOT_COHERENT_CACHE is not set + +# +# Platform options +# +# CONFIG_PPC_MULTIPLATFORM is not set +# CONFIG_APUS is not set +# CONFIG_KATANA is not set +# CONFIG_WILLOW is not set +# CONFIG_CPCI690 is not set +# CONFIG_PCORE is not set +# CONFIG_POWERPMC250 is not set +# CONFIG_CHESTNUT is not set +# CONFIG_SPRUCE is not set +# CONFIG_EV64260 is not set +# CONFIG_LOPEC is not set +# CONFIG_MCPN765 is not set +# CONFIG_MVME5100 is not set +# CONFIG_PPLUS is not set +# CONFIG_PRPMC750 is not set +# CONFIG_PRPMC800 is not set +# CONFIG_SANDPOINT is not set +CONFIG_RADSTONE_PPC7D=y +# CONFIG_ADIR is not set +# CONFIG_K2 is not set +# CONFIG_PAL4 is not set +# CONFIG_GEMINI is not set +# CONFIG_EST8260 is not set +# CONFIG_SBC82xx is not set +# CONFIG_SBS8260 is not set +# CONFIG_RPX8260 is not set +# CONFIG_TQM8260 is not set +# CONFIG_ADS8272 is not set +# CONFIG_PQ2FADS is not set +# CONFIG_LITE5200 is not set +# CONFIG_MPC834x_SYS is not set +CONFIG_MV64360=y +CONFIG_MV64X60=y + +# +# Set bridge options +# +CONFIG_MV64X60_BASE=0xfef00000 +CONFIG_MV64X60_NEW_BASE=0xfef00000 +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_HIGHMEM is not set +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0,9600" + +# +# Bus options +# +CONFIG_GENERIC_ISA_DMA=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# PCCARD (PCMCIA/CardBus) support +# +# CONFIG_PCCARD is not set + +# +# Advanced setup +# +CONFIG_ADVANCED_OPTIONS=y +CONFIG_HIGHMEM_START=0xfe000000 +# CONFIG_LOWMEM_SIZE_BOOL is not set +CONFIG_LOWMEM_SIZE=0x30000000 +# CONFIG_KERNEL_START_BOOL is not set +CONFIG_KERNEL_START=0xc0000000 +# CONFIG_TASK_SIZE_BOOL is not set +CONFIG_TASK_SIZE=0x80000000 +# CONFIG_BOOT_LOAD_BOOL is not set +CONFIG_BOOT_LOAD=0x00800000 + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_CONCAT is not set +# CONFIG_MTD_PARTITIONS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_FTL=y +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_GEOMETRY is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_XIP is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PHYSMAP is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_SX8 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_LBD is not set +# CONFIG_CDROM_PKTCDVD is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +# CONFIG_ATA_OVER_ETH is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI Transport Attributes +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +CONFIG_BRIDGE=y +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=y +# CONFIG_TULIP_MWI is not set +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +CONFIG_R8169=y +CONFIG_R8169_NAPI=y +CONFIG_SK98LIN=y +# CONFIG_VIA_VELOCITY is not set +CONFIG_TIGON3=y +CONFIG_MV643XX_ETH=y +CONFIG_MV643XX_ETH_0=y +CONFIG_MV643XX_ETH_1=y +# CONFIG_MV643XX_ETH_2 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_S2IO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set +# CONFIG_NETCONSOLE is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_XTKBD=y +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +# CONFIG_SERIAL_8250_EXTENDED is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_MPSC=y +# CONFIG_SERIAL_MPSC_CONSOLE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_MV64XXX=y + +# +# Hardware Sensors Chip support +# +CONFIG_I2C_SENSOR=y +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +CONFIG_SENSORS_LM90=y +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83627HF is not set + +# +# Other I2C Chip support +# +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Dallas's 1-wire bus +# +# CONFIG_W1 is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +# CONFIG_FB is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARCH_HAS_OHCI=y +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# MMC/SD Card support +# +# CONFIG_MMC is not set + +# +# InfiniBand support +# +# CONFIG_INFINIBAND is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set + +# +# XFS support +# +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_DNOTIFY=y +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_XATTR is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_NAND is not set +# CONFIG_JFFS2_FS_NOR_ECC is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set +CONFIG_JFFS2_ZLIB=y +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_NFSD is not set +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +# CONFIG_NLS is not set + +# +# Library routines +# +CONFIG_CRC_CCITT=y +CONFIG_CRC32=y +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_SERIAL_TEXT_DEBUG is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set + +# +# Hardware crypto devices +# diff --git a/arch/ppc/platforms/83xx/Makefile b/arch/ppc/platforms/83xx/Makefile new file mode 100644 index 000000000..eb55341d6 --- /dev/null +++ b/arch/ppc/platforms/83xx/Makefile @@ -0,0 +1,4 @@ +# +# Makefile for the PowerPC 83xx linux kernel. +# +obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o diff --git a/arch/ppc/syslib/m82xx_pci.h b/arch/ppc/syslib/m82xx_pci.h new file mode 100644 index 000000000..924f73f8e --- /dev/null +++ b/arch/ppc/syslib/m82xx_pci.h @@ -0,0 +1,92 @@ + +#ifndef _PPC_KERNEL_M82XX_PCI_H +#define _PPC_KERNEL_M82XX_PCI_H + +#include +/* + * Local->PCI map (from CPU) controlled by + * MPC826x master window + * + * 0xF6000000 - 0xF7FFFFFF IO space + * 0x80000000 - 0xBFFFFFFF CPU2PCI memory space PCIBR0 + * + * 0x80000000 - 0x9FFFFFFF PCI Mem with prefetch (Outbound ATU #1) + * 0xA0000000 - 0xBFFFFFFF PCI Mem w/o prefetch (Outbound ATU #2) + * 0xF6000000 - 0xF7FFFFFF 32-bit PCI IO (Outbound ATU #3) + * + * PCI->Local map (from PCI) + * MPC826x slave window controlled by + * + * 0x00000000 - 0x07FFFFFF MPC826x local memory (Inbound ATU #1) + */ + +/* + * Slave window that allows PCI masters to access MPC826x local memory. + * This window is set up using the first set of Inbound ATU registers + */ + +#ifndef M82xx_PCI_SLAVE_MEM_LOCAL +#define M82xx_PCI_SLAVE_MEM_LOCAL (((struct bd_info *)__res)->bi_memstart) +#define M82xx_PCI_SLAVE_MEM_BUS (((struct bd_info *)__res)->bi_memstart) +#define M82xx_PCI_SLAVE_MEM_SIZE (((struct bd_info *)__res)->bi_memsize) +#endif + +/* + * This is the window that allows the CPU to access PCI address space. + * It will be setup with the SIU PCIBR0 register. All three PCI master + * windows, which allow the CPU to access PCI prefetch, non prefetch, + * and IO space (see below), must all fit within this window. + */ + +#ifndef M82xx_PCI_LOWER_MEM +#define M82xx_PCI_LOWER_MEM 0x80000000 +#define M82xx_PCI_UPPER_MEM 0x9fffffff +#define M82xx_PCI_MEM_OFFSET 0x00000000 +#define M82xx_PCI_MEM_SIZE 0x20000000 +#endif + +#ifndef M82xx_PCI_LOWER_MMIO +#define M82xx_PCI_LOWER_MMIO 0xa0000000 +#define M82xx_PCI_UPPER_MMIO 0xafffffff +#define M82xx_PCI_MMIO_OFFSET 0x00000000 +#define M82xx_PCI_MMIO_SIZE 0x20000000 +#endif + +#ifndef M82xx_PCI_LOWER_IO +#define M82xx_PCI_LOWER_IO 0x00000000 +#define M82xx_PCI_UPPER_IO 0x01ffffff +#define M82xx_PCI_IO_BASE 0xf6000000 +#define M82xx_PCI_IO_SIZE 0x02000000 +#endif + +#ifndef M82xx_PCI_PRIM_WND_SIZE +#define M82xx_PCI_PRIM_WND_SIZE ~(M82xx_PCI_IO_SIZE - 1U) +#define M82xx_PCI_PRIM_WND_BASE (M82xx_PCI_IO_BASE) +#endif + +#ifndef M82xx_PCI_SEC_WND_SIZE +#define M82xx_PCI_SEC_WND_SIZE ~(M82xx_PCI_MEM_SIZE + M82xx_PCI_MMIO_SIZE - 1U) +#define M82xx_PCI_SEC_WND_BASE (M82xx_PCI_LOWER_MEM) +#endif + +#ifndef POTA_ADDR_SHIFT +#define POTA_ADDR_SHIFT 12 +#endif + +#ifndef PITA_ADDR_SHIFT +#define PITA_ADDR_SHIFT 12 +#endif + +#ifndef _IO_BASE +#define _IO_BASE isa_io_base +#endif + +#ifdef CONFIG_8260_PCI9 +struct pci_controller; +extern void setup_m8260_indirect_pci(struct pci_controller* hose, + u32 cfg_addr, u32 cfg_data); +#else +#define setup_m8260_indirect_pci setup_indirect_pci +#endif + +#endif /* _PPC_KERNEL_M8260_PCI_H */ diff --git a/arch/sh64/kernel/module.c b/arch/sh64/kernel/module.c new file mode 100644 index 000000000..2598f6b88 --- /dev/null +++ b/arch/sh64/kernel/module.c @@ -0,0 +1,161 @@ +/* Kernel module help for sh64. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Copyright 2004 SuperH (UK) Ltd + Author: Richard Curnow + + Based on the sh version, and on code from the sh64-specific parts of + modutils, originally written by Richard Curnow and Ben Gaster. + +*/ +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + Elf32_Addr relocation; + uint32_t *location; + int align; + int is_shmedia; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rel[i].r_offset; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM(rel[i].r_info); + relocation = sym->st_value + rel[i].r_addend; + align = (int)location & 3; + + /* For text addresses, bit2 of the st_other field indicates + * whether the symbol is SHmedia (1) or SHcompact (0). If + * SHmedia, the LSB of the symbol needs to be asserted + * for the CPU to be in SHmedia mode when it starts executing + * the branch target. */ + is_shmedia = (sym->st_other & 4) ? 1 : 0; + if (is_shmedia) { + relocation |= 1; + } + + switch (ELF32_R_TYPE(rel[i].r_info)) { + case R_SH_DIR32: + DEBUGP("R_SH_DIR32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); + *location += relocation; + break; + case R_SH_REL32: + DEBUGP("R_SH_REL32 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); + relocation -= (Elf32_Addr) location; + *location += relocation; + break; + case R_SH_IMM_LOW16: + DEBUGP("R_SH_IMM_LOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); + *location = (*location & ~0x3fffc00) | + ((relocation & 0xffff) << 10); + break; + case R_SH_IMM_MEDLOW16: + DEBUGP("R_SH_IMM_MEDLOW16 @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); + *location = (*location & ~0x3fffc00) | + (((relocation >> 16) & 0xffff) << 10); + break; + case R_SH_IMM_LOW16_PCREL: + DEBUGP("R_SH_IMM_LOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); + relocation -= (Elf32_Addr) location; + *location = (*location & ~0x3fffc00) | + ((relocation & 0xffff) << 10); + break; + case R_SH_IMM_MEDLOW16_PCREL: + DEBUGP("R_SH_IMM_MEDLOW16_PCREL @%08lx = %08lx\n", (unsigned long) location, (unsigned long) relocation); + relocation -= (Elf32_Addr) location; + *location = (*location & ~0x3fffc00) | + (((relocation >> 16) & 0xffff) << 10); + break; + default: + printk(KERN_ERR "module %s: Unknown relocation: %u\n", + me->name, ELF32_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: REL RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} + diff --git a/arch/sparc64/lib/csum_copy.S b/arch/sparc64/lib/csum_copy.S new file mode 100644 index 000000000..71af48839 --- /dev/null +++ b/arch/sparc64/lib/csum_copy.S @@ -0,0 +1,308 @@ +/* csum_copy.S: Checksum+copy code for sparc64 + * + * Copyright (C) 2005 David S. Miller + */ + +#ifdef __KERNEL__ +#define GLOBAL_SPARE %g7 +#else +#define GLOBAL_SPARE %g5 +#endif + +#ifndef EX_LD +#define EX_LD(x) x +#endif + +#ifndef EX_ST +#define EX_ST(x) x +#endif + +#ifndef EX_RETVAL +#define EX_RETVAL(x) x +#endif + +#ifndef LOAD +#define LOAD(type,addr,dest) type [addr], dest +#endif + +#ifndef STORE +#define STORE(type,src,addr) type src, [addr] +#endif + +#ifndef FUNC_NAME +#define FUNC_NAME csum_partial_copy_nocheck +#endif + + .register %g2, #scratch + .register %g3, #scratch + + .text + +90: + /* We checked for zero length already, so there must be + * at least one byte. + */ + be,pt %icc, 1f + nop + EX_LD(LOAD(ldub, %o0 + 0x00, %o4)) + add %o0, 1, %o0 + sub %o2, 1, %o2 + EX_ST(STORE(stb, %o4, %o1 + 0x00)) + add %o1, 1, %o1 +1: andcc %o0, 0x2, %g0 + be,pn %icc, 80f + cmp %o2, 2 + blu,pn %icc, 60f + nop + EX_LD(LOAD(lduh, %o0 + 0x00, %o5)) + add %o0, 2, %o0 + sub %o2, 2, %o2 + EX_ST(STORE(sth, %o5, %o1 + 0x00)) + add %o1, 2, %o1 + ba,pt %xcc, 80f + add %o5, %o4, %o4 + + .globl FUNC_NAME +FUNC_NAME: /* %o0=src, %o1=dst, %o2=len, %o3=sum */ + LOAD(prefetch, %o0 + 0x000, #n_reads) + xor %o0, %o1, %g1 + clr %o4 + andcc %g1, 0x3, %g0 + bne,pn %icc, 95f + LOAD(prefetch, %o0 + 0x040, #n_reads) + + brz,pn %o2, 70f + andcc %o0, 0x3, %g0 + + /* We "remember" whether the lowest bit in the address + * was set in GLOBAL_SPARE. Because if it is, we have to swap + * upper and lower 8 bit fields of the sum we calculate. + */ + bne,pn %icc, 90b + andcc %o0, 0x1, GLOBAL_SPARE + +80: + LOAD(prefetch, %o0 + 0x080, #n_reads) + andncc %o2, 0x3f, %g3 + + LOAD(prefetch, %o0 + 0x0c0, #n_reads) + sub %o2, %g3, %o2 + brz,pn %g3, 2f + LOAD(prefetch, %o0 + 0x100, #n_reads) + + /* So that we don't need to use the non-pairing + * add-with-carry instructions we accumulate 32-bit + * values into a 64-bit register. At the end of the + * loop we fold it down to 32-bits and so on. + */ + ba,pt %xcc, 1f + LOAD(prefetch, %o0 + 0x140, #n_reads) + + .align 32 +1: EX_LD(LOAD(lduw, %o0 + 0x00, %o5)) + EX_LD(LOAD(lduw, %o0 + 0x04, %g1)) + EX_LD(LOAD(lduw, %o0 + 0x08, %g2)) + add %o4, %o5, %o4 + EX_ST(STORE(stw, %o5, %o1 + 0x00)) + EX_LD(LOAD(lduw, %o0 + 0x0c, %o5)) + add %o4, %g1, %o4 + EX_ST(STORE(stw, %g1, %o1 + 0x04)) + EX_LD(LOAD(lduw, %o0 + 0x10, %g1)) + add %o4, %g2, %o4 + EX_ST(STORE(stw, %g2, %o1 + 0x08)) + EX_LD(LOAD(lduw, %o0 + 0x14, %g2)) + add %o4, %o5, %o4 + EX_ST(STORE(stw, %o5, %o1 + 0x0c)) + EX_LD(LOAD(lduw, %o0 + 0x18, %o5)) + add %o4, %g1, %o4 + EX_ST(STORE(stw, %g1, %o1 + 0x10)) + EX_LD(LOAD(lduw, %o0 + 0x1c, %g1)) + add %o4, %g2, %o4 + EX_ST(STORE(stw, %g2, %o1 + 0x14)) + EX_LD(LOAD(lduw, %o0 + 0x20, %g2)) + add %o4, %o5, %o4 + EX_ST(STORE(stw, %o5, %o1 + 0x18)) + EX_LD(LOAD(lduw, %o0 + 0x24, %o5)) + add %o4, %g1, %o4 + EX_ST(STORE(stw, %g1, %o1 + 0x1c)) + EX_LD(LOAD(lduw, %o0 + 0x28, %g1)) + add %o4, %g2, %o4 + EX_ST(STORE(stw, %g2, %o1 + 0x20)) + EX_LD(LOAD(lduw, %o0 + 0x2c, %g2)) + add %o4, %o5, %o4 + EX_ST(STORE(stw, %o5, %o1 + 0x24)) + EX_LD(LOAD(lduw, %o0 + 0x30, %o5)) + add %o4, %g1, %o4 + EX_ST(STORE(stw, %g1, %o1 + 0x28)) + EX_LD(LOAD(lduw, %o0 + 0x34, %g1)) + add %o4, %g2, %o4 + EX_ST(STORE(stw, %g2, %o1 + 0x2c)) + EX_LD(LOAD(lduw, %o0 + 0x38, %g2)) + add %o4, %o5, %o4 + EX_ST(STORE(stw, %o5, %o1 + 0x30)) + EX_LD(LOAD(lduw, %o0 + 0x3c, %o5)) + add %o4, %g1, %o4 + EX_ST(STORE(stw, %g1, %o1 + 0x34)) + LOAD(prefetch, %o0 + 0x180, #n_reads) + add %o4, %g2, %o4 + EX_ST(STORE(stw, %g2, %o1 + 0x38)) + subcc %g3, 0x40, %g3 + add %o0, 0x40, %o0 + add %o4, %o5, %o4 + EX_ST(STORE(stw, %o5, %o1 + 0x3c)) + bne,pt %icc, 1b + add %o1, 0x40, %o1 + +2: and %o2, 0x3c, %g3 + brz,pn %g3, 2f + sub %o2, %g3, %o2 +1: EX_LD(LOAD(lduw, %o0 + 0x00, %o5)) + subcc %g3, 0x4, %g3 + add %o0, 0x4, %o0 + add %o4, %o5, %o4 + EX_ST(STORE(stw, %o5, %o1 + 0x00)) + bne,pt %icc, 1b + add %o1, 0x4, %o1 + +2: + /* fold 64-->32 */ + srlx %o4, 32, %o5 + srl %o4, 0, %o4 + add %o4, %o5, %o4 + srlx %o4, 32, %o5 + srl %o4, 0, %o4 + add %o4, %o5, %o4 + + /* fold 32-->16 */ + sethi %hi(0xffff0000), %g1 + srl %o4, 16, %o5 + andn %o4, %g1, %g2 + add %o5, %g2, %o4 + srl %o4, 16, %o5 + andn %o4, %g1, %g2 + add %o5, %g2, %o4 + +60: + /* %o4 has the 16-bit sum we have calculated so-far. */ + cmp %o2, 2 + blu,pt %icc, 1f + nop + EX_LD(LOAD(lduh, %o0 + 0x00, %o5)) + sub %o2, 2, %o2 + add %o0, 2, %o0 + add %o4, %o5, %o4 + EX_ST(STORE(sth, %o5, %o1 + 0x00)) + add %o1, 0x2, %o1 +1: brz,pt %o2, 1f + nop + EX_LD(LOAD(ldub, %o0 + 0x00, %o5)) + sub %o2, 1, %o2 + add %o0, 1, %o0 + EX_ST(STORE(stb, %o5, %o1 + 0x00)) + sllx %o5, 8, %o5 + add %o1, 1, %o1 + add %o4, %o5, %o4 +1: + /* fold 32-->16 */ + sethi %hi(0xffff0000), %g1 + srl %o4, 16, %o5 + andn %o4, %g1, %g2 + add %o5, %g2, %o4 + srl %o4, 16, %o5 + andn %o4, %g1, %g2 + add %o5, %g2, %o4 + +1: brz,pt GLOBAL_SPARE, 1f + nop + + /* We started with an odd byte, byte-swap the result. */ + srl %o4, 8, %o5 + and %o4, 0xff, %g1 + sll %g1, 8, %g1 + or %o5, %g1, %o4 + +1: add %o3, %o4, %o3 + +70: + retl + mov %o3, %o0 + +95: mov 0, GLOBAL_SPARE + brlez,pn %o2, 4f + andcc %o0, 1, %o5 + be,a,pt %icc, 1f + srl %o2, 1, %g1 + sub %o2, 1, %o2 + EX_LD(LOAD(ldub, %o0, GLOBAL_SPARE)) + add %o0, 1, %o0 + EX_ST(STORE(stb, GLOBAL_SPARE, %o1)) + srl %o2, 1, %g1 + add %o1, 1, %o1 +1: brz,a,pn %g1, 3f + andcc %o2, 1, %g0 + andcc %o0, 2, %g0 + be,a,pt %icc, 1f + srl %g1, 1, %g1 + EX_LD(LOAD(lduh, %o0, %o4)) + sub %o2, 2, %o2 + srl %o4, 8, %g2 + sub %g1, 1, %g1 + EX_ST(STORE(stb, %g2, %o1)) + add %o4, GLOBAL_SPARE, GLOBAL_SPARE + EX_ST(STORE(stb, %o4, %o1 + 1)) + add %o0, 2, %o0 + srl %g1, 1, %g1 + add %o1, 2, %o1 +1: brz,a,pn %g1, 2f + andcc %o2, 2, %g0 + EX_LD(LOAD(lduw, %o0, %o4)) +5: srl %o4, 24, %g2 + srl %o4, 16, %g3 + EX_ST(STORE(stb, %g2, %o1)) + srl %o4, 8, %g2 + EX_ST(STORE(stb, %g3, %o1 + 1)) + add %o0, 4, %o0 + EX_ST(STORE(stb, %g2, %o1 + 2)) + addcc %o4, GLOBAL_SPARE, GLOBAL_SPARE + EX_ST(STORE(stb, %o4, %o1 + 3)) + addc GLOBAL_SPARE, %g0, GLOBAL_SPARE + add %o1, 4, %o1 + subcc %g1, 1, %g1 + bne,a,pt %icc, 5b + EX_LD(LOAD(lduw, %o0, %o4)) + sll GLOBAL_SPARE, 16, %g2 + srl GLOBAL_SPARE, 16, GLOBAL_SPARE + srl %g2, 16, %g2 + andcc %o2, 2, %g0 + add %g2, GLOBAL_SPARE, GLOBAL_SPARE +2: be,a,pt %icc, 3f + andcc %o2, 1, %g0 + EX_LD(LOAD(lduh, %o0, %o4)) + andcc %o2, 1, %g0 + srl %o4, 8, %g2 + add %o0, 2, %o0 + EX_ST(STORE(stb, %g2, %o1)) + add GLOBAL_SPARE, %o4, GLOBAL_SPARE + EX_ST(STORE(stb, %o4, %o1 + 1)) + add %o1, 2, %o1 +3: be,a,pt %icc, 1f + sll GLOBAL_SPARE, 16, %o4 + EX_LD(LOAD(ldub, %o0, %g2)) + sll %g2, 8, %o4 + EX_ST(STORE(stb, %g2, %o1)) + add GLOBAL_SPARE, %o4, GLOBAL_SPARE + sll GLOBAL_SPARE, 16, %o4 +1: addcc %o4, GLOBAL_SPARE, GLOBAL_SPARE + srl GLOBAL_SPARE, 16, %o4 + addc %g0, %o4, GLOBAL_SPARE + brz,pt %o5, 4f + srl GLOBAL_SPARE, 8, %o4 + and GLOBAL_SPARE, 0xff, %g2 + and %o4, 0xff, %o4 + sll %g2, 8, %g2 + or %g2, %o4, GLOBAL_SPARE +4: addcc %o3, GLOBAL_SPARE, %o3 + addc %g0, %o3, %o0 + retl + srl %o0, 0, %o0 + .size FUNC_NAME, .-FUNC_NAME diff --git a/arch/sparc64/lib/csum_copy_from_user.S b/arch/sparc64/lib/csum_copy_from_user.S new file mode 100644 index 000000000..817ebdae3 --- /dev/null +++ b/arch/sparc64/lib/csum_copy_from_user.S @@ -0,0 +1,21 @@ +/* csum_copy_from_user.S: Checksum+copy from userspace. + * + * Copyright (C) 2005 David S. Miller (davem@davemloft.net) + */ + +#define EX_LD(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov -1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME __csum_partial_copy_from_user +#define LOAD(type,addr,dest) type##a [addr] %asi, dest + +#include "csum_copy.S" diff --git a/arch/sparc64/lib/csum_copy_to_user.S b/arch/sparc64/lib/csum_copy_to_user.S new file mode 100644 index 000000000..c2f9463ea --- /dev/null +++ b/arch/sparc64/lib/csum_copy_to_user.S @@ -0,0 +1,21 @@ +/* csum_copy_to_user.S: Checksum+copy to userspace. + * + * Copyright (C) 2005 David S. Miller (davem@davemloft.net) + */ + +#define EX_ST(x) \ +98: x; \ + .section .fixup; \ + .align 4; \ +99: retl; \ + mov -1, %o0; \ + .section __ex_table; \ + .align 4; \ + .word 98b, 99b; \ + .text; \ + .align 4; + +#define FUNC_NAME __csum_partial_copy_to_user +#define STORE(type,src,addr) type##a src, [addr] %asi + +#include "csum_copy.S" diff --git a/arch/sparc64/lib/rwsem.S b/arch/sparc64/lib/rwsem.S new file mode 100644 index 000000000..174ff7b91 --- /dev/null +++ b/arch/sparc64/lib/rwsem.S @@ -0,0 +1,165 @@ +/* rwsem.S: RW semaphore assembler. + * + * Written by David S. Miller (davem@redhat.com), 2001. + * Derived from asm-i386/rwsem.h + */ + +#include + + .section .sched.text + + .globl __down_read +__down_read: +1: lduw [%o0], %g1 + add %g1, 1, %g7 + cas [%o0], %g1, %g7 + cmp %g1, %g7 + bne,pn %icc, 1b + add %g7, 1, %g7 + cmp %g7, 0 + bl,pn %icc, 3f + membar #StoreLoad | #StoreStore +2: + retl + nop +3: + save %sp, -192, %sp + call rwsem_down_read_failed + mov %i0, %o0 + ret + restore + .size __down_read, .-__down_read + + .globl __down_read_trylock +__down_read_trylock: +1: lduw [%o0], %g1 + add %g1, 1, %g7 + cmp %g7, 0 + bl,pn %icc, 2f + mov 0, %o1 + cas [%o0], %g1, %g7 + cmp %g1, %g7 + bne,pn %icc, 1b + mov 1, %o1 + membar #StoreLoad | #StoreStore +2: retl + mov %o1, %o0 + .size __down_read_trylock, .-__down_read_trylock + + .globl __down_write +__down_write: + sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 + or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 +1: + lduw [%o0], %g3 + add %g3, %g1, %g7 + cas [%o0], %g3, %g7 + cmp %g3, %g7 + bne,pn %icc, 1b + cmp %g7, 0 + bne,pn %icc, 3f + membar #StoreLoad | #StoreStore +2: retl + nop +3: + save %sp, -192, %sp + call rwsem_down_write_failed + mov %i0, %o0 + ret + restore + .size __down_write, .-__down_write + + .globl __down_write_trylock +__down_write_trylock: + sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 + or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 +1: + lduw [%o0], %g3 + cmp %g3, 0 + bne,pn %icc, 2f + mov 0, %o1 + add %g3, %g1, %g7 + cas [%o0], %g3, %g7 + cmp %g3, %g7 + bne,pn %icc, 1b + mov 1, %o1 + membar #StoreLoad | #StoreStore +2: retl + mov %o1, %o0 + .size __down_write_trylock, .-__down_write_trylock + + .globl __up_read +__up_read: +1: + lduw [%o0], %g1 + sub %g1, 1, %g7 + cas [%o0], %g1, %g7 + cmp %g1, %g7 + bne,pn %icc, 1b + cmp %g7, 0 + bl,pn %icc, 3f + membar #StoreLoad | #StoreStore +2: retl + nop +3: sethi %hi(RWSEM_ACTIVE_MASK), %g1 + sub %g7, 1, %g7 + or %g1, %lo(RWSEM_ACTIVE_MASK), %g1 + andcc %g7, %g1, %g0 + bne,pn %icc, 2b + nop + save %sp, -192, %sp + call rwsem_wake + mov %i0, %o0 + ret + restore + .size __up_read, .-__up_read + + .globl __up_write +__up_write: + sethi %hi(RWSEM_ACTIVE_WRITE_BIAS), %g1 + or %g1, %lo(RWSEM_ACTIVE_WRITE_BIAS), %g1 +1: + lduw [%o0], %g3 + sub %g3, %g1, %g7 + cas [%o0], %g3, %g7 + cmp %g3, %g7 + bne,pn %icc, 1b + sub %g7, %g1, %g7 + cmp %g7, 0 + bl,pn %icc, 3f + membar #StoreLoad | #StoreStore +2: + retl + nop +3: + save %sp, -192, %sp + call rwsem_wake + mov %i0, %o0 + ret + restore + .size __up_write, .-__up_write + + .globl __downgrade_write +__downgrade_write: + sethi %hi(RWSEM_WAITING_BIAS), %g1 + or %g1, %lo(RWSEM_WAITING_BIAS), %g1 +1: + lduw [%o0], %g3 + sub %g3, %g1, %g7 + cas [%o0], %g3, %g7 + cmp %g3, %g7 + bne,pn %icc, 1b + sub %g7, %g1, %g7 + cmp %g7, 0 + bl,pn %icc, 3f + membar #StoreLoad | #StoreStore +2: + retl + nop +3: + save %sp, -192, %sp + call rwsem_downgrade_wake + mov %i0, %o0 + ret + restore + .size __downgrade_write, .-__downgrade_write diff --git a/arch/um/drivers/slip_common.c b/arch/um/drivers/slip_common.c new file mode 100644 index 000000000..e89cfc68f --- /dev/null +++ b/arch/um/drivers/slip_common.c @@ -0,0 +1,54 @@ +#include +#include "slip_common.h" +#include "net_user.h" + +int slip_proto_read(int fd, void *buf, int len, struct slip_proto *slip) +{ + int i, n, size, start; + + if(slip->more > 0){ + i = 0; + while(i < slip->more){ + size = slip_unesc(slip->ibuf[i++], slip->ibuf, + &slip->pos, &slip->esc); + if(size){ + memcpy(buf, slip->ibuf, size); + memmove(slip->ibuf, &slip->ibuf[i], + slip->more - i); + slip->more = slip->more - i; + return size; + } + } + slip->more = 0; + } + + n = net_read(fd, &slip->ibuf[slip->pos], + sizeof(slip->ibuf) - slip->pos); + if(n <= 0) + return n; + + start = slip->pos; + for(i = 0; i < n; i++){ + size = slip_unesc(slip->ibuf[start + i], slip->ibuf,&slip->pos, + &slip->esc); + if(size){ + memcpy(buf, slip->ibuf, size); + memmove(slip->ibuf, &slip->ibuf[start+i+1], + n - (i + 1)); + slip->more = n - (i + 1); + return size; + } + } + return 0; +} + +int slip_proto_write(int fd, void *buf, int len, struct slip_proto *slip) +{ + int actual, n; + + actual = slip_esc(buf, slip->obuf, len); + n = net_write(fd, slip->obuf, actual); + if(n < 0) + return n; + else return len; +} diff --git a/arch/um/drivers/slip_common.h b/arch/um/drivers/slip_common.h new file mode 100644 index 000000000..2ae76d8f1 --- /dev/null +++ b/arch/um/drivers/slip_common.h @@ -0,0 +1,104 @@ +#ifndef __UM_SLIP_COMMON_H +#define __UM_SLIP_COMMON_H + +#define BUF_SIZE 1500 + /* two bytes each for a (pathological) max packet of escaped chars + * + * terminating END char + initial END char */ +#define ENC_BUF_SIZE (2 * BUF_SIZE + 2) + +/* SLIP protocol characters. */ +#define SLIP_END 0300 /* indicates end of frame */ +#define SLIP_ESC 0333 /* indicates byte stuffing */ +#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +static inline int slip_unesc(unsigned char c, unsigned char *buf, int *pos, + int *esc) +{ + int ret; + + switch(c){ + case SLIP_END: + *esc = 0; + ret=*pos; + *pos=0; + return(ret); + case SLIP_ESC: + *esc = 1; + return(0); + case SLIP_ESC_ESC: + if(*esc){ + *esc = 0; + c = SLIP_ESC; + } + break; + case SLIP_ESC_END: + if(*esc){ + *esc = 0; + c = SLIP_END; + } + break; + } + buf[(*pos)++] = c; + return(0); +} + +static inline int slip_esc(unsigned char *s, unsigned char *d, int len) +{ + unsigned char *ptr = d; + unsigned char c; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + *ptr++ = SLIP_END; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while (len-- > 0) { + switch(c = *s++) { + case SLIP_END: + *ptr++ = SLIP_ESC; + *ptr++ = SLIP_ESC_END; + break; + case SLIP_ESC: + *ptr++ = SLIP_ESC; + *ptr++ = SLIP_ESC_ESC; + break; + default: + *ptr++ = c; + break; + } + } + *ptr++ = SLIP_END; + return (ptr - d); +} + +struct slip_proto { + unsigned char ibuf[ENC_BUF_SIZE]; + unsigned char obuf[ENC_BUF_SIZE]; + int more; /* more data: do not read fd until ibuf has been drained */ + int pos; + int esc; +}; + +#define SLIP_PROTO_INIT { \ + .ibuf = { '\0' }, \ + .obuf = { '\0' }, \ + .more = 0, \ + .pos = 0, \ + .esc = 0 \ +} + +extern int slip_proto_read(int fd, void *buf, int len, + struct slip_proto *slip); +extern int slip_proto_write(int fd, void *buf, int len, + struct slip_proto *slip); + +#endif diff --git a/arch/um/include/sysdep-i386/faultinfo.h b/arch/um/include/sysdep-i386/faultinfo.h new file mode 100644 index 000000000..db437cc37 --- /dev/null +++ b/arch/um/include/sysdep-i386/faultinfo.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2004 Fujitsu Siemens Computers GmbH + * Author: Bodo Stroesser + * Licensed under the GPL + */ + +#ifndef __FAULTINFO_I386_H +#define __FAULTINFO_I386_H + +/* this structure contains the full arch-specific faultinfo + * from the traps. + * On i386, ptrace_faultinfo unfortunately doesn't provide + * all the info, since trap_no is missing. + * All common elements are defined at the same position in + * both structures, thus making it easy to copy the + * contents without knowledge about the structure elements. + */ +struct faultinfo { + int error_code; /* in ptrace_faultinfo misleadingly called is_write */ + unsigned long cr2; /* in ptrace_faultinfo called addr */ + int trap_no; /* missing in ptrace_faultinfo */ +}; + +#define FAULT_WRITE(fi) ((fi).error_code & 2) +#define FAULT_ADDRESS(fi) ((fi).cr2) + +#define PTRACE_FULL_FAULTINFO 0 + +#endif diff --git a/arch/um/include/sysdep-i386/skas_ptrace.h b/arch/um/include/sysdep-i386/skas_ptrace.h new file mode 100644 index 000000000..e27b8a791 --- /dev/null +++ b/arch/um/include/sysdep-i386/skas_ptrace.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_I386_SKAS_PTRACE_H +#define __SYSDEP_I386_SKAS_PTRACE_H + +struct ptrace_faultinfo { + int is_write; + unsigned long addr; +}; + +struct ptrace_ldt { + int func; + void *ptr; + unsigned long bytecount; +}; + +#define PTRACE_LDT 54 + +#endif diff --git a/arch/um/include/sysdep-ia64/skas_ptrace.h b/arch/um/include/sysdep-ia64/skas_ptrace.h new file mode 100644 index 000000000..25a38e715 --- /dev/null +++ b/arch/um/include/sysdep-ia64/skas_ptrace.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_IA64_SKAS_PTRACE_H +#define __SYSDEP_IA64_SKAS_PTRACE_H + +struct ptrace_faultinfo { + int is_write; + unsigned long addr; +}; + +struct ptrace_ldt { + int func; + void *ptr; + unsigned long bytecount; +}; + +#define PTRACE_LDT 54 + +#endif diff --git a/arch/um/include/sysdep-ppc/skas_ptrace.h b/arch/um/include/sysdep-ppc/skas_ptrace.h new file mode 100644 index 000000000..d9fbbac10 --- /dev/null +++ b/arch/um/include/sysdep-ppc/skas_ptrace.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_PPC_SKAS_PTRACE_H +#define __SYSDEP_PPC_SKAS_PTRACE_H + +struct ptrace_faultinfo { + int is_write; + unsigned long addr; +}; + +struct ptrace_ldt { + int func; + void *ptr; + unsigned long bytecount; +}; + +#define PTRACE_LDT 54 + +#endif diff --git a/arch/um/include/sysdep-x86_64/faultinfo.h b/arch/um/include/sysdep-x86_64/faultinfo.h new file mode 100644 index 000000000..cb917b0d5 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/faultinfo.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2004 Fujitsu Siemens Computers GmbH + * Author: Bodo Stroesser + * Licensed under the GPL + */ + +#ifndef __FAULTINFO_X86_64_H +#define __FAULTINFO_X86_64_H + +/* this structure contains the full arch-specific faultinfo + * from the traps. + * On i386, ptrace_faultinfo unfortunately doesn't provide + * all the info, since trap_no is missing. + * All common elements are defined at the same position in + * both structures, thus making it easy to copy the + * contents without knowledge about the structure elements. + */ +struct faultinfo { + int error_code; /* in ptrace_faultinfo misleadingly called is_write */ + unsigned long cr2; /* in ptrace_faultinfo called addr */ + int trap_no; /* missing in ptrace_faultinfo */ +}; + +#define FAULT_WRITE(fi) ((fi).error_code & 2) +#define FAULT_ADDRESS(fi) ((fi).cr2) + +#define PTRACE_FULL_FAULTINFO 1 + +#endif diff --git a/arch/um/include/sysdep-x86_64/skas_ptrace.h b/arch/um/include/sysdep-x86_64/skas_ptrace.h new file mode 100644 index 000000000..95db4be78 --- /dev/null +++ b/arch/um/include/sysdep-x86_64/skas_ptrace.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SYSDEP_X86_64_SKAS_PTRACE_H +#define __SYSDEP_X86_64_SKAS_PTRACE_H + +struct ptrace_faultinfo { + int is_write; + unsigned long addr; +}; + +struct ptrace_ldt { + int func; + void *ptr; + unsigned long bytecount; +}; + +#define PTRACE_LDT 54 + +#endif diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c new file mode 100644 index 000000000..82ecf904b --- /dev/null +++ b/arch/um/kernel/initrd.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/init.h" +#include "linux/bootmem.h" +#include "linux/initrd.h" +#include "asm/types.h" +#include "user_util.h" +#include "kern_util.h" +#include "initrd.h" +#include "init.h" +#include "os.h" + +/* Changed by uml_initrd_setup, which is a setup */ +static char *initrd __initdata = NULL; + +static int __init read_initrd(void) +{ + void *area; + long long size; + int err; + + if(initrd == NULL) return 0; + err = os_file_size(initrd, &size); + if(err) return 0; + area = alloc_bootmem(size); + if(area == NULL) return 0; + if(load_initrd(initrd, area, size) == -1) return 0; + initrd_start = (unsigned long) area; + initrd_end = initrd_start + size; + return 0; +} + +__uml_postsetup(read_initrd); + +static int __init uml_initrd_setup(char *line, int *add) +{ + initrd = line; + return 0; +} + +__uml_setup("initrd=", uml_initrd_setup, +"initrd=\n" +" This is used to boot UML from an initrd image. The argument is the\n" +" name of the file containing the image.\n\n" +); + +int load_initrd(char *filename, void *buf, int size) +{ + int fd, n; + + fd = os_open_file(filename, of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Opening '%s' failed - err = %d\n", filename, -fd); + return(-1); + } + n = os_read_file(fd, buf, size); + if(n != size){ + printk("Read of %d bytes from '%s' failed, err = %d\n", size, + filename, -n); + return(-1); + } + + os_close_file(fd); + return(0); +} +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/um_module.c b/arch/um/sys-x86_64/um_module.c new file mode 100644 index 000000000..8b8eff1bd --- /dev/null +++ b/arch/um/sys-x86_64/um_module.c @@ -0,0 +1,19 @@ +#include +#include + +/*Copied from i386 arch/i386/kernel/module.c */ +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc_exec(size); +} + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h new file mode 100644 index 000000000..e7fd47e43 --- /dev/null +++ b/drivers/char/mbcs.h @@ -0,0 +1,553 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef __MBCS_H__ +#define __MBCS_H__ + +/* + * General macros + */ +#define MB (1024*1024) +#define MB2 (2*MB) +#define MB4 (4*MB) +#define MB6 (6*MB) + +/* + * Offsets and masks + */ +#define MBCS_CM_ID 0x0000 /* Identification */ +#define MBCS_CM_STATUS 0x0008 /* Status */ +#define MBCS_CM_ERROR_DETAIL1 0x0010 /* Error Detail1 */ +#define MBCS_CM_ERROR_DETAIL2 0x0018 /* Error Detail2 */ +#define MBCS_CM_CONTROL 0x0020 /* Control */ +#define MBCS_CM_REQ_TOUT 0x0028 /* Request Time-out */ +#define MBCS_CM_ERR_INT_DEST 0x0038 /* Error Interrupt Destination */ +#define MBCS_CM_TARG_FL 0x0050 /* Target Flush */ +#define MBCS_CM_ERR_STAT 0x0060 /* Error Status */ +#define MBCS_CM_CLR_ERR_STAT 0x0068 /* Clear Error Status */ +#define MBCS_CM_ERR_INT_EN 0x0070 /* Error Interrupt Enable */ +#define MBCS_RD_DMA_SYS_ADDR 0x0100 /* Read DMA System Address */ +#define MBCS_RD_DMA_LOC_ADDR 0x0108 /* Read DMA Local Address */ +#define MBCS_RD_DMA_CTRL 0x0110 /* Read DMA Control */ +#define MBCS_RD_DMA_AMO_DEST 0x0118 /* Read DMA AMO Destination */ +#define MBCS_RD_DMA_INT_DEST 0x0120 /* Read DMA Interrupt Destination */ +#define MBCS_RD_DMA_AUX_STAT 0x0130 /* Read DMA Auxillary Status */ +#define MBCS_WR_DMA_SYS_ADDR 0x0200 /* Write DMA System Address */ +#define MBCS_WR_DMA_LOC_ADDR 0x0208 /* Write DMA Local Address */ +#define MBCS_WR_DMA_CTRL 0x0210 /* Write DMA Control */ +#define MBCS_WR_DMA_AMO_DEST 0x0218 /* Write DMA AMO Destination */ +#define MBCS_WR_DMA_INT_DEST 0x0220 /* Write DMA Interrupt Destination */ +#define MBCS_WR_DMA_AUX_STAT 0x0230 /* Write DMA Auxillary Status */ +#define MBCS_ALG_AMO_DEST 0x0300 /* Algorithm AMO Destination */ +#define MBCS_ALG_INT_DEST 0x0308 /* Algorithm Interrupt Destination */ +#define MBCS_ALG_OFFSETS 0x0310 +#define MBCS_ALG_STEP 0x0318 /* Algorithm Step */ + +#define MBCS_GSCR_START 0x0000000 +#define MBCS_DEBUG_START 0x0100000 +#define MBCS_RAM0_START 0x0200000 +#define MBCS_RAM1_START 0x0400000 +#define MBCS_RAM2_START 0x0600000 + +#define MBCS_CM_CONTROL_REQ_TOUT_MASK 0x0000000000ffffffUL +//#define PIO_BASE_ADDR_BASE_OFFSET_MASK 0x00fffffffff00000UL + +#define MBCS_SRAM_SIZE (1024*1024) +#define MBCS_CACHELINE_SIZE 128 + +/* + * MMR get's and put's + */ +#define MBCS_MMR_ADDR(mmr_base, offset)((uint64_t *)(mmr_base + offset)) +#define MBCS_MMR_SET(mmr_base, offset, value) { \ + uint64_t *mbcs_mmr_set_u64p, readback; \ + mbcs_mmr_set_u64p = (uint64_t *)(mmr_base + offset); \ + *mbcs_mmr_set_u64p = value; \ + readback = *mbcs_mmr_set_u64p; \ +} +#define MBCS_MMR_GET(mmr_base, offset) *(uint64_t *)(mmr_base + offset) +#define MBCS_MMR_ZERO(mmr_base, offset) MBCS_MMR_SET(mmr_base, offset, 0) + +/* + * MBCS mmr structures + */ +union cm_id { + uint64_t cm_id_reg; + struct { + uint64_t always_one:1, // 0 + mfg_id:11, // 11:1 + part_num:16, // 27:12 + bitstream_rev:8, // 35:28 + :28; // 63:36 + }; +}; + +union cm_status { + uint64_t cm_status_reg; + struct { + uint64_t pending_reads:8, // 7:0 + pending_writes:8, // 15:8 + ice_rsp_credits:8, // 23:16 + ice_req_credits:8, // 31:24 + cm_req_credits:8, // 39:32 + :1, // 40 + rd_dma_in_progress:1, // 41 + rd_dma_done:1, // 42 + :1, // 43 + wr_dma_in_progress:1, // 44 + wr_dma_done:1, // 45 + alg_waiting:1, // 46 + alg_pipe_running:1, // 47 + alg_done:1, // 48 + :3, // 51:49 + pending_int_reqs:8, // 59:52 + :3, // 62:60 + alg_half_speed_sel:1; // 63 + }; +}; + +union cm_error_detail1 { + uint64_t cm_error_detail1_reg; + struct { + uint64_t packet_type:4, // 3:0 + source_id:2, // 5:4 + data_size:2, // 7:6 + tnum:8, // 15:8 + byte_enable:8, // 23:16 + gfx_cred:8, // 31:24 + read_type:2, // 33:32 + pio_or_memory:1, // 34 + head_cw_error:1, // 35 + :12, // 47:36 + head_error_bit:1, // 48 + data_error_bit:1, // 49 + :13, // 62:50 + valid:1; // 63 + }; +}; + +union cm_error_detail2 { + uint64_t cm_error_detail2_reg; + struct { + uint64_t address:56, // 55:0 + :8; // 63:56 + }; +}; + +union cm_control { + uint64_t cm_control_reg; + struct { + uint64_t cm_id:2, // 1:0 + :2, // 3:2 + max_trans:5, // 8:4 + :3, // 11:9 + address_mode:1, // 12 + :7, // 19:13 + credit_limit:8, // 27:20 + :5, // 32:28 + rearm_stat_regs:1, // 33 + prescalar_byp:1, // 34 + force_gap_war:1, // 35 + rd_dma_go:1, // 36 + wr_dma_go:1, // 37 + alg_go:1, // 38 + rd_dma_clr:1, // 39 + wr_dma_clr:1, // 40 + alg_clr:1, // 41 + :2, // 43:42 + alg_wait_step:1, // 44 + alg_done_amo_en:1, // 45 + alg_done_int_en:1, // 46 + :1, // 47 + alg_sram0_locked:1, // 48 + alg_sram1_locked:1, // 49 + alg_sram2_locked:1, // 50 + alg_done_clr:1, // 51 + :12; // 63:52 + }; +}; + +union cm_req_timeout { + uint64_t cm_req_timeout_reg; + struct { + uint64_t time_out:24, // 23:0 + :40; // 63:24 + }; +}; + +union intr_dest { + uint64_t intr_dest_reg; + struct { + uint64_t address:56, // 55:0 + int_vector:8; // 63:56 + }; +}; + +union cm_error_status { + uint64_t cm_error_status_reg; + struct { + uint64_t ecc_sbe:1, // 0 + ecc_mbe:1, // 1 + unsupported_req:1, // 2 + unexpected_rsp:1, // 3 + bad_length:1, // 4 + bad_datavalid:1, // 5 + buffer_overflow:1, // 6 + request_timeout:1, // 7 + :8, // 15:8 + head_inv_data_size:1, // 16 + rsp_pactype_inv:1, // 17 + head_sb_err:1, // 18 + missing_head:1, // 19 + head_inv_rd_type:1, // 20 + head_cmd_err_bit:1, // 21 + req_addr_align_inv:1, // 22 + pio_req_addr_inv:1, // 23 + req_range_dsize_inv:1, // 24 + early_term:1, // 25 + early_tail:1, // 26 + missing_tail:1, // 27 + data_flit_sb_err:1, // 28 + cm2hcm_req_cred_of:1, // 29 + cm2hcm_rsp_cred_of:1, // 30 + rx_bad_didn:1, // 31 + rd_dma_err_rsp:1, // 32 + rd_dma_tnum_tout:1, // 33 + rd_dma_multi_tnum_tou:1, // 34 + wr_dma_err_rsp:1, // 35 + wr_dma_tnum_tout:1, // 36 + wr_dma_multi_tnum_tou:1, // 37 + alg_data_overflow:1, // 38 + alg_data_underflow:1, // 39 + ram0_access_conflict:1, // 40 + ram1_access_conflict:1, // 41 + ram2_access_conflict:1, // 42 + ram0_perr:1, // 43 + ram1_perr:1, // 44 + ram2_perr:1, // 45 + int_gen_rsp_err:1, // 46 + int_gen_tnum_tout:1, // 47 + rd_dma_prog_err:1, // 48 + wr_dma_prog_err:1, // 49 + :14; // 63:50 + }; +}; + +union cm_clr_error_status { + uint64_t cm_clr_error_status_reg; + struct { + uint64_t clr_ecc_sbe:1, // 0 + clr_ecc_mbe:1, // 1 + clr_unsupported_req:1, // 2 + clr_unexpected_rsp:1, // 3 + clr_bad_length:1, // 4 + clr_bad_datavalid:1, // 5 + clr_buffer_overflow:1, // 6 + clr_request_timeout:1, // 7 + :8, // 15:8 + clr_head_inv_data_siz:1, // 16 + clr_rsp_pactype_inv:1, // 17 + clr_head_sb_err:1, // 18 + clr_missing_head:1, // 19 + clr_head_inv_rd_type:1, // 20 + clr_head_cmd_err_bit:1, // 21 + clr_req_addr_align_in:1, // 22 + clr_pio_req_addr_inv:1, // 23 + clr_req_range_dsize_i:1, // 24 + clr_early_term:1, // 25 + clr_early_tail:1, // 26 + clr_missing_tail:1, // 27 + clr_data_flit_sb_err:1, // 28 + clr_cm2hcm_req_cred_o:1, // 29 + clr_cm2hcm_rsp_cred_o:1, // 30 + clr_rx_bad_didn:1, // 31 + clr_rd_dma_err_rsp:1, // 32 + clr_rd_dma_tnum_tout:1, // 33 + clr_rd_dma_multi_tnum:1, // 34 + clr_wr_dma_err_rsp:1, // 35 + clr_wr_dma_tnum_tout:1, // 36 + clr_wr_dma_multi_tnum:1, // 37 + clr_alg_data_overflow:1, // 38 + clr_alg_data_underflo:1, // 39 + clr_ram0_access_confl:1, // 40 + clr_ram1_access_confl:1, // 41 + clr_ram2_access_confl:1, // 42 + clr_ram0_perr:1, // 43 + clr_ram1_perr:1, // 44 + clr_ram2_perr:1, // 45 + clr_int_gen_rsp_err:1, // 46 + clr_int_gen_tnum_tout:1, // 47 + clr_rd_dma_prog_err:1, // 48 + clr_wr_dma_prog_err:1, // 49 + :14; // 63:50 + }; +}; + +union cm_error_intr_enable { + uint64_t cm_error_intr_enable_reg; + struct { + uint64_t int_en_ecc_sbe:1, // 0 + int_en_ecc_mbe:1, // 1 + int_en_unsupported_re:1, // 2 + int_en_unexpected_rsp:1, // 3 + int_en_bad_length:1, // 4 + int_en_bad_datavalid:1, // 5 + int_en_buffer_overflo:1, // 6 + int_en_request_timeou:1, // 7 + :8, // 15:8 + int_en_head_inv_data_:1, // 16 + int_en_rsp_pactype_in:1, // 17 + int_en_head_sb_err:1, // 18 + int_en_missing_head:1, // 19 + int_en_head_inv_rd_ty:1, // 20 + int_en_head_cmd_err_b:1, // 21 + int_en_req_addr_align:1, // 22 + int_en_pio_req_addr_i:1, // 23 + int_en_req_range_dsiz:1, // 24 + int_en_early_term:1, // 25 + int_en_early_tail:1, // 26 + int_en_missing_tail:1, // 27 + int_en_data_flit_sb_e:1, // 28 + int_en_cm2hcm_req_cre:1, // 29 + int_en_cm2hcm_rsp_cre:1, // 30 + int_en_rx_bad_didn:1, // 31 + int_en_rd_dma_err_rsp:1, // 32 + int_en_rd_dma_tnum_to:1, // 33 + int_en_rd_dma_multi_t:1, // 34 + int_en_wr_dma_err_rsp:1, // 35 + int_en_wr_dma_tnum_to:1, // 36 + int_en_wr_dma_multi_t:1, // 37 + int_en_alg_data_overf:1, // 38 + int_en_alg_data_under:1, // 39 + int_en_ram0_access_co:1, // 40 + int_en_ram1_access_co:1, // 41 + int_en_ram2_access_co:1, // 42 + int_en_ram0_perr:1, // 43 + int_en_ram1_perr:1, // 44 + int_en_ram2_perr:1, // 45 + int_en_int_gen_rsp_er:1, // 46 + int_en_int_gen_tnum_t:1, // 47 + int_en_rd_dma_prog_er:1, // 48 + int_en_wr_dma_prog_er:1, // 49 + :14; // 63:50 + }; +}; + +struct cm_mmr { + union cm_id id; + union cm_status status; + union cm_error_detail1 err_detail1; + union cm_error_detail2 err_detail2; + union cm_control control; + union cm_req_timeout req_timeout; + uint64_t reserved1[1]; + union intr_dest int_dest; + uint64_t reserved2[2]; + uint64_t targ_flush; + uint64_t reserved3[1]; + union cm_error_status err_status; + union cm_clr_error_status clr_err_status; + union cm_error_intr_enable int_enable; +}; + +union dma_hostaddr { + uint64_t dma_hostaddr_reg; + struct { + uint64_t dma_sys_addr:56, // 55:0 + :8; // 63:56 + }; +}; + +union dma_localaddr { + uint64_t dma_localaddr_reg; + struct { + uint64_t dma_ram_addr:21, // 20:0 + dma_ram_sel:2, // 22:21 + :41; // 63:23 + }; +}; + +union dma_control { + uint64_t dma_control_reg; + struct { + uint64_t dma_op_length:16, // 15:0 + :18, // 33:16 + done_amo_en:1, // 34 + done_int_en:1, // 35 + :1, // 36 + pio_mem_n:1, // 37 + :26; // 63:38 + }; +}; + +union dma_amo_dest { + uint64_t dma_amo_dest_reg; + struct { + uint64_t dma_amo_sys_addr:56, // 55:0 + dma_amo_mod_type:3, // 58:56 + :5; // 63:59 + }; +}; + +union rdma_aux_status { + uint64_t rdma_aux_status_reg; + struct { + uint64_t op_num_pacs_left:17, // 16:0 + :5, // 21:17 + lrsp_buff_empty:1, // 22 + :17, // 39:23 + pending_reqs_left:6, // 45:40 + :18; // 63:46 + }; +}; + +struct rdma_mmr { + union dma_hostaddr host_addr; + union dma_localaddr local_addr; + union dma_control control; + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union rdma_aux_status aux_status; +}; + +union wdma_aux_status { + uint64_t wdma_aux_status_reg; + struct { + uint64_t op_num_pacs_left:17, // 16:0 + :4, // 20:17 + lreq_buff_empty:1, // 21 + :18, // 39:22 + pending_reqs_left:6, // 45:40 + :18; // 63:46 + }; +}; + +struct wdma_mmr { + union dma_hostaddr host_addr; + union dma_localaddr local_addr; + union dma_control control; + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union wdma_aux_status aux_status; +}; + +union algo_step { + uint64_t algo_step_reg; + struct { + uint64_t alg_step_cnt:16, // 15:0 + :48; // 63:16 + }; +}; + +struct algo_mmr { + union dma_amo_dest amo_dest; + union intr_dest intr_dest; + union { + uint64_t algo_offset_reg; + struct { + uint64_t sram0_offset:7, // 6:0 + reserved0:1, // 7 + sram1_offset:7, // 14:8 + reserved1:1, // 15 + sram2_offset:7, // 22:16 + reserved2:14; // 63:23 + }; + } sram_offset; + union algo_step step; +}; + +struct mbcs_mmr { + struct cm_mmr cm; + uint64_t reserved1[17]; + struct rdma_mmr rdDma; + uint64_t reserved2[25]; + struct wdma_mmr wrDma; + uint64_t reserved3[25]; + struct algo_mmr algo; + uint64_t reserved4[156]; +}; + +/* + * defines + */ +#define DEVICE_NAME "mbcs" +#define MBCS_PART_NUM 0xfff0 +#define MBCS_PART_NUM_ALG0 0xf001 +#define MBCS_MFG_NUM 0x1 + +struct algoblock { + uint64_t amoHostDest; + uint64_t amoModType; + uint64_t intrHostDest; + uint64_t intrVector; + uint64_t algoStepCount; +}; + +struct getdma { + uint64_t hostAddr; + uint64_t localAddr; + uint64_t bytes; + uint64_t DoneAmoEnable; + uint64_t DoneIntEnable; + uint64_t peerIO; + uint64_t amoHostDest; + uint64_t amoModType; + uint64_t intrHostDest; + uint64_t intrVector; +}; + +struct putdma { + uint64_t hostAddr; + uint64_t localAddr; + uint64_t bytes; + uint64_t DoneAmoEnable; + uint64_t DoneIntEnable; + uint64_t peerIO; + uint64_t amoHostDest; + uint64_t amoModType; + uint64_t intrHostDest; + uint64_t intrVector; +}; + +struct mbcs_soft { + struct list_head list; + struct cx_dev *cxdev; + int major; + int nasid; + void *mmr_base; + wait_queue_head_t dmawrite_queue; + wait_queue_head_t dmaread_queue; + wait_queue_head_t algo_queue; + struct sn_irq_info *get_sn_irq; + struct sn_irq_info *put_sn_irq; + struct sn_irq_info *algo_sn_irq; + struct getdma getdma; + struct putdma putdma; + struct algoblock algo; + uint64_t gscr_addr; // pio addr + uint64_t ram0_addr; // pio addr + uint64_t ram1_addr; // pio addr + uint64_t ram2_addr; // pio addr + uint64_t debug_addr; // pio addr + atomic_t dmawrite_done; + atomic_t dmaread_done; + atomic_t algo_done; + struct semaphore dmawritelock; + struct semaphore dmareadlock; + struct semaphore algolock; +}; + +extern int mbcs_open(struct inode *ip, struct file *fp); +extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len, + loff_t * off); +extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len, + loff_t * off); +extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence); +extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma); + +#endif // __MBCS_H__ diff --git a/drivers/md/dm-bio-record.h b/drivers/md/dm-bio-record.h new file mode 100644 index 000000000..d3ec21784 --- /dev/null +++ b/drivers/md/dm-bio-record.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. + * + * This file is released under the GPL. + */ + +#ifndef DM_BIO_RECORD_H +#define DM_BIO_RECORD_H + +#include + +/* + * There are lots of mutable fields in the bio struct that get + * changed by the lower levels of the block layer. Some targets, + * such as multipath, may wish to resubmit a bio on error. The + * functions in this file help the target record and restore the + * original bio state. + */ +struct dm_bio_details { + sector_t bi_sector; + struct block_device *bi_bdev; + unsigned int bi_size; + unsigned short bi_idx; + unsigned long bi_flags; +}; + +static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) +{ + bd->bi_sector = bio->bi_sector; + bd->bi_bdev = bio->bi_bdev; + bd->bi_size = bio->bi_size; + bd->bi_idx = bio->bi_idx; + bd->bi_flags = bio->bi_flags; +} + +static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) +{ + bio->bi_sector = bd->bi_sector; + bio->bi_bdev = bd->bi_bdev; + bio->bi_size = bd->bi_size; + bio->bi_idx = bd->bi_idx; + bio->bi_flags = bd->bi_flags; +} + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c new file mode 100644 index 000000000..8d2706075 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-dma.c @@ -0,0 +1,149 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-dma.c - methods for configuring and controlling the DMA of the FlexCop. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size) +{ + u8 *tcpu; + dma_addr_t tdma; + + if (size % 2) { + err("dma buffersize has to be even."); + return -EINVAL; + } + + if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) { + dma->pdev = pdev; + dma->cpu_addr0 = tcpu; + dma->dma_addr0 = tdma; + dma->cpu_addr1 = tcpu + size/2; + dma->dma_addr1 = tdma + size/2; + dma->size = size/2; + return 0; + } + return -ENOMEM; +} +EXPORT_SYMBOL(flexcop_dma_allocate); + +void flexcop_dma_free(struct flexcop_dma *dma) +{ + pci_free_consistent(dma->pdev, dma->size*2,dma->cpu_addr0, dma->dma_addr0); + memset(dma,0,sizeof(struct flexcop_dma)); +} +EXPORT_SYMBOL(flexcop_dma_free); + +int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_Timer_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_Timer_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_timer_irq); + +int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_IRQ_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_IRQ_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_size_irq); + +int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208); + + if (no & FC_DMA_1) + v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff; + + if (no & FC_DMA_2) + v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff; + + fc->write_ibi_reg(fc,ctrl_208,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_control_packet_irq); + +int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index) +{ + + flexcop_ibi_value v0x0,v0x4,v0xc; + v0x0.raw = v0x4.raw = v0xc.raw = 0; + + v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2; + v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2; + v0x4.dma_0x4_write.dma_addr_size = dma->size / 4; + + if (index & FC_DMA_SUBADDR_0) + v0x0.dma_0x0.dma_0start = 1; + + if (index & FC_DMA_SUBADDR_1) + v0xc.dma_0xc.dma_1start = 1; + + if (dma_idx & FC_DMA_1) { + fc->write_ibi_reg(fc,dma1_000,v0x0); + fc->write_ibi_reg(fc,dma1_004,v0x4); + fc->write_ibi_reg(fc,dma1_00c,v0xc); + } else { /* (dma_idx & FC_DMA_2) */ + fc->write_ibi_reg(fc,dma2_010,v0x0); + fc->write_ibi_reg(fc,dma2_014,v0x4); + fc->write_ibi_reg(fc,dma2_01c,v0xc); + } + + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config); + +static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + v.dma_0xc.remap_enable = onoff; + fc->write_ibi_reg(fc,r,v); + return 0; +} + +/* 1 cycles = 1.97 msec */ +int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + + flexcop_dma_remap(fc,dma_idx,0); + + v.dma_0x4_write.dmatimer = cycles >> 1; + fc->write_ibi_reg(fc,r,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config_timer); + +int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets) +{ + flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014; + flexcop_ibi_value v = fc->read_ibi_reg(fc,r); + + flexcop_dma_remap(fc,dma_idx,1); + + v.dma_0x4_remap.DMA_maxpackets = packets; + fc->write_ibi_reg(fc,r,v); + return 0; +} +EXPORT_SYMBOL(flexcop_dma_config_packet_count); diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c new file mode 100644 index 000000000..bbcf070a1 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c @@ -0,0 +1,153 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-eeprom.c - eeprom access methods (currently only MAC address reading is used) + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +#if 0 +/*EEPROM (Skystar2 has one "24LC08B" chip on board) */ +static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len) +{ + return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len); +} + +static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries) +{ + int i; + + for (i = 0; i < retries; i++) { + if (eeprom_write(adapter, addr, wbuf, len) == len) { + if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1) + return 1; + } + } + + return 0; +} + +/* These functions could be used to unlock SkyStar2 cards. */ + +static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len) +{ + u8 rbuf[20]; + u8 wbuf[20]; + + if (len != 16) + return 0; + + memcpy(wbuf, key, len); + + wbuf[16] = 0; + wbuf[17] = 0; + wbuf[18] = 0; + wbuf[19] = calc_lrc(wbuf, 19); + + return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4); +} + +static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len) +{ + u8 buf[20]; + + if (len != 16) + return 0; + + if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0) + return 0; + + memcpy(key, buf, len); + + return 1; +} + +static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac) +{ + u8 tmp[8]; + + if (type != 0) { + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[5]; + tmp[4] = mac[6]; + tmp[5] = mac[7]; + + } else { + + tmp[0] = mac[0]; + tmp[1] = mac[1]; + tmp[2] = mac[2]; + tmp[3] = mac[3]; + tmp[4] = mac[4]; + tmp[5] = mac[5]; + } + + tmp[6] = 0; + tmp[7] = calc_lrc(tmp, 7); + + if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8) + return 1; + + return 0; +} + +static int flexcop_eeprom_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len) +{ + return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len); +} + +#endif + +static u8 calc_lrc(u8 *buf, int len) +{ + int i; + u8 sum = 0; + for (i = 0; i < len; i++) + sum = sum ^ buf[i]; + return sum; +} + +static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries) +{ + int i,ret = 0; + u8 chipaddr = 0x50 | ((addr >> 8) & 3); + for (i = 0; i < retries; i++) + if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0) + break; + return ret; +} + +static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries) +{ + int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries); + if (ret == 0) + if (calc_lrc(buf, len - 1) != buf[len - 1]) + ret = -EINVAL; + return ret; +} + +/* JJ's comment about extended == 1: it is not presently used anywhere but was + * added to the low-level functions for possible support of EUI64 + */ +int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) +{ + u8 buf[8]; + int ret = 0; + + if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { + if (extended != 0) { + err("TODO: extended (EUI64) MAC addresses aren't completely supported yet"); + ret = -EINVAL; +/* memcpy(fc->dvb_adapter.proposed_mac,buf,3); + mac[3] = 0xfe; + mac[4] = 0xff; + memcpy(&fc->dvb_adapter.proposed_mac[3],&buf[5],3); */ + } else + memcpy(fc->dvb_adapter.proposed_mac,buf,6); + } + return ret; +} +EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr); diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c new file mode 100644 index 000000000..2baf43d3c --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c @@ -0,0 +1,204 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-hw-filter.c - pid and mac address filtering and corresponding control functions. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff); +} + +void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,SMC_Enable_sig,onoff); +} + +void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,Null_filter_sig,onoff); +} + +void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]) +{ + flexcop_ibi_value v418,v41c; + v41c = fc->read_ibi_reg(fc,mac_address_41c); + + v418.mac_address_418.MAC1 = mac[0]; + v418.mac_address_418.MAC2 = mac[1]; + v418.mac_address_418.MAC3 = mac[2]; + v418.mac_address_418.MAC6 = mac[3]; + v41c.mac_address_41c.MAC7 = mac[4]; + v41c.mac_address_41c.MAC8 = mac[5]; + + fc->write_ibi_reg(fc,mac_address_418,v418); + fc->write_ibi_reg(fc,mac_address_41c,v41c); +} + +void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,MAC_filter_Mode_sig,onoff); +} + +static void flexcop_pid_group_filter(struct flexcop_device *fc, u16 pid, u16 mask) +{ + /* index_reg_310.extra_index_reg need to 0 or 7 to work */ + flexcop_ibi_value v30c; + v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid; + v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask; + fc->write_ibi_reg(fc,pid_filter_30c,v30c); +} + +static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff) +{ + flexcop_set_ibi_value(ctrl_208,Mask_filter_sig,onoff); +} + +/* this fancy define reduces the code size of the quite similar PID controlling of + * the first 6 PIDs + */ + +#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \ + flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \ + v208 = fc->read_ibi_reg(fc, ctrl_208); \ +\ + vpid.vregname.field = onoff ? pid : 0x1fff; \ + vpid.vregname.trans_field = transval; \ + v208.ctrl_208.enablefield = onoff; \ +\ + fc->write_ibi_reg(fc,vregname,vpid); \ + fc->write_ibi_reg(fc,ctrl_208,v208); + +static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_300,Stream1_PID,Stream1_filter_sig,Stream1_trans,0); +} + +static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_300,Stream2_PID,Stream2_filter_sig,Stream2_trans,0); +} + +static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_304,PCR_PID,PCR_filter_sig,PCR_trans,0); +} + +static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_304,PMT_PID,PMT_filter_sig,PMT_trans,0); +} + +static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_308,EMM_PID,EMM_filter_sig,EMM_trans,0); +} + +static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) +{ + pid_ctrl(pid_filter_308,ECM_PID,ECM_filter_sig,ECM_trans,0); +} + +static void flexcop_pid_control(struct flexcop_device *fc, int index, u16 pid,int onoff) +{ + if (pid == 0x2000) + return; + + deb_ts("setting pid: %5d %04x at index %d '%s'\n",pid,pid,index,onoff ? "on" : "off"); + + /* We could use bit magic here to reduce source code size. + * I decided against it, but to use the real register names */ + switch (index) { + case 0: flexcop_pid_Stream1_PID_ctrl(fc,pid,onoff); break; + case 1: flexcop_pid_Stream2_PID_ctrl(fc,pid,onoff); break; + case 2: flexcop_pid_PCR_PID_ctrl(fc,pid,onoff); break; + case 3: flexcop_pid_PMT_PID_ctrl(fc,pid,onoff); break; + case 4: flexcop_pid_EMM_PID_ctrl(fc,pid,onoff); break; + case 5: flexcop_pid_ECM_PID_ctrl(fc,pid,onoff); break; + default: + if (fc->has_32_hw_pid_filter && index < 38) { + flexcop_ibi_value vpid,vid; + + /* set the index */ + vid = fc->read_ibi_reg(fc,index_reg_310); + vid.index_reg_310.index_reg = index - 6; + fc->write_ibi_reg(fc,index_reg_310, vid); + + vpid = fc->read_ibi_reg(fc,pid_n_reg_314); + vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff; + vpid.pid_n_reg_314.PID_enable_bit = onoff; + fc->write_ibi_reg(fc,pid_n_reg_314, vpid); + } + break; + } +} + +static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc,int onoff) +{ + if (fc->fullts_streaming_state != onoff) { + deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling"); + flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff)); + flexcop_pid_group_filter_ctrl(fc,onoff); + fc->fullts_streaming_state = onoff; + } + return 0; +} + +int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32; + + fc->feedcount += onoff ? 1 : -1; + if (dvbdmxfeed->index >= max_pid_filter) + fc->extra_feedcount += onoff ? 1 : -1; + + /* toggle complete-TS-streaming when: + * - pid_filtering is not enabled and it is the first or last feed requested + * - pid_filtering is enabled, + * - but the number of requested feeds is exceeded + * - or the requested pid is 0x2000 */ + + if (!fc->pid_filtering && fc->feedcount == onoff) + flexcop_toggle_fullts_streaming(fc,onoff); + + if (fc->pid_filtering) { + flexcop_pid_control(fc,dvbdmxfeed->index,dvbdmxfeed->pid,onoff); + + if (fc->extra_feedcount > 0) + flexcop_toggle_fullts_streaming(fc,1); + else if (dvbdmxfeed->pid == 0x2000) + flexcop_toggle_fullts_streaming(fc,onoff); + else + flexcop_toggle_fullts_streaming(fc,0); + } + + /* if it was the first or last feed request change the stream-status */ + if (fc->feedcount == onoff) { + flexcop_rcv_data_ctrl(fc,onoff); + if (fc->stream_control) + fc->stream_control(fc,onoff); + } + + return 0; +} + +void flexcop_hw_filter_init(struct flexcop_device *fc) +{ + int i; + flexcop_ibi_value v; + for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++) + flexcop_pid_control(fc,i,0x1fff,0); + + flexcop_pid_group_filter(fc, 0, 0x1fe0); + flexcop_pid_group_filter_ctrl(fc,0); + + v = fc->read_ibi_reg(fc,pid_filter_308); + v.pid_filter_308.EMM_filter_4 = 1; + v.pid_filter_308.EMM_filter_6 = 0; + fc->write_ibi_reg(fc,pid_filter_308,v); + + flexcop_null_filter_ctrl(fc, 1); +} diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c new file mode 100644 index 000000000..19e06da46 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-misc.c @@ -0,0 +1,66 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-misc.c - miscellaneous functions. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +void flexcop_determine_revision(struct flexcop_device *fc) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); + + switch (v.misc_204.Rev_N_sig_revision_hi) { + case 0x2: + deb_info("found a FlexCopII.\n"); + fc->rev = FLEXCOP_II; + break; + case 0x3: + deb_info("found a FlexCopIIb.\n"); + fc->rev = FLEXCOP_IIB; + break; + case 0x0: + deb_info("found a FlexCopIII.\n"); + fc->rev = FLEXCOP_III; + break; + default: + err("unkown FlexCop Revision: %x. Please report the linux-dvb@linuxtv.org.",v.misc_204.Rev_N_sig_revision_hi); + break; + } + + if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps)) + deb_info("this FlexCop has the additional 32 hardware pid filter.\n"); + else + deb_info("this FlexCop has only the 6 basic main hardware pid filter.\n"); + /* bus parts have to decide if hw pid filtering is used or not. */ +} + +const char *flexcop_revision_names[] = { + "Unkown chip", + "FlexCopII", + "FlexCopIIb", + "FlexCopIII", +}; + +const char *flexcop_device_names[] = { + "Unkown device", + "AirStar 2 DVB-T", + "AirStar 2 ATSC", + "SkyStar 2 DVB-S", + "SkyStar 2 DVB-S (old version)", + "CableStar 2 DVB-C", +}; + +const char *flexcop_bus_names[] = { + "USB", + "PCI", +}; + +void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const + char *suffix) +{ + info("%s '%s' at the '%s' bus controlled by a '%s' %s",prefix, + flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type], + flexcop_revision_names[fc->rev],suffix); +} diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h new file mode 100644 index 000000000..5e131be55 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-reg.h @@ -0,0 +1,701 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII + * + * see flexcop.c for copyright information. + */ +#ifndef __FLEXCOP_REG_H__ +#define __FLEXCOP_REG_H__ + + +typedef enum { + FLEXCOP_UNK = 0, + FLEXCOP_II, + FLEXCOP_IIB, + FLEXCOP_III, +} flexcop_revision_t; + +extern const char *flexcop_revision_names[]; + +typedef enum { + FC_UNK = 0, + FC_AIR_DVB, + FC_AIR_ATSC, + FC_SKY, + FC_SKY_OLD, + FC_CABLE, +} flexcop_device_type_t; + +typedef enum { + FC_USB = 0, + FC_PCI, +} flexcop_bus_t; + +extern const char *flexcop_device_names[]; + +/* FlexCop IBI Registers */ + +/* flexcop_ibi_reg - a huge union representing the register structure */ +typedef union { + u32 raw; + +/* DMA 0x000 to 0x01c + * DMA1 0x000 to 0x00c + * DMA2 0x010 to 0x01c + */ + struct { + u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */ + u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */ + u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */ + } dma_0x0; + + struct { + u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable + is able to be read and written while bit(1) of register + 0x00c (remap_enable) is set. This variable represents + the number of packets that will be transmitted to the PCI + host using PCI DMA1 before an interrupt to the PCI is + asserted. This functionality may be enabled using bit(20) + of register 0x208. N=0 disables the IRQ. */ + u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */ + } dma_0x4_remap; + + struct { + u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */ + u32 unused : 1; + u32 dma_addr_size :24; + } dma_0x4_read; + + struct { + u32 unused : 1; + u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */ + u32 dma_addr_size :24; + } dma_0x4_write; + + struct { + u32 unused : 2; + u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */ + } dma_0x8; + + struct { + u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */ + u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */ + u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */ + } dma_0xc; + +/* Two-wire Serial Master and Clock 0x100-0x110 */ + struct { +// u32 slave_transmitter : 1; /* ???*/ + u32 chipaddr : 7; /* two-line serial address of the target slave */ + u32 reserved1 : 1; + u32 baseaddr : 8; /* address of the location of the read/write operation */ + u32 data1_reg : 8; /* first byte in two-line serial read/write operation */ + u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready + * set to 1 when doing a write operation */ + u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */ + u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/ + u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */ + u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o + * preceding address assignment write frame + * ACK_ERROR = 1 when no ACK from slave in the last transaction */ + u32 st_done : 1; /* indicator for transaction is done */ + } tw_sm_c_100; + + struct { + u32 data2_reg : 8; /* 2nd data byte */ + u32 data3_reg : 8; /* 3rd data byte */ + u32 data4_reg : 8; /* 4th data byte */ + u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */ + u32 force_stop : 1; /* isolated stop flag */ + u32 unused : 6; + } tw_sm_c_104; + +/* Clock. The register allows the FCIII to convert an incoming Master clock + * (MCLK) signal into a lower frequency clock through the use of a LowCounter + * (TLO) and a High- Counter (THI). The time counts for THI and TLO are + * measured in MCLK; each count represents 4 MCLK input clock cycles. + * + * The default output for port #1 is set for Front End Demod communication. (0x108) + * The default output for port #2 is set for EEPROM communication. (0x10c) + * The default output for port #3 is set for Tuner communication. (0x110) + */ + struct { + u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */ + u32 reserved1 : 2; + u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */ + u32 reserved2 :19; + } tw_sm_c_108; + + struct { + u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */ + u32 reserved1 : 2; + u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */ + u32 reserved2 :19; + } tw_sm_c_10c; + + struct { + u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */ + u32 reserved1 : 2; + u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */ + u32 reserved2 :19; + } tw_sm_c_110; + +/* LNB Switch Frequency 0x200 + * Clock that creates the LNB switch tone. The default is set to have a fixed + * low output (not oscillating) to the LNB_CTL line. + */ + struct { + u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */ + u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master + Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */ + u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */ + } lnb_switch_freq_200; + +/* ACPI, Peripheral Reset, LNB Polarity + * ACPI power conservation mode, LNB polarity selection (low or high voltage), + * and peripheral reset. + */ + struct { + u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */ + u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */ + u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */ + u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */ + u32 reserved :20; + u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */ + u32 Rev_N_sig_reserved1 : 2; + u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */ + u32 Rev_N_sig_reserved2 : 1; + } misc_204; + +/* Control and Status 0x208 to 0x21c */ +/* Gross enable and disable control */ + struct { + u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */ + u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */ + u32 PCR_filter_sig : 1; /* PCR PID filter */ + u32 PMT_filter_sig : 1; /* PMT PID filter */ + + u32 EMM_filter_sig : 1; /* EMM PID filter */ + u32 ECM_filter_sig : 1; /* ECM PID filter */ + u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */ + u32 Mask_filter_sig : 1; /* mask PID filter */ + + u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */ + u32 WAN_CA_Enable_sig : 1; /* not in FCIII */ + u32 CA_Enable_sig : 1; /* not in FCIII */ + u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */ + + u32 Per_CA_Enable_sig : 1; /* not in FCIII */ + u32 Multi2_Enable_sig : 1; /* ? */ + u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */ + u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will + examine and process packets according to all other (individual) PID + filtering controls. If it a zero, no packet processing of any kind will + take place. All data from the tuner will be thrown away. */ + + u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI + * interrupt after the specified count for filling the buffer. */ + u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt + after a specified amount of time. */ + u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */ + u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */ + + u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */ + u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */ + u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the + PCI host to indicate that mailbox data is available. */ + + u32 unused : 9; + } ctrl_208; + +/* General status. When a PCI interrupt occurs, this register is read to + * discover the reason for the interrupt. + */ + struct { + u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */ + u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */ + u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */ + u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */ + u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */ + u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/ + u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */ + u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */ + u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */ + u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */ + u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */ + u32 reserved :21; + } irq_20c; + + +/* Software reset register */ + struct { + u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00. + Each bit location represents a 0x100 block of registers. Writing + a one in a bit location resets that block of registers and the logic + that it controls. */ + u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */ + u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A; + Turns off pci encryption => 0xC259 Note: pci_encryption default + at power-up is ON. */ + } sw_reset_210; + + struct { + u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART + (RS-232 Smart Card interface). When set, the IBI interface + defined by register 0x600 controls the serial UART. */ + u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line + Serial Master EEPROM target. When set, the Two-line Serial Master + EEPROM target interface is controlled by IBI register 0x100. */ + u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space + bus masters. Once this signal is cleared, normal V8-space + operations resume. */ + u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry + to process section packed transport streams. */ + u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data + within the FlexCop3 front end circuitry is converted from a serial + stream into parallel data before downstream processing otherwise + interprets the data. */ + u32 unused1 : 3; + u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport + stream CLOCK signal before any processing occurs on the transport + stream within FlexCop3. */ + u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport + stream VALID signal before any processing occurs on the transport + stream within FlexCop3. */ + u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport + stream SYNC signal before any processing occurs on the transport + stream within FlexCop3. */ + u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport + stream ERROR signal before any processing occurs on the transport + stream within FlexCop3. */ + u32 unused2 :20; + } misc_214; + +/* Mailbox from V8 to host */ + struct { + u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an + end host, an interrupt is generated to the PCI host to indicate + that mailbox data is available. Reading register 20c will clear + the IRQ. */ + } mbox_v8_to_host_218; + +/* Mailbox from host to v8 Mailbox_to_V8 + * Mailbox_to_V8 mailbox storage register + * used to send messages from PCI to V8. Writing to this register will send an + * IRQ to the V8. Then it can read the data from here. Reading this register + * will clear the IRQ. If the V8 is halted and bit 31 of this register is set, + * then this register is used instead as a direct interface to access the + * V8space memory. + */ + struct { + u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */ + u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */ + u32 unused : 7; + u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */ + u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows + this IBI register interface to directly drive the V8-space memory. */ + } mbox_host_to_v8_21c; + + +/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */ + struct { + u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally + hold the PID value for the desired network stream. */ + u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */ + u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */ + u32 debug_flag_pid_saved : 1; + u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */ + u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in + Stream2_PID TS packets. */ + u32 debug_flag_write_status00 : 1; + u32 debug_fifo_problem : 1; + } pid_filter_300; + + struct { + u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */ + u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 debug_overrun3 : 1; + u32 debug_overrun2 : 1; + u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */ + u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 reserved : 2; + } pid_filter_304; + + struct { + u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for + conditional access-related data. */ + u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the + first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */ + u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users + complete 6-byte Smart Card ID number. */ + u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional + access-related data. */ + u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 reserved : 2; + } pid_filter_308; + + struct { + u32 Group_PID :13; /* PID value for group filtering. */ + u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */ + u32 unused1 : 2; + u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */ + u32 unused2 : 3; + } pid_filter_30c_ext_ind_0_7; + + struct { + u32 net_master_read :17; + u32 unused :15; + } pid_filter_30c_ext_ind_1; + + struct { + u32 net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_2; + + struct { + u32 next_net_master_write :17; + u32 unused :15; + } pid_filter_30c_ext_ind_3; + + struct { + u32 unused1 : 1; + u32 state_write :10; + u32 reserved1 : 6; /* default: 000100 */ + u32 stack_read :10; + u32 reserved2 : 5; /* default: 00100 */ + } pid_filter_30c_ext_ind_4; + + struct { + u32 stack_cnt :10; + u32 unused :22; + } pid_filter_30c_ext_ind_5; + + struct { + u32 pid_fsm_save_reg0 : 2; + u32 pid_fsm_save_reg1 : 2; + u32 pid_fsm_save_reg2 : 2; + u32 pid_fsm_save_reg3 : 2; + u32 pid_fsm_save_reg4 : 2; + u32 pid_fsm_save_reg300 : 2; + u32 write_status1 : 2; + u32 write_status4 : 2; + u32 data_size_reg :12; + u32 unused : 4; + } pid_filter_30c_ext_ind_6; + + struct { + u32 index_reg : 5; /* (Index pointer) Points at an internal PIDn register. A binary code + representing one of 32 internal PIDn registers as well as its + corresponding internal MAC_lown register. */ + u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */ + u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register + 0=MAC_highB register, 1=MAC_highA */ + u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400. + All types of networks (DVB, ATSC, ISDB) are passed. */ + u32 unused :22; + } index_reg_310; + + struct { + u32 PID :13; /* PID value */ + u32 PID_trans : 1; /* translation will take place for packets filtered */ + u32 PID_enable_bit : 1; /* When set this PID filter is enabled */ + u32 reserved :17; + } pid_n_reg_314; + + struct { + u32 A4_byte : 8; + u32 A5_byte : 8; + u32 A6_byte : 8; + u32 Enable_bit : 1; /* enabled (1) or disabled (1) */ + u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */ + u32 reserved : 6; + } mac_low_reg_318; + + struct { + u32 A1_byte : 8; + u32 A2_byte : 8; + u32 A3_byte : 8; + u32 reserved : 8; + } mac_high_reg_31c; + +/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */ + struct { + u32 reserved :16; +#define fc_data_Tag_ID_DVB 0x3e +#define fc_data_Tag_ID_ATSC 0x3f +#define fc_data_Tag_ID_IDSB 0x8b + u32 data_Tag_ID :16; + } data_tag_400; + + struct { + u32 Card_IDbyte6 : 8; + u32 Card_IDbyte5 : 8; + u32 Card_IDbyte4 : 8; + u32 Card_IDbyte3 : 8; + } card_id_408; + + struct { + u32 Card_IDbyte2 : 8; + u32 Card_IDbyte1 : 8; + } card_id_40c; + + /* holding the unique mac address of the receiver which houses the FlexCopIII */ + struct { + u32 MAC1 : 8; + u32 MAC2 : 8; + u32 MAC3 : 8; + u32 MAC6 : 8; + } mac_address_418; + + struct { + u32 MAC7 : 8; + u32 MAC8 : 8; + u32 reserved : 16; + } mac_address_41c; + + struct { + u32 transmitter_data_byte : 8; + u32 ReceiveDataReady : 1; + u32 ReceiveByteFrameError: 1; + u32 txbuffempty : 1; + u32 reserved :21; + } ci_600; + + struct { + u32 pi_d : 8; + u32 pi_ha :20; + u32 pi_rw : 1; + u32 pi_component_reg : 3; + } pi_604; + + struct { + u32 serialReset : 1; + u32 oncecycle_read : 1; + u32 Timer_Read_req : 1; + u32 Timer_Load_req : 1; + u32 timer_data : 7; + u32 unused : 1; /* ??? not mentioned in data book */ + u32 Timer_addr : 5; + u32 reserved : 3; + u32 pcmcia_a_mod_pwr_n : 1; + u32 pcmcia_b_mod_pwr_n : 1; + u32 config_Done_stat : 1; + u32 config_Init_stat : 1; + u32 config_Prog_n : 1; + u32 config_wr_n : 1; + u32 config_cs_n : 1; + u32 config_cclk : 1; + u32 pi_CiMax_IRQ_n : 1; + u32 pi_timeout_status : 1; + u32 pi_wait_n : 1; + u32 pi_busy_n : 1; + } pi_608; + + struct { + u32 PID :13; + u32 key_enable : 1; +#define fc_key_code_default 0x1 +#define fc_key_code_even 0x2 +#define fc_key_code_odd 0x3 + u32 key_code : 2; + u32 key_array_col : 3; + u32 key_array_row : 5; + u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */ + u32 rw_flag : 1; + u32 reserved : 6; + } dvb_reg_60c; + +/* SRAM and Output Destination 0x700 to 0x714 */ + struct { + u32 sram_addr :15; + u32 sram_rw : 1; /* 0=write, 1=read */ + u32 sram_data : 8; + u32 sc_xfer_bit : 1; + u32 reserved1 : 3; + u32 oe_pin_reg : 1; + u32 ce_pin_reg : 1; + u32 reserved2 : 1; + u32 start_sram_ibi : 1; + } sram_ctrl_reg_700; + + struct { + u32 net_addr_read :16; + u32 net_addr_write :16; + } net_buf_reg_704; + + struct { + u32 cai_read :11; + u32 reserved1 : 5; + u32 cai_write :11; + u32 reserved2 : 6; + u32 cai_cnt : 4; + } cai_buf_reg_708; + + struct { + u32 cao_read :11; + u32 reserved1 : 5; + u32 cap_write :11; + u32 reserved2 : 6; + u32 cao_cnt : 4; + } cao_buf_reg_70c; + + struct { + u32 media_read :11; + u32 reserved1 : 5; + u32 media_write :11; + u32 reserved2 : 6; + u32 media_cnt : 4; + } media_buf_reg_710; + + struct { + u32 NET_Dest : 2; + u32 CAI_Dest : 2; + u32 CAO_Dest : 2; + u32 MEDIA_Dest : 2; + u32 net_ovflow_error : 1; + u32 media_ovflow_error : 1; + u32 cai_ovflow_error : 1; + u32 cao_ovflow_error : 1; + u32 ctrl_usb_wan : 1; + u32 ctrl_sramdma : 1; + u32 ctrl_maximumfill : 1; + u32 reserved :17; + } sram_dest_reg_714; + + struct { + u32 net_cnt :12; + u32 reserved1 : 4; + u32 net_addr_read : 1; + u32 reserved2 : 3; + u32 net_addr_write : 1; + u32 reserved3 :11; + } net_buf_reg_718; + + struct { + u32 wan_speed_sig : 2; + u32 reserved1 : 6; + u32 wan_wait_state : 8; + u32 sram_chip : 2; + u32 sram_memmap : 2; + u32 reserved2 : 4; + u32 wan_pkt_frame : 4; + u32 reserved3 : 4; + } wan_ctrl_reg_71c; +} flexcop_ibi_value; + +extern flexcop_ibi_value ibi_zero; + +typedef enum { + FC_I2C_PORT_DEMOD = 1, + FC_I2C_PORT_EEPROM = 2, + FC_I2C_PORT_TUNER = 3, +} flexcop_i2c_port_t; + +typedef enum { + FC_WRITE = 0, + FC_READ = 1, +} flexcop_access_op_t; + +typedef enum { + FC_SRAM_DEST_NET = 1, + FC_SRAM_DEST_CAI = 2, + FC_SRAM_DEST_CAO = 4, + FC_SRAM_DEST_MEDIA = 8 +} flexcop_sram_dest_t; + +typedef enum { + FC_SRAM_DEST_TARGET_WAN_USB = 0, + FC_SRAM_DEST_TARGET_DMA1 = 1, + FC_SRAM_DEST_TARGET_DMA2 = 2, + FC_SRAM_DEST_TARGET_FC3_CA = 3 +} flexcop_sram_dest_target_t; + +typedef enum { + FC_SRAM_2_32KB = 0, /* 64KB */ + FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */ + FC_SRAM_1_128KB = 2, /* 128KB */ + FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */ +} flexcop_sram_type_t; + +typedef enum { + FC_WAN_SPEED_4MBITS = 0, + FC_WAN_SPEED_8MBITS = 1, + FC_WAN_SPEED_12MBITS = 2, + FC_WAN_SPEED_16MBITS = 3, +} flexcop_wan_speed_t; + +typedef enum { + FC_DMA_1 = 1, + FC_DMA_2 = 2, +} flexcop_dma_index_t; + +typedef enum { + FC_DMA_SUBADDR_0 = 1, + FC_DMA_SUBADDR_1 = 2, +} flexcop_dma_addr_index_t; + +/* names of the particular registers */ +typedef enum { + dma1_000 = 0x000, + dma1_004 = 0x004, + dma1_008 = 0x008, + dma1_00c = 0x00c, + dma2_010 = 0x010, + dma2_014 = 0x014, + dma2_018 = 0x018, + dma2_01c = 0x01c, + + tw_sm_c_100 = 0x100, + tw_sm_c_104 = 0x104, + tw_sm_c_108 = 0x108, + tw_sm_c_10c = 0x10c, + tw_sm_c_110 = 0x110, + + lnb_switch_freq_200 = 0x200, + misc_204 = 0x204, + ctrl_208 = 0x208, + irq_20c = 0x20c, + sw_reset_210 = 0x210, + misc_214 = 0x214, + mbox_v8_to_host_218 = 0x218, + mbox_host_to_v8_21c = 0x21c, + + pid_filter_300 = 0x300, + pid_filter_304 = 0x304, + pid_filter_308 = 0x308, + pid_filter_30c = 0x30c, + index_reg_310 = 0x310, + pid_n_reg_314 = 0x314, + mac_low_reg_318 = 0x318, + mac_high_reg_31c = 0x31c, + + data_tag_400 = 0x400, + card_id_408 = 0x408, + card_id_40c = 0x40c, + mac_address_418 = 0x418, + mac_address_41c = 0x41c, + + ci_600 = 0x600, + pi_604 = 0x604, + pi_608 = 0x608, + dvb_reg_60c = 0x60c, + + sram_ctrl_reg_700 = 0x700, + net_buf_reg_704 = 0x704, + cai_buf_reg_708 = 0x708, + cao_buf_reg_70c = 0x70c, + media_buf_reg_710 = 0x710, + sram_dest_reg_714 = 0x714, + net_buf_reg_718 = 0x718, + wan_ctrl_reg_71c = 0x71c, +} flexcop_ibi_register; + +#define flexcop_set_ibi_value(reg,attr,val) { \ + flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \ + v.reg.attr = val; \ + fc->write_ibi_reg(fc,reg,v); \ +} + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop-sram.c b/drivers/media/dvb/b2c2/flexcop-sram.c new file mode 100644 index 000000000..01570ec80 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-sram.c @@ -0,0 +1,403 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop-sram.c - functions for controlling the SRAM. + * + * see flexcop.c for copyright information. + */ +#include "flexcop.h" + +static void flexcop_sram_set_chip (struct flexcop_device *fc, flexcop_sram_type_t type) +{ + flexcop_set_ibi_value(wan_ctrl_reg_71c,sram_chip,type); +} + +int flexcop_sram_init(struct flexcop_device *fc) +{ + switch (fc->rev) { + case FLEXCOP_II: + case FLEXCOP_IIB: + flexcop_sram_set_chip(fc,FC_SRAM_1_32KB); + break; + case FLEXCOP_III: + flexcop_sram_set_chip(fc,FC_SRAM_1_48KB); + break; + default: + return -EINVAL; + } + return 0; +} + +int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target) +{ + flexcop_ibi_value v; + + v = fc->read_ibi_reg(fc,sram_dest_reg_714); + + if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) { + err("SRAM destination target to available on FlexCopII(b)\n"); + return -EINVAL; + } + + deb_sram("sram dest: %x target: %x\n",dest, target); + + if (dest & FC_SRAM_DEST_NET) + v.sram_dest_reg_714.NET_Dest = target; + if (dest & FC_SRAM_DEST_CAI) + v.sram_dest_reg_714.CAI_Dest = target; + if (dest & FC_SRAM_DEST_CAO) + v.sram_dest_reg_714.CAO_Dest = target; + if (dest & FC_SRAM_DEST_MEDIA) + v.sram_dest_reg_714.MEDIA_Dest = target; + + fc->write_ibi_reg(fc,sram_dest_reg_714,v); + udelay(1000); /* TODO delay really necessary */ + + return 0; +} +EXPORT_SYMBOL(flexcop_sram_set_dest); + +void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s) +{ + flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s); +} +EXPORT_SYMBOL(flexcop_wan_set_speed); + +void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill) +{ + flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714); + v.sram_dest_reg_714.ctrl_usb_wan = usb_wan; + v.sram_dest_reg_714.ctrl_sramdma = sramdma; + v.sram_dest_reg_714.ctrl_maximumfill = maximumfill; + fc->write_ibi_reg(fc,sram_dest_reg_714,v); +} +EXPORT_SYMBOL(flexcop_sram_ctrl); + +#if 0 +static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) +{ + int i, retries; + u32 command; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04000000 | (*buf << 0x10); + + retries = 2; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + write_reg_dw(adapter, 0x700, command); + + buf++; + addr++; + } +} + +static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len) +{ + int i, retries; + u32 command, value; + + for (i = 0; i < len; i++) { + command = bank | addr | 0x04008000; + + retries = 10000; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + write_reg_dw(adapter, 0x700, command); + + retries = 10000; + + while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) { + mdelay(1); + retries--; + }; + + if (retries == 0) + printk("%s: SRAM timeout\n", __FUNCTION__); + + value = read_reg_dw(adapter, 0x700) >> 0x10; + + *buf = (value & 0xff); + + addr++; + buf++; + } +} + +static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) +{ + u32 bank; + + bank = 0; + + if (adapter->dw_sram_type == 0x20000) { + bank = (addr & 0x18000) << 0x0d; + } + + if (adapter->dw_sram_type == 0x00000) { + if ((addr >> 0x0f) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + + flex_sram_write(adapter, bank, addr & 0x7fff, buf, len); +} + +static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len) +{ + u32 bank; + + bank = 0; + + if (adapter->dw_sram_type == 0x20000) { + bank = (addr & 0x18000) << 0x0d; + } + + if (adapter->dw_sram_type == 0x00000) { + if ((addr >> 0x0f) == 0) + bank = 0x20000000; + else + bank = 0x10000000; + } + + flex_sram_read(adapter, bank, addr & 0x7fff, buf, len); +} + +static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len) +{ + u32 length; + + while (len != 0) { + length = len; + + // check if the address range belongs to the same + // 32K memory chip. If not, the data is read from + // one chip at a time. + if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { + length = (((addr >> 0x0f) + 1) << 0x0f) - addr; + } + + sram_read_chunk(adapter, addr, buf, length); + + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len) +{ + u32 length; + + while (len != 0) { + length = len; + + // check if the address range belongs to the same + // 32K memory chip. If not, the data is written to + // one chip at a time. + if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) { + length = (((addr >> 0x0f) + 1) << 0x0f) - addr; + } + + sram_write_chunk(adapter, addr, buf, length); + + addr = addr + length; + buf = buf + length; + len = len - length; + } +} + +static void sram_set_size(struct adapter *adapter, u32 mask) +{ + write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c)))); +} + +static void sram_init(struct adapter *adapter) +{ + u32 tmp; + + tmp = read_reg_dw(adapter, 0x71c); + + write_reg_dw(adapter, 0x71c, 1); + + if (read_reg_dw(adapter, 0x71c) != 0) { + write_reg_dw(adapter, 0x71c, tmp); + + adapter->dw_sram_type = tmp & 0x30000; + + ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); + + } else { + + adapter->dw_sram_type = 0x10000; + + ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type); + } + + /* return value is never used? */ +/* return adapter->dw_sram_type; */ +} + +static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr) +{ + u8 tmp1, tmp2; + + dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr); + + sram_set_size(adapter, mask); + sram_init(adapter); + + tmp2 = 0xa5; + tmp1 = 0x4f; + + sram_write(adapter, addr, &tmp2, 1); + sram_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + + mdelay(20); + + sram_read(adapter, addr, &tmp2, 1); + sram_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2); + + if (tmp2 != 0xa5) + return 0; + + tmp2 = 0x5a; + tmp1 = 0xf4; + + sram_write(adapter, addr, &tmp2, 1); + sram_write(adapter, addr + 4, &tmp1, 1); + + tmp2 = 0; + + mdelay(20); + + sram_read(adapter, addr, &tmp2, 1); + sram_read(adapter, addr, &tmp2, 1); + + dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2); + + if (tmp2 != 0x5a) + return 0; + + return 1; +} + +static u32 sram_length(struct adapter *adapter) +{ + if (adapter->dw_sram_type == 0x10000) + return 32768; // 32K + if (adapter->dw_sram_type == 0x00000) + return 65536; // 64K + if (adapter->dw_sram_type == 0x20000) + return 131072; // 128K + + return 32768; // 32K +} + +/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory. + - for 128K there are 4x32K chips at bank 0,1,2,3. + - for 64K there are 2x32K chips at bank 1,2. + - for 32K there is one 32K chip at bank 0. + + FlexCop works only with one bank at a time. The bank is selected + by bits 28-29 of the 0x700 register. + + bank 0 covers addresses 0x00000-0x07fff + bank 1 covers addresses 0x08000-0x0ffff + bank 2 covers addresses 0x10000-0x17fff + bank 3 covers addresses 0x18000-0x1ffff +*/ + +static int flexcop_sram_detect(struct flexcop_device *fc) +{ + flexcop_ibi_value r208,r71c_0,vr71c_1; + + r208 = fc->read_ibi_reg(fc, ctrl_208); + fc->write_ibi_reg(fc, ctrl_208, ibi_zero); + + r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c); + + write_reg_dw(adapter, 0x71c, 1); + + tmp3 = read_reg_dw(adapter, 0x71c); + + dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3); + + write_reg_dw(adapter, 0x71c, tmp2); + + // check for internal SRAM ??? + tmp3--; + if (tmp3 != 0) { + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: sram size = 32K\n", __FUNCTION__); + + return 32; + } + + if (sram_test_location(adapter, 0x20000, 0x18000) != 0) { + sram_set_size(adapter, 0x20000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: sram size = 128K\n", __FUNCTION__); + + return 128; + } + + if (sram_test_location(adapter, 0x00000, 0x10000) != 0) { + sram_set_size(adapter, 0x00000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: sram size = 64K\n", __FUNCTION__); + + return 64; + } + + if (sram_test_location(adapter, 0x10000, 0x00000) != 0) { + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: sram size = 32K\n", __FUNCTION__); + + return 32; + } + + sram_set_size(adapter, 0x10000); + sram_init(adapter); + write_reg_dw(adapter, 0x208, tmp); + + dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__); + + return 0; +} + +static void sll_detect_sram_size(struct adapter *adapter) +{ + sram_detect_for_flex2(adapter); +} + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop-usb.h b/drivers/media/dvb/b2c2/flexcop-usb.h new file mode 100644 index 000000000..630e647a2 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop-usb.h @@ -0,0 +1,119 @@ +#ifndef __FLEXCOP_USB_H_INCLUDED__ +#define __FLEXCOP_USB_H_INCLUDED__ + +#include + +/* transfer parameters */ +#define B2C2_USB_FRAMES_PER_ISO 4 +#define B2C2_USB_NUM_ISO_URB 4 + +#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev,0) +#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev,0) +#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev,0x81) + +struct flexcop_usb { + struct usb_device *udev; + struct usb_interface *uintf; + + u8 *iso_buffer; + int buffer_size; + dma_addr_t dma_addr; + struct urb *iso_urb[B2C2_USB_NUM_ISO_URB]; + + struct flexcop_device *fc_dev; + + u8 tmp_buffer[1023+190]; + int tmp_buffer_length; +}; + +#if 0 +/* request types TODO What is its use?*/ +typedef enum { + +/* something is wrong with this part + RTYPE_READ_DW = (1 << 6), + RTYPE_WRITE_DW_1 = (3 << 6), + RTYPE_READ_V8_MEMORY = (6 << 6), + RTYPE_WRITE_V8_MEMORY = (7 << 6), + RTYPE_WRITE_V8_FLASH = (8 << 6), + RTYPE_GENERIC = (9 << 6), +*/ +} flexcop_usb_request_type_t; +#endif + +/* request */ +typedef enum { + B2C2_USB_WRITE_V8_MEM = 0x04, + B2C2_USB_READ_V8_MEM = 0x05, + B2C2_USB_READ_REG = 0x08, + B2C2_USB_WRITE_REG = 0x0A, +/* B2C2_USB_WRITEREGLO = 0x0A, */ + B2C2_USB_WRITEREGHI = 0x0B, + B2C2_USB_FLASH_BLOCK = 0x10, + B2C2_USB_I2C_REQUEST = 0x11, + B2C2_USB_UTILITY = 0x12, +} flexcop_usb_request_t; + +/* function definition for I2C_REQUEST */ +typedef enum { + USB_FUNC_I2C_WRITE = 0x01, + USB_FUNC_I2C_MULTIWRITE = 0x02, + USB_FUNC_I2C_READ = 0x03, + USB_FUNC_I2C_REPEATWRITE = 0x04, + USB_FUNC_GET_DESCRIPTOR = 0x05, + USB_FUNC_I2C_REPEATREAD = 0x06, +/* DKT 020208 - add this to support special case of DiSEqC */ + USB_FUNC_I2C_CHECKWRITE = 0x07, + USB_FUNC_I2C_CHECKRESULT = 0x08, +} flexcop_usb_i2c_function_t; + +/* + * function definition for UTILITY request 0x12 + * DKT 020304 - new utility function + */ +typedef enum { + UTILITY_SET_FILTER = 0x01, + UTILITY_DATA_ENABLE = 0x02, + UTILITY_FLEX_MULTIWRITE = 0x03, + UTILITY_SET_BUFFER_SIZE = 0x04, + UTILITY_FLEX_OPERATOR = 0x05, + UTILITY_FLEX_RESET300_START = 0x06, + UTILITY_FLEX_RESET300_STOP = 0x07, + UTILITY_FLEX_RESET300 = 0x08, + UTILITY_SET_ISO_SIZE = 0x09, + UTILITY_DATA_RESET = 0x0A, + UTILITY_GET_DATA_STATUS = 0x10, + UTILITY_GET_V8_REG = 0x11, +/* DKT 020326 - add function for v1.14 */ + UTILITY_SRAM_WRITE = 0x12, + UTILITY_SRAM_READ = 0x13, + UTILITY_SRAM_TESTFILL = 0x14, + UTILITY_SRAM_TESTSET = 0x15, + UTILITY_SRAM_TESTVERIFY = 0x16, +} flexcop_usb_utility_function_t; + +#define B2C2_WAIT_FOR_OPERATION_RW 1*HZ /* 1 s */ +#define B2C2_WAIT_FOR_OPERATION_RDW 3*HZ /* 3 s */ +#define B2C2_WAIT_FOR_OPERATION_WDW 1*HZ /* 1 s */ + +#define B2C2_WAIT_FOR_OPERATION_V8READ 3*HZ /* 3 s */ +#define B2C2_WAIT_FOR_OPERATION_V8WRITE 3*HZ /* 3 s */ +#define B2C2_WAIT_FOR_OPERATION_V8FLASH 3*HZ /* 3 s */ + +typedef enum { + V8_MEMORY_PAGE_DVB_CI = 0x20, + V8_MEMORY_PAGE_DVB_DS = 0x40, + V8_MEMORY_PAGE_MULTI2 = 0x60, + V8_MEMORY_PAGE_FLASH = 0x80 +} flexcop_usb_mem_page_t; + +#define V8_MEMORY_EXTENDED (1 << 15) + +#define USB_MEM_READ_MAX 32 +#define USB_MEM_WRITE_MAX 1 +#define USB_FLASH_MAX 8 + +#define V8_MEMORY_PAGE_SIZE 0x8000 // 32K +#define V8_MEMORY_PAGE_MASK 0x7FFF + +#endif diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h new file mode 100644 index 000000000..caa343a97 --- /dev/null +++ b/drivers/media/dvb/b2c2/flexcop.h @@ -0,0 +1,30 @@ +/* + * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III + * + * flexcop.h - private header file for all flexcop-chip-source files. + * + * see flexcop.c for copyright information. + */ +#ifndef __FLEXCOP_H__ +#define __FLEXCOP_H___ + +#define FC_LOG_PREFIX "b2c2-flexcop" +#include "flexcop-common.h" + +extern int b2c2_flexcop_debug; + +/* debug */ +#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG +#define dprintk(level,args...) \ + do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0) +#else +#define dprintk(level,args...) +#endif + +#define deb_info(args...) dprintk(0x01,args) +#define deb_tuner(args...) dprintk(0x02,args) +#define deb_i2c(args...) dprintk(0x04,args) +#define deb_ts(args...) dprintk(0x08,args) +#define deb_sram(args...) dprintk(0x10,args) + +#endif diff --git a/drivers/media/dvb/bt8xx/dst_ca.h b/drivers/media/dvb/bt8xx/dst_ca.h new file mode 100644 index 000000000..59cd0ddd6 --- /dev/null +++ b/drivers/media/dvb/bt8xx/dst_ca.h @@ -0,0 +1,58 @@ +/* + CA-driver for TwinHan DST Frontend/Card + + Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _DST_CA_H_ +#define _DST_CA_H_ + +#define RETRIES 5 + + +#define CA_APP_INFO_ENQUIRY 0x9f8020 +#define CA_APP_INFO 0x9f8021 +#define CA_ENTER_MENU 0x9f8022 +#define CA_INFO_ENQUIRY 0x9f8030 +#define CA_INFO 0x9f8031 +#define CA_PMT 0x9f8032 +#define CA_PMT_REPLY 0x9f8033 + +#define CA_CLOSE_MMI 0x9f8800 +#define CA_DISPLAY_CONTROL 0x9f8801 +#define CA_DISPLAY_REPLY 0x9f8802 +#define CA_TEXT_LAST 0x9f8803 +#define CA_TEXT_MORE 0x9f8804 +#define CA_KEYPAD_CONTROL 0x9f8805 +#define CA_KEYPRESS 0x9f8806 + +#define CA_ENQUIRY 0x9f8807 +#define CA_ANSWER 0x9f8808 +#define CA_MENU_LAST 0x9f8809 +#define CA_MENU_MORE 0x9f880a +#define CA_MENU_ANSWER 0x9f880b +#define CA_LIST_LAST 0x9f880c +#define CA_LIST_MORE 0x9f880d + + +struct dst_ca_private { + struct dst_state *dst; + struct dvb_device *dvbdev; +}; + + +#endif diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c new file mode 100644 index 000000000..95ad17b7f --- /dev/null +++ b/drivers/media/video/mt20xx.c @@ -0,0 +1,558 @@ +/* + * $Id: mt20xx.c,v 1.4 2005/03/04 09:24:56 kraxel Exp $ + * + * i2c tv tuner chip device driver + * controls microtune tuners, mt2032 + mt2050 at the moment. + */ +#include +#include +#include +#include +#include + +/* ---------------------------------------------------------------------- */ + +static unsigned int optimize_vco = 1; +module_param(optimize_vco, int, 0644); + +static unsigned int tv_antenna = 1; +module_param(tv_antenna, int, 0644); + +static unsigned int radio_antenna = 0; +module_param(radio_antenna, int, 0644); + +/* ---------------------------------------------------------------------- */ + +#define MT2032 0x04 +#define MT2030 0x06 +#define MT2040 0x07 +#define MT2050 0x42 + +static char *microtune_part[] = { + [ MT2030 ] = "MT2030", + [ MT2032 ] = "MT2032", + [ MT2040 ] = "MT2040", + [ MT2050 ] = "MT2050", +}; + +// IsSpurInBand()? +static int mt2032_spurcheck(struct i2c_client *c, + int f1, int f2, int spectrum_from,int spectrum_to) +{ + struct tuner *t = i2c_get_clientdata(c); + int n1=1,n2,f; + + f1=f1/1000; //scale to kHz to avoid 32bit overflows + f2=f2/1000; + spectrum_from/=1000; + spectrum_to/=1000; + + tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n", + f1,f2,spectrum_from,spectrum_to); + + do { + n2=-n1; + f=n1*(f1-f2); + do { + n2--; + f=f-f2; + tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); + + if( (f>spectrum_from) && (f(f2-spectrum_to)) || (n2>-5)); + n1++; + } while (n1<5); + + return 1; +} + +static int mt2032_compute_freq(struct i2c_client *c, + unsigned int rfin, + unsigned int if1, unsigned int if2, + unsigned int spectrum_from, + unsigned int spectrum_to, + unsigned char *buf, + int *ret_sel, + unsigned int xogc) //all in Hz +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, + desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; + + fref= 5250 *1000; //5.25MHz + desired_lo1=rfin+if1; + + lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); + lo1n=lo1/8; + lo1a=lo1-(lo1n*8); + + s=rfin/1000/1000+1090; + + if(optimize_vco) { + if(s>1890) sel=0; + else if(s>1720) sel=1; + else if(s>1530) sel=2; + else if(s>1370) sel=3; + else sel=4; // >1090 + } + else { + if(s>1790) sel=0; // <1958 + else if(s>1617) sel=1; + else if(s>1449) sel=2; + else if(s>1291) sel=3; + else sel=4; // >1090 + } + *ret_sel=sel; + + lo1freq=(lo1a+8*lo1n)*fref; + + tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", + rfin,lo1,lo1n,lo1a,sel,lo1freq); + + desired_lo2=lo1freq-rfin-if2; + lo2=(desired_lo2)/fref; + lo2n=lo2/8; + lo2a=lo2-(lo2n*8); + lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith + lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; + + tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", + rfin,lo2,lo2n,lo2a,lo2num,lo2freq); + + if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) { + tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", + lo1a, lo1n, lo2a,lo2n); + return(-1); + } + + mt2032_spurcheck(c, lo1freq, desired_lo2, spectrum_from, spectrum_to); + // should recalculate lo1 (one step up/down) + + // set up MT2032 register map for transfer over i2c + buf[0]=lo1n-1; + buf[1]=lo1a | (sel<<4); + buf[2]=0x86; // LOGC + buf[3]=0x0f; //reserved + buf[4]=0x1f; + buf[5]=(lo2n-1) | (lo2a<<5); + if(rfin >400*1000*1000) + buf[6]=0xe4; + else + buf[6]=0xf4; // set PKEN per rev 1.2 + buf[7]=8+xogc; + buf[8]=0xc3; //reserved + buf[9]=0x4e; //reserved + buf[10]=0xec; //reserved + buf[11]=(lo2num&0xff); + buf[12]=(lo2num>>8) |0x80; // Lo2RST + + return 0; +} + +static int mt2032_check_lo_lock(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + int try,lock=0; + unsigned char buf[2]; + + for(try=0;try<10;try++) { + buf[0]=0x0e; + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); + lock=buf[0] &0x06; + + if (lock==6) + break; + + tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); + udelay(1000); + } + return lock; +} + +static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[2]; + int tad1; + + buf[0]=0x0f; + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); + tad1=buf[0]&0x07; + + if(tad1 ==0) return lock; + if(tad1 ==1) return lock; + + if(tad1==2) { + if(sel==0) + return lock; + else sel--; + } + else { + if(sel<4) + sel++; + else + return lock; + } + + tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); + + buf[0]=0x0f; + buf[1]=sel; + i2c_master_send(c,buf,2); + lock=mt2032_check_lo_lock(c); + return lock; +} + + +static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin, + unsigned int if1, unsigned int if2, + unsigned int from, unsigned int to) +{ + unsigned char buf[21]; + int lint_try,ret,sel,lock=0; + struct tuner *t = i2c_get_clientdata(c); + + tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", + rfin,if1,if2,from,to); + + buf[0]=0; + ret=i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,21); + + buf[0]=0; + ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc); + if (ret<0) + return; + + // send only the relevant registers per Rev. 1.2 + buf[0]=0; + ret=i2c_master_send(c,buf,4); + buf[5]=5; + ret=i2c_master_send(c,buf+5,4); + buf[11]=11; + ret=i2c_master_send(c,buf+11,3); + if(ret!=3) + tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); + + // wait for PLLs to lock (per manual), retry LINT if not. + for(lint_try=0; lint_try<2; lint_try++) { + lock=mt2032_check_lo_lock(c); + + if(optimize_vco) + lock=mt2032_optimize_vco(c,sel,lock); + if(lock==6) break; + + tuner_dbg("mt2032: re-init PLLs by LINT\n"); + buf[0]=7; + buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs + i2c_master_send(c,buf,2); + mdelay(10); + buf[1]=8+t->xogc; + i2c_master_send(c,buf,2); + } + + if (lock!=6) + tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); + + buf[0]=2; + buf[1]=0x20; // LOGC for optimal phase noise + ret=i2c_master_send(c,buf,2); + if (ret!=2) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); +} + + +static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + int if2,from,to; + + // signal bandwidth and picture carrier + if (t->std & V4L2_STD_525_60) { + // NTSC + from = 40750*1000; + to = 46750*1000; + if2 = 45750*1000; + } else { + // PAL + from = 32900*1000; + to = 39900*1000; + if2 = 38900*1000; + } + + mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */, + 1090*1000*1000, if2, from, to); +} + +static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + 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); +} + +// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 +static int mt2032_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[21]; + int ret,xogc,xok=0; + + // Initialize Registers per spec. + buf[1]=2; // Index to register 2 + buf[2]=0xff; + buf[3]=0x0f; + buf[4]=0x1f; + ret=i2c_master_send(c,buf+1,4); + + buf[5]=6; // Index register 6 + buf[6]=0xe4; + buf[7]=0x8f; + buf[8]=0xc3; + buf[9]=0x4e; + buf[10]=0xec; + ret=i2c_master_send(c,buf+5,6); + + buf[12]=13; // Index register 13 + buf[13]=0x32; + ret=i2c_master_send(c,buf+12,2); + + // Adjust XOGC (register 7), wait for XOK + xogc=7; + do { + tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); + mdelay(10); + buf[0]=0x0e; + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + xok=buf[0]&0x01; + tuner_dbg("mt2032: xok = 0x%02x\n",xok); + if (xok == 1) break; + + xogc--; + tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); + if (xogc == 3) { + xogc=4; // min. 4 per spec + break; + } + buf[0]=0x07; + buf[1]=0x88 + xogc; + ret=i2c_master_send(c,buf,2); + if (ret!=2) + tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); + } while (xok != 1 ); + t->xogc=xogc; + + t->tv_freq = mt2032_set_tv_freq; + t->radio_freq = mt2032_set_radio_freq; + return(1); +} + +static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[2]; + int ret; + + buf[0] = 6; + buf[1] = antenna ? 0x11 : 0x10; + ret=i2c_master_send(c,buf,2); + tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); +} + +static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned int if1=1218*1000*1000; + unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; + int ret; + unsigned char buf[6]; + + tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", + freq,if1,if2); + + f_lo1=freq+if1; + f_lo1=(f_lo1/1000000)*1000000; + + f_lo2=f_lo1-freq-if2; + f_lo2=(f_lo2/50000)*50000; + + lo1=f_lo1/4000000; + lo2=f_lo2/4000000; + + f_lo1_modulo= f_lo1-(lo1*4000000); + f_lo2_modulo= f_lo2-(lo2*4000000); + + num1=4*f_lo1_modulo/4000000; + num2=4096*(f_lo2_modulo/1000)/4000; + + // todo spurchecks + + div1a=(lo1/12)-1; + div1b=lo1-(div1a+1)*12; + + div2a=(lo2/8)-1; + div2b=lo2-(div2a+1)*8; + + if (tuner_debug > 1) { + tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); + tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", + num1,num2,div1a,div1b,div2a,div2b); + } + + buf[0]=1; + buf[1]= 4*div1b + num1; + if(freq<275*1000*1000) buf[1] = buf[1]|0x80; + + buf[2]=div1a; + buf[3]=32*div2b + num2/256; + buf[4]=num2-(num2/256)*256; + buf[5]=div2a; + if(num2!=0) buf[5]=buf[5]|0x40; + + if (tuner_debug > 1) { + int i; + tuner_dbg("bufs is: "); + for(i=0;i<6;i++) + printk("%x ",buf[i]); + printk("\n"); + } + + ret=i2c_master_send(c,buf,6); + if (ret!=6) + tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); +} + +static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned int if2; + + if (t->std & V4L2_STD_525_60) { + // NTSC + if2 = 45750*1000; + } else { + // PAL + if2 = 38900*1000; + } + if (V4L2_TUNER_DIGITAL_TV == t->mode) { + // DVB (pinnacle 300i) + if2 = 36150*1000; + } + mt2050_set_if_freq(c, freq*62500, if2); + mt2050_set_antenna(c, tv_antenna); +} + +static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = i2c_get_clientdata(c); + int if2 = t->radio_if2; + + mt2050_set_if_freq(c, freq*62500, if2); + mt2050_set_antenna(c, radio_antenna); +} + +static int mt2050_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + unsigned char buf[2]; + int ret; + + buf[0]=6; + buf[1]=0x10; + ret=i2c_master_send(c,buf,2); // power + + buf[0]=0x0f; + buf[1]=0x0f; + ret=i2c_master_send(c,buf,2); // m1lo + + buf[0]=0x0d; + ret=i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,1); + + tuner_dbg("mt2050: sro is %x\n",buf[0]); + t->tv_freq = mt2050_set_tv_freq; + t->radio_freq = mt2050_set_radio_freq; + return 0; +} + +int microtune_init(struct i2c_client *c) +{ + struct tuner *t = i2c_get_clientdata(c); + char *name; + unsigned char buf[21]; + int company_code; + + memset(buf,0,sizeof(buf)); + t->tv_freq = NULL; + t->radio_freq = NULL; + name = "unknown"; + + i2c_master_send(c,buf,1); + i2c_master_recv(c,buf,21); + if (tuner_debug) { + int i; + tuner_dbg("MT20xx hexdump:"); + for(i=0;i<21;i++) { + printk(" %02x",buf[i]); + if(((i+1)%8)==0) printk(" "); + } + printk("\n"); + } + company_code = buf[0x11] << 8 | buf[0x12]; + tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", + company_code,buf[0x13],buf[0x14]); + +#if 0 + /* seems to cause more problems than it solves ... */ + switch (company_code) { + case 0x30bf: + case 0x3cbf: + case 0x3dbf: + case 0x4d54: + case 0x8e81: + case 0x8e91: + /* ok (?) */ + break; + default: + tuner_warn("tuner: microtune: unknown companycode\n"); + return 0; + } +#endif + + if (buf[0x13] < ARRAY_SIZE(microtune_part) && + NULL != microtune_part[buf[0x13]]) + name = microtune_part[buf[0x13]]; + switch (buf[0x13]) { + case MT2032: + mt2032_init(c); + break; + case MT2050: + mt2050_init(c); + break; + default: + tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", + name); + return 0; + } + + strlcpy(c->name, name, sizeof(c->name)); + tuner_info("microtune %s found, OK\n",name); + return 0; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/misc/hdpuftrs/Makefile b/drivers/misc/hdpuftrs/Makefile new file mode 100644 index 000000000..ac74ae679 --- /dev/null +++ b/drivers/misc/hdpuftrs/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_HDPU_FEATURES) := hdpu_cpustate.o hdpu_nexus.o diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c new file mode 100644 index 000000000..7501fab34 --- /dev/null +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -0,0 +1,234 @@ +/* + * Sky CPU State Driver + * + * Copyright (C) 2002 Brian Waite + * + * This driver allows use of the CPU state bits + * It exports the /dev/sky_cpustate and also + * /proc/sky_cpustate pseudo-file for status information. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SKY_CPUSTATE_VERSION "1.1" + +static int hdpu_cpustate_probe(struct device *ddev); +static int hdpu_cpustate_remove(struct device *ddev); + +struct cpustate_t cpustate; + +static int cpustate_get_ref(int excl) +{ + + int retval = -EBUSY; + + spin_lock(&cpustate.lock); + + if (cpustate.excl) + goto out_busy; + + if (excl) { + if (cpustate.open_count) + goto out_busy; + cpustate.excl = 1; + } + + cpustate.open_count++; + retval = 0; + + out_busy: + spin_unlock(&cpustate.lock); + return retval; +} + +static int cpustate_free_ref(void) +{ + + spin_lock(&cpustate.lock); + + cpustate.excl = 0; + cpustate.open_count--; + + spin_unlock(&cpustate.lock); + return 0; +} + +unsigned char cpustate_get_state(void) +{ + + return cpustate.cached_val; +} + +void cpustate_set_state(unsigned char new_state) +{ + unsigned int state = (new_state << 21); + +#ifdef DEBUG_CPUSTATE + printk("CPUSTATE -> 0x%x\n", new_state); +#endif + spin_lock(&cpustate.lock); + cpustate.cached_val = new_state; + writel((0xff << 21), cpustate.clr_addr); + writel(state, cpustate.set_addr); + spin_unlock(&cpustate.lock); +} + +/* + * Now all the various file operations that we export. + */ + +static ssize_t cpustate_read(struct file *file, char *buf, + size_t count, loff_t * ppos) +{ + unsigned char data; + + if (count < 0) + return -EFAULT; + if (count == 0) + return 0; + + data = cpustate_get_state(); + if (copy_to_user(buf, &data, sizeof(unsigned char))) + return -EFAULT; + return sizeof(unsigned char); +} + +static ssize_t cpustate_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + unsigned char data; + + if (count < 0) + return -EFAULT; + + if (count == 0) + return 0; + + if (copy_from_user((unsigned char *)&data, buf, sizeof(unsigned char))) + return -EFAULT; + + cpustate_set_state(data); + return sizeof(unsigned char); +} + +static int cpustate_open(struct inode *inode, struct file *file) +{ + return cpustate_get_ref((file->f_flags & O_EXCL)); +} + +static int cpustate_release(struct inode *inode, struct file *file) +{ + return cpustate_free_ref(); +} + +/* + * Info exported via "/proc/sky_cpustate". + */ +static int cpustate_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *p = page; + int len = 0; + + p += sprintf(p, "CPU State: %04x\n", cpustate_get_state()); + len = p - page; + + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +static struct device_driver hdpu_cpustate_driver = { + .name = HDPU_CPUSTATE_NAME, + .bus = &platform_bus_type, + .probe = hdpu_cpustate_probe, + .remove = hdpu_cpustate_remove, +}; + +/* + * The various file operations we support. + */ +static struct file_operations cpustate_fops = { + owner:THIS_MODULE, + open:cpustate_open, + release:cpustate_release, + read:cpustate_read, + write:cpustate_write, + fasync:NULL, + poll:NULL, + ioctl:NULL, + llseek:no_llseek, + +}; + +static struct miscdevice cpustate_dev = { + MISC_DYNAMIC_MINOR, + "sky_cpustate", + &cpustate_fops +}; + +static int hdpu_cpustate_probe(struct device *ddev) +{ + struct platform_device *pdev = to_platform_device(ddev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + cpustate.set_addr = (unsigned long *)res->start; + cpustate.clr_addr = (unsigned long *)res->end - 1; + + misc_register(&cpustate_dev); + create_proc_read_entry("sky_cpustate", 0, 0, cpustate_read_proc, NULL); + + printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); + return 0; +} +static int hdpu_cpustate_remove(struct device *ddev) +{ + + cpustate.set_addr = 0; + cpustate.clr_addr = 0; + + remove_proc_entry("sky_cpustate", NULL); + misc_deregister(&cpustate_dev); + return 0; + +} + +static int __init cpustate_init(void) +{ + int rc; + rc = driver_register(&hdpu_cpustate_driver); + return rc; +} + +static void __exit cpustate_exit(void) +{ + driver_unregister(&hdpu_cpustate_driver); +} + +module_init(cpustate_init); +module_exit(cpustate_exit); + +MODULE_AUTHOR("Brian Waite"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c new file mode 100644 index 000000000..c203b2726 --- /dev/null +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -0,0 +1,111 @@ +/* + * Sky Nexus Register Driver + * + * Copyright (C) 2002 Brian Waite + * + * This driver allows reading the Nexus register + * It exports the /proc/sky_chassis_id and also + * /proc/sky_slot_id pseudo-file for status information. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +static int hdpu_nexus_probe(struct device *ddev); +static int hdpu_nexus_remove(struct device *ddev); + +static struct proc_dir_entry *hdpu_slot_id; +static struct proc_dir_entry *hdpu_chassis_id; +static int slot_id = -1; +static int chassis_id = -1; + +static struct device_driver hdpu_nexus_driver = { + .name = HDPU_NEXUS_NAME, + .bus = &platform_bus_type, + .probe = hdpu_nexus_probe, + .remove = hdpu_nexus_remove, +}; + +int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset, + int buffer_length, int *zero, void *ptr) +{ + + if (offset > 0) + return 0; + return sprintf(buffer, "%d\n", slot_id); +} + +int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset, + int buffer_length, int *zero, void *ptr) +{ + + if (offset > 0) + return 0; + return sprintf(buffer, "%d\n", chassis_id); +} + +static int hdpu_nexus_probe(struct device *ddev) +{ + struct platform_device *pdev = to_platform_device(ddev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int *nexus_id_addr; + nexus_id_addr = + ioremap(res->start, (unsigned long)(res->end - res->start)); + if (nexus_id_addr) { + slot_id = (*nexus_id_addr >> 8) & 0x1f; + chassis_id = *nexus_id_addr & 0xff; + iounmap(nexus_id_addr); + } else + printk("Could not map slot id\n"); + hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); + hdpu_slot_id->read_proc = hdpu_slot_id_read; + hdpu_slot_id->nlink = 1; + + hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); + hdpu_chassis_id->read_proc = hdpu_chassis_id_read; + hdpu_chassis_id->nlink = 1; + return 0; +} + +static int hdpu_nexus_remove(struct device *ddev) +{ + slot_id = -1; + chassis_id = -1; + remove_proc_entry("sky_slot_id", &proc_root); + remove_proc_entry("sky_chassis_id", &proc_root); + hdpu_slot_id = 0; + hdpu_chassis_id = 0; + return 0; +} + +static int __init nexus_init(void) +{ + int rc; + rc = driver_register(&hdpu_nexus_driver); + return rc; +} + +static void __exit nexus_exit(void) +{ + driver_unregister(&hdpu_nexus_driver); +} + +module_init(nexus_init); +module_exit(nexus_exit); + +MODULE_AUTHOR("Brian Waite"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/atmel.h b/drivers/net/wireless/atmel.h new file mode 100644 index 000000000..825000edf --- /dev/null +++ b/drivers/net/wireless/atmel.h @@ -0,0 +1,43 @@ +/*** -*- linux-c -*- ********************************************************** + + Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. + + Copyright 2005 Dan Williams and Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This software is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Atmel wireless lan drivers; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +******************************************************************************/ + +#ifndef _ATMEL_H +#define _ATMEL_H + +typedef enum { + ATMEL_FW_TYPE_NONE = 0, + ATMEL_FW_TYPE_502, + ATMEL_FW_TYPE_502D, + ATMEL_FW_TYPE_502E, + ATMEL_FW_TYPE_502_3COM, + ATMEL_FW_TYPE_504, + ATMEL_FW_TYPE_504_2958, + ATMEL_FW_TYPE_504A_2958, + ATMEL_FW_TYPE_506 +} AtmelFWType; + +struct net_device *init_atmel_card(unsigned short, int, const AtmelFWType, struct device *, + int (*present_func)(void *), void * ); +void stop_atmel_card( struct net_device *, int ); +int atmel_open( struct net_device * ); + +#endif diff --git a/drivers/serial/jsm/Makefile b/drivers/serial/jsm/Makefile new file mode 100644 index 000000000..e46b6e0f8 --- /dev/null +++ b/drivers/serial/jsm/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for Jasmine adapter +# + +obj-$(CONFIG_SERIAL_JSM) += jsm.o + +jsm-objs := jsm_driver.o jsm_neo.o jsm_tty.o + diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile new file mode 100644 index 000000000..8a143894e --- /dev/null +++ b/drivers/sh/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the SuperH specific drivers. +# + +obj-$(CONFIG_SUPERHYWAY) += superhyway/ + diff --git a/drivers/sh/superhyway/Makefile b/drivers/sh/superhyway/Makefile new file mode 100644 index 000000000..499dc47d8 --- /dev/null +++ b/drivers/sh/superhyway/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the SuperHyway bus drivers. +# + +obj-$(CONFIG_SUPERHYWAY) += superhyway.o +obj-$(CONFIG_SYSFS) += superhyway-sysfs.o + diff --git a/drivers/sh/superhyway/superhyway-sysfs.c b/drivers/sh/superhyway/superhyway-sysfs.c new file mode 100644 index 000000000..39ab6a12d --- /dev/null +++ b/drivers/sh/superhyway/superhyway-sysfs.c @@ -0,0 +1,45 @@ +/* + * drivers/sh/superhyway/superhyway-sysfs.c + * + * SuperHyway Bus sysfs interface + * + * Copyright (C) 2004, 2005 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include + +#define superhyway_ro_attr(name, fmt, field) \ +static ssize_t name##_show(struct device *dev, char *buf) \ +{ \ + struct superhyway_device *s = to_superhyway_device(dev); \ + return sprintf(buf, fmt, s->field); \ +} + +/* VCR flags */ +superhyway_ro_attr(perr_flags, "0x%02x\n", vcr.perr_flags); +superhyway_ro_attr(merr_flags, "0x%02x\n", vcr.merr_flags); +superhyway_ro_attr(mod_vers, "0x%04x\n", vcr.mod_vers); +superhyway_ro_attr(mod_id, "0x%04x\n", vcr.mod_id); +superhyway_ro_attr(bot_mb, "0x%02x\n", vcr.bot_mb); +superhyway_ro_attr(top_mb, "0x%02x\n", vcr.top_mb); + +/* Misc */ +superhyway_ro_attr(resource, "0x%08lx\n", resource.start); + +struct device_attribute superhyway_dev_attrs[] = { + __ATTR_RO(perr_flags), + __ATTR_RO(merr_flags), + __ATTR_RO(mod_vers), + __ATTR_RO(mod_id), + __ATTR_RO(bot_mb), + __ATTR_RO(top_mb), + __ATTR_RO(resource), + __ATTR_NULL, +}; + diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c new file mode 100644 index 000000000..f056276b0 --- /dev/null +++ b/drivers/sh/superhyway/superhyway.c @@ -0,0 +1,201 @@ +/* + * drivers/sh/superhyway/superhyway.c + * + * SuperHyway Bus Driver + * + * Copyright (C) 2004, 2005 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include +#include + +static int superhyway_devices; + +static struct device superhyway_bus_device = { + .bus_id = "superhyway", +}; + +static void superhyway_device_release(struct device *dev) +{ + kfree(to_superhyway_device(dev)); +} + +/** + * superhyway_add_device - Add a SuperHyway module + * @mod_id: Module ID (taken from MODULE.VCR.MOD_ID). + * @base: Physical address where module is mapped. + * @vcr: VCR value. + * + * This is responsible for adding a new SuperHyway module. This sets up a new + * struct superhyway_device for the module being added. Each one of @mod_id, + * @base, and @vcr are registered with the new device for further use + * elsewhere. + * + * Devices are initially added in the order that they are scanned (from the + * top-down of the memory map), and are assigned an ID based on the order that + * they are added. Any manual addition of a module will thus get the ID after + * the devices already discovered regardless of where it resides in memory. + * + * Further work can and should be done in superhyway_scan_bus(), to be sure + * that any new modules are properly discovered and subsequently registered. + */ +int superhyway_add_device(unsigned int mod_id, unsigned long base, + unsigned long long vcr) +{ + struct superhyway_device *dev; + + dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + memset(dev, 0, sizeof(struct superhyway_device)); + + dev->id.id = mod_id; + sprintf(dev->name, "SuperHyway device %04x", dev->id.id); + + dev->vcr = *((struct vcr_info *)(&vcr)); + dev->resource.name = dev->name; + dev->resource.start = base; + dev->resource.end = dev->resource.start + 0x01000000; + dev->dev.parent = &superhyway_bus_device; + dev->dev.bus = &superhyway_bus_type; + dev->dev.release = superhyway_device_release; + + sprintf(dev->dev.bus_id, "%02x", superhyway_devices); + + superhyway_devices++; + + return device_register(&dev->dev); +} + +static int __init superhyway_init(void) +{ + device_register(&superhyway_bus_device); + return superhyway_scan_bus(); +} + +postcore_initcall(superhyway_init); + +static const struct superhyway_device_id * +superhyway_match_id(const struct superhyway_device_id *ids, + struct superhyway_device *dev) +{ + while (ids->id) { + if (ids->id == dev->id.id) + return ids; + + ids++; + } + + return NULL; +} + +static int superhyway_device_probe(struct device *dev) +{ + struct superhyway_device *shyway_dev = to_superhyway_device(dev); + struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver); + + if (shyway_drv && shyway_drv->probe) { + const struct superhyway_device_id *id; + + id = superhyway_match_id(shyway_drv->id_table, shyway_dev); + if (id) + return shyway_drv->probe(shyway_dev, id); + } + + return -ENODEV; +} + +static int superhyway_device_remove(struct device *dev) +{ + struct superhyway_device *shyway_dev = to_superhyway_device(dev); + struct superhyway_driver *shyway_drv = to_superhyway_driver(dev->driver); + + if (shyway_drv && shyway_drv->remove) { + shyway_drv->remove(shyway_dev); + return 0; + } + + return -ENODEV; +} + +/** + * superhyway_register_driver - Register a new SuperHyway driver + * @drv: SuperHyway driver to register. + * + * This registers the passed in @drv. Any devices matching the id table will + * automatically be populated and handed off to the driver's specified probe + * routine. + */ +int superhyway_register_driver(struct superhyway_driver *drv) +{ + drv->drv.name = drv->name; + drv->drv.bus = &superhyway_bus_type; + drv->drv.probe = superhyway_device_probe; + drv->drv.remove = superhyway_device_remove; + + return driver_register(&drv->drv); +} + +/** + * superhyway_unregister_driver - Unregister a SuperHyway driver + * @drv: SuperHyway driver to unregister. + * + * This cleans up after superhyway_register_driver(), and should be invoked in + * the exit path of any module drivers. + */ +void superhyway_unregister_driver(struct superhyway_driver *drv) +{ + driver_unregister(&drv->drv); +} + +static int superhyway_bus_match(struct device *dev, struct device_driver *drv) +{ + struct superhyway_device *shyway_dev = to_superhyway_device(dev); + struct superhyway_driver *shyway_drv = to_superhyway_driver(drv); + const struct superhyway_device_id *ids = shyway_drv->id_table; + + if (!ids) + return -EINVAL; + if (superhyway_match_id(ids, shyway_dev)) + return 1; + + return -ENODEV; +} + +struct bus_type superhyway_bus_type = { + .name = "superhyway", + .match = superhyway_bus_match, +#ifdef CONFIG_SYSFS + .dev_attrs = superhyway_dev_attrs, +#endif +}; + +static int __init superhyway_bus_init(void) +{ + return bus_register(&superhyway_bus_type); +} + +static void __exit superhyway_bus_exit(void) +{ + device_unregister(&superhyway_bus_device); + bus_unregister(&superhyway_bus_type); +} + +core_initcall(superhyway_bus_init); +module_exit(superhyway_bus_exit); + +EXPORT_SYMBOL(superhyway_bus_type); +EXPORT_SYMBOL(superhyway_add_device); +EXPORT_SYMBOL(superhyway_register_driver); +EXPORT_SYMBOL(superhyway_unregister_driver); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig new file mode 100644 index 000000000..3957e144c --- /dev/null +++ b/drivers/usb/misc/sisusbvga/Kconfig @@ -0,0 +1,14 @@ + +config USB_SISUSBVGA + tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" + depends on USB && USB_EHCI_HCD + ---help--- + Say Y here if you intend to attach a USB2VGA dongle based on a + Net2280 and a SiS315 chip. + + Note that this device requires a USB 2.0 host controller. It will not + work with USB 1.x controllers. + + To compile this driver as a module, choose M here: the module will be + called sisusb. If unsure, say N. + diff --git a/drivers/usb/misc/sisusbvga/Makefile b/drivers/usb/misc/sisusbvga/Makefile new file mode 100644 index 000000000..76f1643ce --- /dev/null +++ b/drivers/usb/misc/sisusbvga/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the sisusb driver (if driver is inside kernel tree). +# + +obj-$(CONFIG_USB_SISUSBVGA) += sisusb.o + diff --git a/drivers/usb/mon/Kconfig b/drivers/usb/mon/Kconfig new file mode 100644 index 000000000..4e6152aa5 --- /dev/null +++ b/drivers/usb/mon/Kconfig @@ -0,0 +1,22 @@ +# +# USB Monitor configuration +# + +# In normal life, it makes little sense to have usbmon as a module, and in fact +# it is harmful, because there is no way to autoload the module. +# The 'm' option is allowed for hackers who debug the usbmon itself, +# and for those who have usbcore as a module. +config USB_MON + tristate "USB Monitor" + depends on USB + default y + help + If you say Y here, a component which captures the USB traffic + between peripheral-specific drivers and HC drivers will be built. + The USB_MON is similar in spirit and may be compatible with Dave + Harding's USBMon. + + This is somewhat experimental at this time, but it should be safe, + as long as you aren't building this as a module and then removing it. + + If unsure, say Y. Do not say M. diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile new file mode 100644 index 000000000..3cff8d444 --- /dev/null +++ b/drivers/usb/mon/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for USB Core files and filesystem +# + +usbmon-objs := mon_main.o mon_stat.o mon_text.o + +obj-$(CONFIG_USB_MON) += usbmon.o diff --git a/drivers/video/geode/display_gx1.c b/drivers/video/geode/display_gx1.c new file mode 100644 index 000000000..f4983879f --- /dev/null +++ b/drivers/video/geode/display_gx1.c @@ -0,0 +1,214 @@ +/* + * drivers/video/geode/display_gx1.c + * -- Geode GX1 display controller + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * Based on AMD's original 2.4 driver: + * Copyright (C) 2004 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include + +#include "geodefb.h" +#include "display_gx1.h" + +static spinlock_t gx1_conf_reg_lock = SPIN_LOCK_UNLOCKED; + +static u8 gx1_read_conf_reg(u8 reg) +{ + u8 val, ccr3; + unsigned long flags; + + spin_lock_irqsave(&gx1_conf_reg_lock, flags); + + outb(CONFIG_CCR3, 0x22); + ccr3 = inb(0x23); + outb(CONFIG_CCR3, 0x22); + outb(ccr3 | CONFIG_CCR3_MAPEN, 0x23); + outb(reg, 0x22); + val = inb(0x23); + outb(CONFIG_CCR3, 0x22); + outb(ccr3, 0x23); + + spin_unlock_irqrestore(&gx1_conf_reg_lock, flags); + + return val; +} + +unsigned gx1_gx_base(void) +{ + return (gx1_read_conf_reg(CONFIG_GCR) & 0x03) << 30; +} + +int gx1_frame_buffer_size(void) +{ + void __iomem *mc_regs; + u32 bank_cfg; + int d; + unsigned dram_size = 0, fb_base; + + mc_regs = ioremap(gx1_gx_base() + 0x8400, 0x100); + if (!mc_regs) + return -ENOMEM; + + + /* Calculate the total size of both DIMM0 and DIMM1. */ + bank_cfg = readl(mc_regs + MC_BANK_CFG); + + for (d = 0; d < 2; d++) { + if ((bank_cfg & MC_BCFG_DIMM0_PG_SZ_MASK) != MC_BCFG_DIMM0_PG_SZ_NO_DIMM) + dram_size += 0x400000 << ((bank_cfg & MC_BCFG_DIMM0_SZ_MASK) >> 8); + bank_cfg >>= 16; /* look at DIMM1 next */ + } + + fb_base = (readl(mc_regs + MC_GBASE_ADD) & MC_GADD_GBADD_MASK) << 19; + + iounmap(mc_regs); + + return dram_size - fb_base; +} + +static void gx1_set_mode(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + u32 gcfg, tcfg, ocfg, dclk_div, val; + int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal; + int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal; + + /* Unlock the display controller registers. */ + readl(par->dc_regs + DC_UNLOCK); + writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK); + + gcfg = readl(par->dc_regs + DC_GENERAL_CFG); + tcfg = readl(par->dc_regs + DC_TIMING_CFG); + + /* Blank the display and disable the timing generator. */ + tcfg &= ~(DC_TCFG_BLKE | DC_TCFG_TGEN); + writel(tcfg, par->dc_regs + DC_TIMING_CFG); + + /* Wait for pending memory requests before disabling the FIFO load. */ + udelay(100); + + /* Disable FIFO load and compression. */ + gcfg &= ~(DC_GCFG_DFLE | DC_GCFG_CMPE | DC_GCFG_DECE); + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + + /* Setup DCLK and its divisor. */ + gcfg &= ~DC_GCFG_DCLK_MASK; + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + + par->vid_ops->set_dclk(info); + + dclk_div = DC_GCFG_DCLK_DIV_1; /* FIXME: may need to divide DCLK by 2 sometimes? */ + gcfg |= dclk_div; + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + + /* Wait for the clock generatation to settle. This is needed since + * some of the register writes that follow require that clock to be + * present. */ + udelay(1000); /* FIXME: seems a little long */ + + /* + * Setup new mode. + */ + + /* Clear all unused feature bits. */ + gcfg = DC_GCFG_VRDY | dclk_div; + + /* Set FIFO priority (default 6/5) and enable. */ + /* FIXME: increase fifo priority for 1280x1024 modes? */ + gcfg |= (6 << DC_GCFG_DFHPEL_POS) | (5 << DC_GCFG_DFHPSL_POS) | DC_GCFG_DFLE; + + /* FIXME: Set pixel and line double bits if necessary. */ + + /* Framebuffer start offset. */ + writel(0, par->dc_regs + DC_FB_ST_OFFSET); + + /* Line delta and line buffer length. */ + writel(info->fix.line_length >> 2, par->dc_regs + DC_LINE_DELTA); + writel(((info->var.xres * info->var.bits_per_pixel/8) >> 3) + 2, + par->dc_regs + DC_BUF_SIZE); + + /* Output configuration. Enable panel data, set pixel format. */ + ocfg = DC_OCFG_PCKE | DC_OCFG_PDEL | DC_OCFG_PDEH; + if (info->var.bits_per_pixel == 8) ocfg |= DC_OCFG_8BPP; + + /* Enable timing generator, sync and FP data. */ + tcfg = DC_TCFG_FPPE | DC_TCFG_HSYE | DC_TCFG_VSYE | DC_TCFG_BLKE + | DC_TCFG_TGEN; + + /* Horizontal and vertical timings. */ + hactive = info->var.xres; + hblankstart = hactive; + hsyncstart = hblankstart + info->var.right_margin; + hsyncend = hsyncstart + info->var.hsync_len; + hblankend = hsyncend + info->var.left_margin; + htotal = hblankend; + + vactive = info->var.yres; + vblankstart = vactive; + vsyncstart = vblankstart + info->var.lower_margin; + vsyncend = vsyncstart + info->var.vsync_len; + vblankend = vsyncend + info->var.upper_margin; + vtotal = vblankend; + + val = (hactive - 1) | ((htotal - 1) << 16); + writel(val, par->dc_regs + DC_H_TIMING_1); + val = (hblankstart - 1) | ((hblankend - 1) << 16); + writel(val, par->dc_regs + DC_H_TIMING_2); + val = (hsyncstart - 1) | ((hsyncend - 1) << 16); + writel(val, par->dc_regs + DC_H_TIMING_3); + writel(val, par->dc_regs + DC_FP_H_TIMING); + val = (vactive - 1) | ((vtotal - 1) << 16); + writel(val, par->dc_regs + DC_V_TIMING_1); + val = (vblankstart - 1) | ((vblankend - 1) << 16); + writel(val, par->dc_regs + DC_V_TIMING_2); + val = (vsyncstart - 1) | ((vsyncend - 1) << 16); + writel(val, par->dc_regs + DC_V_TIMING_3); + val = (vsyncstart - 2) | ((vsyncend - 2) << 16); + writel(val, par->dc_regs + DC_FP_V_TIMING); + + /* Write final register values. */ + writel(ocfg, par->dc_regs + DC_OUTPUT_CFG); + writel(tcfg, par->dc_regs + DC_TIMING_CFG); + udelay(1000); /* delay after TIMING_CFG. FIXME: perhaps a little long */ + writel(gcfg, par->dc_regs + DC_GENERAL_CFG); + + par->vid_ops->configure_display(info); + + /* Relock display controller registers */ + writel(0, par->dc_regs + DC_UNLOCK); + + /* FIXME: write line_length and bpp to Graphics Pipeline GP_BLT_STATUS + * register. */ +} + +static void gx1_set_hw_palette_reg(struct fb_info *info, unsigned regno, + unsigned red, unsigned green, unsigned blue) +{ + struct geodefb_par *par = info->par; + int val; + + /* Hardware palette is in RGB 6-6-6 format. */ + val = (red << 2) & 0x3f000; + val |= (green >> 4) & 0x00fc0; + val |= (blue >> 10) & 0x0003f; + + writel(regno, par->dc_regs + DC_PAL_ADDRESS); + writel(val, par->dc_regs + DC_PAL_DATA); +} + +struct geode_dc_ops gx1_dc_ops = { + .set_mode = gx1_set_mode, + .set_palette_reg = gx1_set_hw_palette_reg, +}; diff --git a/drivers/video/geode/display_gx1.h b/drivers/video/geode/display_gx1.h new file mode 100644 index 000000000..671c05558 --- /dev/null +++ b/drivers/video/geode/display_gx1.h @@ -0,0 +1,154 @@ +/* + * drivers/video/geode/display_gx1.h + * -- Geode GX1 display controller + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * Based on AMD's original 2.4 driver: + * Copyright (C) 2004 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __DISPLAY_GX1_H__ +#define __DISPLAY_GX1_H__ + +unsigned gx1_gx_base(void); +int gx1_frame_buffer_size(void); + +extern struct geode_dc_ops gx1_dc_ops; + +/* GX1 configuration I/O registers */ + +#define CONFIG_CCR3 0xc3 +# define CONFIG_CCR3_MAPEN 0x10 +#define CONFIG_GCR 0xb8 + +/* Memory controller registers */ + +#define MC_BANK_CFG 0x08 +# define MC_BCFG_DIMM0_SZ_MASK 0x00000700 +# define MC_BCFG_DIMM0_PG_SZ_MASK 0x00000070 +# define MC_BCFG_DIMM0_PG_SZ_NO_DIMM 0x00000070 + +#define MC_GBASE_ADD 0x14 +# define MC_GADD_GBADD_MASK 0x000003ff + +/* Display controller registers */ + +#define DC_PAL_ADDRESS 0x70 +#define DC_PAL_DATA 0x74 + +#define DC_UNLOCK 0x00 +# define DC_UNLOCK_CODE 0x00004758 + +#define DC_GENERAL_CFG 0x04 +# define DC_GCFG_DFLE 0x00000001 +# define DC_GCFG_CURE 0x00000002 +# define DC_GCFG_VCLK_DIV 0x00000004 +# define DC_GCFG_PLNO 0x00000004 +# define DC_GCFG_PPC 0x00000008 +# define DC_GCFG_CMPE 0x00000010 +# define DC_GCFG_DECE 0x00000020 +# define DC_GCFG_DCLK_MASK 0x000000C0 +# define DC_GCFG_DCLK_DIV_1 0x00000080 +# define DC_GCFG_DFHPSL_MASK 0x00000F00 +# define DC_GCFG_DFHPSL_POS 8 +# define DC_GCFG_DFHPEL_MASK 0x0000F000 +# define DC_GCFG_DFHPEL_POS 12 +# define DC_GCFG_CIM_MASK 0x00030000 +# define DC_GCFG_CIM_POS 16 +# define DC_GCFG_FDTY 0x00040000 +# define DC_GCFG_RTPM 0x00080000 +# define DC_GCFG_DAC_RS_MASK 0x00700000 +# define DC_GCFG_DAC_RS_POS 20 +# define DC_GCFG_CKWR 0x00800000 +# define DC_GCFG_LDBL 0x01000000 +# define DC_GCFG_DIAG 0x02000000 +# define DC_GCFG_CH4S 0x04000000 +# define DC_GCFG_SSLC 0x08000000 +# define DC_GCFG_VIDE 0x10000000 +# define DC_GCFG_VRDY 0x20000000 +# define DC_GCFG_DPCK 0x40000000 +# define DC_GCFG_DDCK 0x80000000 + +#define DC_TIMING_CFG 0x08 +# define DC_TCFG_FPPE 0x00000001 +# define DC_TCFG_HSYE 0x00000002 +# define DC_TCFG_VSYE 0x00000004 +# define DC_TCFG_BLKE 0x00000008 +# define DC_TCFG_DDCK 0x00000010 +# define DC_TCFG_TGEN 0x00000020 +# define DC_TCFG_VIEN 0x00000040 +# define DC_TCFG_BLNK 0x00000080 +# define DC_TCFG_CHSP 0x00000100 +# define DC_TCFG_CVSP 0x00000200 +# define DC_TCFG_FHSP 0x00000400 +# define DC_TCFG_FVSP 0x00000800 +# define DC_TCFG_FCEN 0x00001000 +# define DC_TCFG_CDCE 0x00002000 +# define DC_TCFG_PLNR 0x00002000 +# define DC_TCFG_INTL 0x00004000 +# define DC_TCFG_PXDB 0x00008000 +# define DC_TCFG_BKRT 0x00010000 +# define DC_TCFG_PSD_MASK 0x000E0000 +# define DC_TCFG_PSD_POS 17 +# define DC_TCFG_DDCI 0x08000000 +# define DC_TCFG_SENS 0x10000000 +# define DC_TCFG_DNA 0x20000000 +# define DC_TCFG_VNA 0x40000000 +# define DC_TCFG_VINT 0x80000000 + +#define DC_OUTPUT_CFG 0x0C +# define DC_OCFG_8BPP 0x00000001 +# define DC_OCFG_555 0x00000002 +# define DC_OCFG_PCKE 0x00000004 +# define DC_OCFG_FRME 0x00000008 +# define DC_OCFG_DITE 0x00000010 +# define DC_OCFG_2PXE 0x00000020 +# define DC_OCFG_2XCK 0x00000040 +# define DC_OCFG_2IND 0x00000080 +# define DC_OCFG_34ADD 0x00000100 +# define DC_OCFG_FRMS 0x00000200 +# define DC_OCFG_CKSL 0x00000400 +# define DC_OCFG_PRMP 0x00000800 +# define DC_OCFG_PDEL 0x00001000 +# define DC_OCFG_PDEH 0x00002000 +# define DC_OCFG_CFRW 0x00004000 +# define DC_OCFG_DIAG 0x00008000 + +#define DC_FB_ST_OFFSET 0x10 +#define DC_CB_ST_OFFSET 0x14 +#define DC_CURS_ST_OFFSET 0x18 +#define DC_ICON_ST_OFFSET 0x1C +#define DC_VID_ST_OFFSET 0x20 +#define DC_LINE_DELTA 0x24 +#define DC_BUF_SIZE 0x28 + +#define DC_H_TIMING_1 0x30 +#define DC_H_TIMING_2 0x34 +#define DC_H_TIMING_3 0x38 +#define DC_FP_H_TIMING 0x3C + +#define DC_V_TIMING_1 0x40 +#define DC_V_TIMING_2 0x44 +#define DC_V_TIMING_3 0x48 +#define DC_FP_V_TIMING 0x4C + +#define DC_CURSOR_X 0x50 +#define DC_ICON_X 0x54 +#define DC_V_LINE_CNT 0x54 +#define DC_CURSOR_Y 0x58 +#define DC_ICON_Y 0x5C +#define DC_SS_LINE_CMP 0x5C +#define DC_CURSOR_COLOR 0x60 +#define DC_ICON_COLOR 0x64 +#define DC_BORDER_COLOR 0x68 +#define DC_PAL_ADDRESS 0x70 +#define DC_PAL_DATA 0x74 +#define DC_DFIFO_DIAG 0x78 +#define DC_CFIFO_DIAG 0x7C + +#endif /* !__DISPLAY_GX1_H__ */ diff --git a/drivers/video/geode/geodefb.h b/drivers/video/geode/geodefb.h new file mode 100644 index 000000000..b7bac0a52 --- /dev/null +++ b/drivers/video/geode/geodefb.h @@ -0,0 +1,39 @@ +/* + * drivers/video/geode/geodefb.h + * -- Geode framebuffer driver + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __GEODEFB_H__ +#define __GEODEFB_H__ + +struct geodefb_info; + +struct geode_dc_ops { + void (*set_mode)(struct fb_info *); + void (*set_palette_reg)(struct fb_info *, unsigned, unsigned, unsigned, unsigned); +}; + +struct geode_vid_ops { + void (*set_dclk)(struct fb_info *); + void (*configure_display)(struct fb_info *); + int (*blank_display)(struct fb_info *, int blank_mode); +}; + +struct geodefb_par { + int enable_crt; + int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */ + int panel_y; + struct pci_dev *vid_dev; + void __iomem *dc_regs; + void __iomem *vid_regs; + struct geode_dc_ops *dc_ops; + struct geode_vid_ops *vid_ops; +}; + +#endif /* !__GEODEFB_H__ */ diff --git a/drivers/video/geode/video_cs5530.c b/drivers/video/geode/video_cs5530.c new file mode 100644 index 000000000..d3764acf8 --- /dev/null +++ b/drivers/video/geode/video_cs5530.c @@ -0,0 +1,195 @@ +/* + * drivers/video/geode/video_cs5530.c + * -- CS5530 video device + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * Based on AMD's original 2.4 driver: + * Copyright (C) 2004 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include + +#include "geodefb.h" +#include "video_cs5530.h" + +/* + * CS5530 PLL table. This maps pixclocks to the appropriate PLL register + * value. + */ +struct cs5530_pll_entry { + long pixclock; /* ps */ + u32 pll_value; +}; + +static const struct cs5530_pll_entry cs5530_pll_table[] = { + { 39721, 0x31C45801, }, /* 25.1750 MHz */ + { 35308, 0x20E36802, }, /* 28.3220 */ + { 31746, 0x33915801, }, /* 31.5000 */ + { 27777, 0x31EC4801, }, /* 36.0000 */ + { 26666, 0x21E22801, }, /* 37.5000 */ + { 25000, 0x33088801, }, /* 40.0000 */ + { 22271, 0x33E22801, }, /* 44.9000 */ + { 20202, 0x336C4801, }, /* 49.5000 */ + { 20000, 0x23088801, }, /* 50.0000 */ + { 19860, 0x23088801, }, /* 50.3500 */ + { 18518, 0x3708A801, }, /* 54.0000 */ + { 17777, 0x23E36802, }, /* 56.2500 */ + { 17733, 0x23E36802, }, /* 56.3916 */ + { 17653, 0x23E36802, }, /* 56.6444 */ + { 16949, 0x37C45801, }, /* 59.0000 */ + { 15873, 0x23EC4801, }, /* 63.0000 */ + { 15384, 0x37911801, }, /* 65.0000 */ + { 14814, 0x37963803, }, /* 67.5000 */ + { 14124, 0x37058803, }, /* 70.8000 */ + { 13888, 0x3710C805, }, /* 72.0000 */ + { 13333, 0x37E22801, }, /* 75.0000 */ + { 12698, 0x27915801, }, /* 78.7500 */ + { 12500, 0x37D8D802, }, /* 80.0000 */ + { 11135, 0x27588802, }, /* 89.8000 */ + { 10582, 0x27EC4802, }, /* 94.5000 */ + { 10101, 0x27AC6803, }, /* 99.0000 */ + { 10000, 0x27088801, }, /* 100.0000 */ + { 9259, 0x2710C805, }, /* 108.0000 */ + { 8888, 0x27E36802, }, /* 112.5000 */ + { 7692, 0x27C58803, }, /* 130.0000 */ + { 7407, 0x27316803, }, /* 135.0000 */ + { 6349, 0x2F915801, }, /* 157.5000 */ + { 6172, 0x2F08A801, }, /* 162.0000 */ + { 5714, 0x2FB11802, }, /* 175.0000 */ + { 5291, 0x2FEC4802, }, /* 189.0000 */ + { 4950, 0x2F963803, }, /* 202.0000 */ + { 4310, 0x2FB1B802, }, /* 232.0000 */ +}; + +#define NUM_CS5530_FREQUENCIES sizeof(cs5530_pll_table)/sizeof(struct cs5530_pll_entry) + +static void cs5530_set_dclk_frequency(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + int i; + u32 value; + long min, diff; + + /* Search the table for the closest pixclock. */ + value = cs5530_pll_table[0].pll_value; + min = cs5530_pll_table[0].pixclock - info->var.pixclock; + if (min < 0) min = -min; + for (i = 1; i < NUM_CS5530_FREQUENCIES; i++) { + diff = cs5530_pll_table[i].pixclock - info->var.pixclock; + if (diff < 0L) diff = -diff; + if (diff < min) { + min = diff; + value = cs5530_pll_table[i].pll_value; + } + } + + writel(value, par->vid_regs + CS5530_DOT_CLK_CONFIG); + writel(value | 0x80000100, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* set reset and bypass */ + udelay(500); /* wait for PLL to settle */ + writel(value & 0x7FFFFFFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear reset */ + writel(value & 0x7FFFFEFF, par->vid_regs + CS5530_DOT_CLK_CONFIG); /* clear bypass */ +} + +static void cs5530_configure_display(struct fb_info *info) +{ + struct geodefb_par *par = info->par; + u32 dcfg; + + dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG); + + /* Clear bits from existing mode. */ + dcfg &= ~(CS5530_DCFG_CRT_SYNC_SKW_MASK | CS5530_DCFG_PWR_SEQ_DLY_MASK + | CS5530_DCFG_CRT_HSYNC_POL | CS5530_DCFG_CRT_VSYNC_POL + | CS5530_DCFG_FP_PWR_EN | CS5530_DCFG_FP_DATA_EN + | CS5530_DCFG_DAC_PWR_EN | CS5530_DCFG_VSYNC_EN + | CS5530_DCFG_HSYNC_EN); + + /* Set default sync skew and power sequence delays. */ + dcfg |= (CS5530_DCFG_CRT_SYNC_SKW_INIT | CS5530_DCFG_PWR_SEQ_DLY_INIT + | CS5530_DCFG_GV_PAL_BYP); + + /* Enable DACs, hsync and vsync for CRTs */ + if (par->enable_crt) { + dcfg |= CS5530_DCFG_DAC_PWR_EN; + dcfg |= CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN; + } + /* Enable panel power and data if using a flat panel. */ + if (par->panel_x > 0) { + dcfg |= CS5530_DCFG_FP_PWR_EN; + dcfg |= CS5530_DCFG_FP_DATA_EN; + } + + /* Sync polarities. */ + if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) + dcfg |= CS5530_DCFG_CRT_HSYNC_POL; + if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) + dcfg |= CS5530_DCFG_CRT_VSYNC_POL; + + writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG); +} + +static int cs5530_blank_display(struct fb_info *info, int blank_mode) +{ + struct geodefb_par *par = info->par; + u32 dcfg; + int blank, hsync, vsync; + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + blank = 0; hsync = 1; vsync = 1; + break; + case FB_BLANK_NORMAL: + blank = 1; hsync = 1; vsync = 1; + break; + case FB_BLANK_VSYNC_SUSPEND: + blank = 1; hsync = 1; vsync = 0; + break; + case FB_BLANK_HSYNC_SUSPEND: + blank = 1; hsync = 0; vsync = 1; + break; + case FB_BLANK_POWERDOWN: + blank = 1; hsync = 0; vsync = 0; + break; + default: + return -EINVAL; + } + + dcfg = readl(par->vid_regs + CS5530_DISPLAY_CONFIG); + + dcfg &= ~(CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN + | CS5530_DCFG_HSYNC_EN | CS5530_DCFG_VSYNC_EN + | CS5530_DCFG_FP_DATA_EN | CS5530_DCFG_FP_PWR_EN); + + if (par->enable_crt) { + if (!blank) + dcfg |= CS5530_DCFG_DAC_BL_EN | CS5530_DCFG_DAC_PWR_EN; + if (hsync) + dcfg |= CS5530_DCFG_HSYNC_EN; + if (vsync) + dcfg |= CS5530_DCFG_VSYNC_EN; + } + if (par->panel_x > 0) { + if (!blank) + dcfg |= CS5530_DCFG_FP_DATA_EN; + if (hsync && vsync) + dcfg |= CS5530_DCFG_FP_PWR_EN; + } + + writel(dcfg, par->vid_regs + CS5530_DISPLAY_CONFIG); + + return 0; +} + +struct geode_vid_ops cs5530_vid_ops = { + .set_dclk = cs5530_set_dclk_frequency, + .configure_display = cs5530_configure_display, + .blank_display = cs5530_blank_display, +}; diff --git a/drivers/video/geode/video_cs5530.h b/drivers/video/geode/video_cs5530.h new file mode 100644 index 000000000..56cecca7f --- /dev/null +++ b/drivers/video/geode/video_cs5530.h @@ -0,0 +1,75 @@ +/* + * drivers/video/geode/video_cs5530.h + * -- CS5530 video device + * + * Copyright (C) 2005 Arcom Control Systems Ltd. + * + * Based on AMD's original 2.4 driver: + * Copyright (C) 2004 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __VIDEO_CS5530_H__ +#define __VIDEO_CS5530_H__ + +extern struct geode_vid_ops cs5530_vid_ops; + +/* CS5530 Video device registers */ + +#define CS5530_VIDEO_CONFIG 0x0000 +# define CS5530_VCFG_VID_EN 0x00000001 +# define CS5530_VCFG_VID_REG_UPDATE 0x00000002 +# define CS5530_VCFG_VID_INP_FORMAT 0x0000000C +# define CS5530_VCFG_8_BIT_4_2_0 0x00000004 +# define CS5530_VCFG_16_BIT_4_2_0 0x00000008 +# define CS5530_VCFG_GV_SEL 0x00000010 +# define CS5530_VCFG_CSC_BYPASS 0x00000020 +# define CS5530_VCFG_X_FILTER_EN 0x00000040 +# define CS5530_VCFG_Y_FILTER_EN 0x00000080 +# define CS5530_VCFG_LINE_SIZE_LOWER_MASK 0x0000FF00 +# define CS5530_VCFG_INIT_READ_MASK 0x01FF0000 +# define CS5530_VCFG_EARLY_VID_RDY 0x02000000 +# define CS5530_VCFG_LINE_SIZE_UPPER 0x08000000 +# define CS5530_VCFG_4_2_0_MODE 0x10000000 +# define CS5530_VCFG_16_BIT_EN 0x20000000 +# define CS5530_VCFG_HIGH_SPD_INT 0x40000000 + +#define CS5530_DISPLAY_CONFIG 0x0004 +# define CS5530_DCFG_DIS_EN 0x00000001 +# define CS5530_DCFG_HSYNC_EN 0x00000002 +# define CS5530_DCFG_VSYNC_EN 0x00000004 +# define CS5530_DCFG_DAC_BL_EN 0x00000008 +# define CS5530_DCFG_DAC_PWR_EN 0x00000020 +# define CS5530_DCFG_FP_PWR_EN 0x00000040 +# define CS5530_DCFG_FP_DATA_EN 0x00000080 +# define CS5530_DCFG_CRT_HSYNC_POL 0x00000100 +# define CS5530_DCFG_CRT_VSYNC_POL 0x00000200 +# define CS5530_DCFG_FP_HSYNC_POL 0x00000400 +# define CS5530_DCFG_FP_VSYNC_POL 0x00000800 +# define CS5530_DCFG_XGA_FP 0x00001000 +# define CS5530_DCFG_FP_DITH_EN 0x00002000 +# define CS5530_DCFG_CRT_SYNC_SKW_MASK 0x0001C000 +# define CS5530_DCFG_CRT_SYNC_SKW_INIT 0x00010000 +# define CS5530_DCFG_PWR_SEQ_DLY_MASK 0x000E0000 +# define CS5530_DCFG_PWR_SEQ_DLY_INIT 0x00080000 +# define CS5530_DCFG_VG_CK 0x00100000 +# define CS5530_DCFG_GV_PAL_BYP 0x00200000 +# define CS5530_DCFG_DDC_SCL 0x00400000 +# define CS5530_DCFG_DDC_SDA 0x00800000 +# define CS5530_DCFG_DDC_OE 0x01000000 +# define CS5530_DCFG_16_BIT_EN 0x02000000 + +#define CS5530_VIDEO_X_POS 0x0008 +#define CS5530_VIDEO_Y_POS 0x000C +#define CS5530_VIDEO_SCALE 0x0010 +#define CS5530_VIDEO_COLOR_KEY 0x0014 +#define CS5530_VIDEO_COLOR_MASK 0x0018 +#define CS5530_PALETTE_ADDRESS 0x001C +#define CS5530_PALETTE_DATA 0x0020 +#define CS5530_DOT_CLK_CONFIG 0x0024 +#define CS5530_CRCSIG_TFT_TV 0x0028 + +#endif /* !__VIDEO_CS5530_H__ */ diff --git a/drivers/video/imxfb.h b/drivers/video/imxfb.h new file mode 100644 index 000000000..128c3ee51 --- /dev/null +++ b/drivers/video/imxfb.h @@ -0,0 +1,72 @@ +/* + * linux/drivers/video/imxfb.h + * + * Freescale i.MX Frame Buffer device driver + * + * Copyright (C) 2004 S.Hauer, Pengutronix + * + * Copyright (C) 1999 Eric A. Thomas + * Based on acornfb.c Copyright (C) Russell King. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +/* + * These are the bitfields for each + * display depth that we support. + */ +struct imxfb_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; +}; + +#define RGB_16 (0) +#define RGB_8 (1) +#define NR_RGB 2 + +struct imxfb_info { + struct device *dev; + struct imxfb_rgb *rgb[NR_RGB]; + + u_int max_bpp; + u_int max_xres; + u_int max_yres; + + /* + * These are the addresses we mapped + * the framebuffer memory region to. + */ + dma_addr_t map_dma; + u_char * map_cpu; + u_int map_size; + + u_char * screen_cpu; + dma_addr_t screen_dma; + u_int palette_size; + + dma_addr_t dbar1; + dma_addr_t dbar2; + + u_int pcr; + u_int pwmr; + u_int lscr1; + u_int cmap_inverse:1, + cmap_static:1, + unused:30; + + void (*lcd_power)(int); + void (*backlight_power)(int); +}; + +#define IMX_NAME "IMX" + +/* + * Minimum X and Y resolutions + */ +#define MIN_XRES 64 +#define MIN_YRES 64 + diff --git a/drivers/video/nvidia/nv_dma.h b/drivers/video/nvidia/nv_dma.h new file mode 100644 index 000000000..a7ed1c0ac --- /dev/null +++ b/drivers/video/nvidia/nv_dma.h @@ -0,0 +1,188 @@ + + /***************************************************************************\ +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NOTICE TO USER: The source code is copyrighted under U.S. and *| +|* international laws. Users and possessors of this source code are *| +|* hereby granted a nonexclusive, royalty-free copyright license to *| +|* use this code in individual and commercial software. *| +|* *| +|* Any use of this source code must include, in the user documenta- *| +|* tion and internal comments to the code, notices to the end user *| +|* as follows: *| +|* *| +|* Copyright 2003 NVIDIA, Corporation. All rights reserved. *| +|* *| +|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *| +|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *| +|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *| +|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *| +|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *| +|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *| +|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *| +|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *| +|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *| +|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *| +|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *| +|* *| +|* U.S. Government End Users. This source code is a "commercial *| +|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *| +|* consisting of "commercial computer software" and "commercial *| +|* computer software documentation," as such terms are used in *| +|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *| +|* ment only as a commercial end item. Consistent with 48 C.F.R. *| +|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *| +|* all U.S. Government End Users acquire the source code with only *| +|* those rights set forth herein. *| +|* *| + \***************************************************************************/ + +/* + * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/ + * XFree86 'nv' driver, this source code is provided under MIT-style licensing + * where the source code is provided "as is" without warranty of any kind. + * The only usage restriction is for the copyright notices to be retained + * whenever code is used. + * + * Antonino Daplas 2005-03-11 + */ + +#define SURFACE_FORMAT 0x00000300 +#define SURFACE_FORMAT_DEPTH8 0x00000001 +#define SURFACE_FORMAT_DEPTH15 0x00000002 +#define SURFACE_FORMAT_DEPTH16 0x00000004 +#define SURFACE_FORMAT_DEPTH24 0x00000006 +#define SURFACE_PITCH 0x00000304 +#define SURFACE_PITCH_SRC 15:0 +#define SURFACE_PITCH_DST 31:16 +#define SURFACE_OFFSET_SRC 0x00000308 +#define SURFACE_OFFSET_DST 0x0000030C + +#define ROP_SET 0x00002300 + +#define PATTERN_FORMAT 0x00004300 +#define PATTERN_FORMAT_DEPTH8 0x00000003 +#define PATTERN_FORMAT_DEPTH16 0x00000001 +#define PATTERN_FORMAT_DEPTH24 0x00000003 +#define PATTERN_COLOR_0 0x00004310 +#define PATTERN_COLOR_1 0x00004314 +#define PATTERN_PATTERN_0 0x00004318 +#define PATTERN_PATTERN_1 0x0000431C + +#define CLIP_POINT 0x00006300 +#define CLIP_POINT_X 15:0 +#define CLIP_POINT_Y 31:16 +#define CLIP_SIZE 0x00006304 +#define CLIP_SIZE_WIDTH 15:0 +#define CLIP_SIZE_HEIGHT 31:16 + +#define LINE_FORMAT 0x00008300 +#define LINE_FORMAT_DEPTH8 0x00000003 +#define LINE_FORMAT_DEPTH16 0x00000001 +#define LINE_FORMAT_DEPTH24 0x00000003 +#define LINE_COLOR 0x00008304 +#define LINE_MAX_LINES 16 +#define LINE_LINES(i) 0x00008400\ + +(i)*8 +#define LINE_LINES_POINT0_X 15:0 +#define LINE_LINES_POINT0_Y 31:16 +#define LINE_LINES_POINT1_X 47:32 +#define LINE_LINES_POINT1_Y 63:48 + +#define BLIT_POINT_SRC 0x0000A300 +#define BLIT_POINT_SRC_X 15:0 +#define BLIT_POINT_SRC_Y 31:16 +#define BLIT_POINT_DST 0x0000A304 +#define BLIT_POINT_DST_X 15:0 +#define BLIT_POINT_DST_Y 31:16 +#define BLIT_SIZE 0x0000A308 +#define BLIT_SIZE_WIDTH 15:0 +#define BLIT_SIZE_HEIGHT 31:16 + +#define RECT_FORMAT 0x0000C300 +#define RECT_FORMAT_DEPTH8 0x00000003 +#define RECT_FORMAT_DEPTH16 0x00000001 +#define RECT_FORMAT_DEPTH24 0x00000003 +#define RECT_SOLID_COLOR 0x0000C3FC +#define RECT_SOLID_RECTS_MAX_RECTS 32 +#define RECT_SOLID_RECTS(i) 0x0000C400\ + +(i)*8 +#define RECT_SOLID_RECTS_Y 15:0 +#define RECT_SOLID_RECTS_X 31:16 +#define RECT_SOLID_RECTS_HEIGHT 47:32 +#define RECT_SOLID_RECTS_WIDTH 63:48 + +#define RECT_EXPAND_ONE_COLOR_CLIP 0x0000C7EC +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_X 15:0 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT0_Y 31:16 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_X 47:32 +#define RECT_EXPAND_ONE_COLOR_CLIP_POINT1_Y 63:48 +#define RECT_EXPAND_ONE_COLOR_COLOR 0x0000C7F4 +#define RECT_EXPAND_ONE_COLOR_SIZE 0x0000C7F8 +#define RECT_EXPAND_ONE_COLOR_SIZE_WIDTH 15:0 +#define RECT_EXPAND_ONE_COLOR_SIZE_HEIGHT 31:16 +#define RECT_EXPAND_ONE_COLOR_POINT 0x0000C7FC +#define RECT_EXPAND_ONE_COLOR_POINT_X 15:0 +#define RECT_EXPAND_ONE_COLOR_POINT_Y 31:16 +#define RECT_EXPAND_ONE_COLOR_DATA_MAX_DWORDS 128 +#define RECT_EXPAND_ONE_COLOR_DATA(i) 0x0000C800\ + +(i)*4 + +#define RECT_EXPAND_TWO_COLOR_CLIP 0x0000CBE4 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_X 15:0 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT0_Y 31:16 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_X 47:32 +#define RECT_EXPAND_TWO_COLOR_CLIP_POINT1_Y 63:48 +#define RECT_EXPAND_TWO_COLOR_COLOR_0 0x0000CBEC +#define RECT_EXPAND_TWO_COLOR_COLOR_1 0x0000CBF0 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN 0x0000CBF4 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN_WIDTH 15:0 +#define RECT_EXPAND_TWO_COLOR_SIZE_IN_HEIGHT 31:16 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT 0x0000CBF8 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_WIDTH 15:0 +#define RECT_EXPAND_TWO_COLOR_SIZE_OUT_HEIGHT 31:16 +#define RECT_EXPAND_TWO_COLOR_POINT 0x0000CBFC +#define RECT_EXPAND_TWO_COLOR_POINT_X 15:0 +#define RECT_EXPAND_TWO_COLOR_POINT_Y 31:16 +#define RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS 128 +#define RECT_EXPAND_TWO_COLOR_DATA(i) 0x0000CC00\ + +(i)*4 + +#define STRETCH_BLIT_FORMAT 0x0000E300 +#define STRETCH_BLIT_FORMAT_DEPTH8 0x00000004 +#define STRETCH_BLIT_FORMAT_DEPTH16 0x00000007 +#define STRETCH_BLIT_FORMAT_DEPTH24 0x00000004 +#define STRETCH_BLIT_FORMAT_X8R8G8B8 0x00000004 +#define STRETCH_BLIT_FORMAT_YUYV 0x00000005 +#define STRETCH_BLIT_FORMAT_UYVY 0x00000006 +#define STRETCH_BLIT_CLIP_POINT 0x0000E308 +#define STRETCH_BLIT_CLIP_POINT_X 15:0 +#define STRETCH_BLIT_CLIP_POINT_Y 31:16 +#define STRETCH_BLIT_CLIP_POINT 0x0000E308 +#define STRETCH_BLIT_CLIP_SIZE 0x0000E30C +#define STRETCH_BLIT_CLIP_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_CLIP_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_DST_POINT 0x0000E310 +#define STRETCH_BLIT_DST_POINT_X 15:0 +#define STRETCH_BLIT_DST_POINT_Y 31:16 +#define STRETCH_BLIT_DST_SIZE 0x0000E314 +#define STRETCH_BLIT_DST_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_DST_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_DU_DX 0x0000E318 +#define STRETCH_BLIT_DV_DY 0x0000E31C +#define STRETCH_BLIT_SRC_SIZE 0x0000E400 +#define STRETCH_BLIT_SRC_SIZE_WIDTH 15:0 +#define STRETCH_BLIT_SRC_SIZE_HEIGHT 31:16 +#define STRETCH_BLIT_SRC_FORMAT 0x0000E404 +#define STRETCH_BLIT_SRC_FORMAT_PITCH 15:0 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN 23:16 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CENTER 0x00000001 +#define STRETCH_BLIT_SRC_FORMAT_ORIGIN_CORNER 0x00000002 +#define STRETCH_BLIT_SRC_FORMAT_FILTER 31:24 +#define STRETCH_BLIT_SRC_FORMAT_FILTER_POINT_SAMPLE 0x00000000 +#define STRETCH_BLIT_SRC_FORMAT_FILTER_BILINEAR 0x00000001 +#define STRETCH_BLIT_SRC_OFFSET 0x0000E408 +#define STRETCH_BLIT_SRC_POINT 0x0000E40C +#define STRETCH_BLIT_SRC_POINT_U 15:0 +#define STRETCH_BLIT_SRC_POINT_V 31:16 diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile new file mode 100644 index 000000000..7bb479830 --- /dev/null +++ b/drivers/xen/Makefile @@ -0,0 +1,13 @@ + + +obj-y += console/ +obj-y += evtchn/ +obj-y += balloon/ + +obj-$(CONFIG_XEN_PRIVILEGED_GUEST) += privcmd/ +obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ +obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/ +obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/ +obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ +obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/ + diff --git a/drivers/xen/balloon/Makefile b/drivers/xen/balloon/Makefile new file mode 100644 index 000000000..0e3a3485c --- /dev/null +++ b/drivers/xen/balloon/Makefile @@ -0,0 +1,2 @@ + +obj-y += balloon.o diff --git a/drivers/xen/balloon/balloon.c b/drivers/xen/balloon/balloon.c new file mode 100644 index 000000000..649f64c40 --- /dev/null +++ b/drivers/xen/balloon/balloon.c @@ -0,0 +1,438 @@ +/****************************************************************************** + * balloon.c + * + * Xen balloon driver - enables returning/claiming memory to/from Xen. + * + * Copyright (c) 2003, B Dragovic + * Copyright (c) 2003-2004, M Williamson, K Fraser + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct proc_dir_entry *balloon_pde; + +static DECLARE_MUTEX(balloon_mutex); +spinlock_t balloon_lock = SPIN_LOCK_UNLOCKED; + +/* We aim for 'current allocation' == 'target allocation'. */ +static unsigned long current_pages; +static unsigned long target_pages; + +/* We may hit the hard limit in Xen. If we do then we remember it. */ +static unsigned long hard_limit; + +/* + * Drivers may alter the memory reservation independently, but they must + * inform the balloon driver so that we can avoid hitting the hard limit. + */ +static unsigned long driver_pages; + +/* List of ballooned pages, threaded through the mem_map array. */ +static LIST_HEAD(ballooned_pages); +static unsigned long balloon_low, balloon_high; + +/* Main work function, always executed in process context. */ +static void balloon_process(void *unused); +static DECLARE_WORK(balloon_worker, balloon_process, NULL); +static struct timer_list balloon_timer; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +/* Use the private and mapping fields of struct page as a list. */ +#define PAGE_TO_LIST(p) ( (struct list_head *)&p->private ) +#define LIST_TO_PAGE(l) ( list_entry( ((unsigned long *)l), \ + struct page, private ) ) +#define UNLIST_PAGE(p) do { list_del(PAGE_TO_LIST(p)); \ + p->mapping = NULL; \ + p->private = 0; } while(0) +#else +/* There's a dedicated list field in struct page we can use. */ +#define PAGE_TO_LIST(p) ( &p->list ) +#define LIST_TO_PAGE(l) ( list_entry(l, struct page, list) ) +#define UNLIST_PAGE(p) ( list_del(&p->list) ) +#define pte_offset_kernel pte_offset +#define pud_t pgd_t +#define pud_offset(d, va) d +#define pud_none(d) 0 +#define pud_bad(d) 0 +#define subsys_initcall(_fn) __initcall(_fn) +#define pfn_to_page(_pfn) (mem_map + (_pfn)) +#endif + +#define IPRINTK(fmt, args...) \ + printk(KERN_INFO "xen_mem: " fmt, ##args) +#define WPRINTK(fmt, args...) \ + printk(KERN_WARNING "xen_mem: " fmt, ##args) + +/* balloon_append: add the given page to the balloon. */ +static void balloon_append(struct page *page) +{ + /* Low memory is re-populated first, so highmem pages go at list tail. */ + if ( PageHighMem(page) ) + { + list_add_tail(PAGE_TO_LIST(page), &ballooned_pages); + balloon_high++; + } + else + { + list_add(PAGE_TO_LIST(page), &ballooned_pages); + balloon_low++; + } +} + +/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */ +static struct page *balloon_retrieve(void) +{ + struct page *page; + + if ( list_empty(&ballooned_pages) ) + return NULL; + + page = LIST_TO_PAGE(ballooned_pages.next); + UNLIST_PAGE(page); + + if ( PageHighMem(page) ) + balloon_high--; + else + balloon_low--; + + return page; +} + +static void balloon_alarm(unsigned long unused) +{ + schedule_work(&balloon_worker); +} + +static unsigned long current_target(void) +{ + unsigned long target = min(target_pages, hard_limit); + if ( target > (current_pages + balloon_low + balloon_high) ) + target = current_pages + balloon_low + balloon_high; + return target; +} + +/* + * We avoid multiple worker processes conflicting via the balloon mutex. + * We may of course race updates of the target counts (which are protected + * by the balloon lock), or with changes to the Xen hard limit, but we will + * recover from these in time. + */ +static void balloon_process(void *unused) +{ + unsigned long *mfn_list, pfn, i, flags; + struct page *page; + long credit, debt, rc; + void *v; + + down(&balloon_mutex); + + retry: + mfn_list = NULL; + + if ( (credit = current_target() - current_pages) > 0 ) + { + mfn_list = (unsigned long *)vmalloc(credit * sizeof(*mfn_list)); + if ( mfn_list == NULL ) + goto out; + + balloon_lock(flags); + rc = HYPERVISOR_dom_mem_op( + MEMOP_increase_reservation, mfn_list, credit, 0); + balloon_unlock(flags); + if ( rc < credit ) + { + /* We hit the Xen hard limit: reprobe. */ + if ( HYPERVISOR_dom_mem_op( + MEMOP_decrease_reservation, mfn_list, rc, 0) != rc ) + BUG(); + hard_limit = current_pages + rc - driver_pages; + vfree(mfn_list); + goto retry; + } + + for ( i = 0; i < credit; i++ ) + { + if ( (page = balloon_retrieve()) == NULL ) + BUG(); + + pfn = page - mem_map; + if ( phys_to_machine_mapping[pfn] != INVALID_P2M_ENTRY ) + BUG(); + + /* Update P->M and M->P tables. */ + phys_to_machine_mapping[pfn] = mfn_list[i]; + xen_machphys_update(mfn_list[i], pfn); + + /* Link back into the page tables if it's not a highmem page. */ + if ( pfn < max_low_pfn ) + { + HYPERVISOR_update_va_mapping( + (unsigned long)__va(pfn << PAGE_SHIFT), + __pte_ma((mfn_list[i] << PAGE_SHIFT) | + pgprot_val(PAGE_KERNEL)), + 0); + } + + /* Finally, relinquish the memory back to the system allocator. */ + ClearPageReserved(page); + set_page_count(page, 1); + __free_page(page); + } + + current_pages += credit; + } + else if ( credit < 0 ) + { + debt = -credit; + + mfn_list = (unsigned long *)vmalloc(debt * sizeof(*mfn_list)); + if ( mfn_list == NULL ) + goto out; + + for ( i = 0; i < debt; i++ ) + { + if ( (page = alloc_page(GFP_HIGHUSER)) == NULL ) + { + debt = i; + break; + } + + pfn = page - mem_map; + mfn_list[i] = phys_to_machine_mapping[pfn]; + + if ( !PageHighMem(page) ) + { + v = phys_to_virt(pfn << PAGE_SHIFT); + scrub_pages(v, 1); + HYPERVISOR_update_va_mapping( + (unsigned long)v, __pte_ma(0), 0); + } +#ifdef CONFIG_XEN_SCRUB_PAGES + else + { + v = kmap(page); + scrub_pages(v, 1); + kunmap(page); + } +#endif + } + + /* Ensure that ballooned highmem pages don't have cached mappings. */ + kmap_flush_unused(); + flush_tlb_all(); + + /* No more mappings: invalidate pages in P2M and add to balloon. */ + for ( i = 0; i < debt; i++ ) + { + pfn = mfn_to_pfn(mfn_list[i]); + phys_to_machine_mapping[pfn] = INVALID_P2M_ENTRY; + balloon_append(pfn_to_page(pfn)); + } + + if ( HYPERVISOR_dom_mem_op( + MEMOP_decrease_reservation, mfn_list, debt, 0) != debt ) + BUG(); + + current_pages -= debt; + } + + out: + if ( mfn_list != NULL ) + vfree(mfn_list); + + /* Schedule more work if there is some still to be done. */ + if ( current_target() != current_pages ) + mod_timer(&balloon_timer, jiffies + HZ); + + up(&balloon_mutex); +} + +/* Resets the Xen limit, sets new target, and kicks off processing. */ +static void set_new_target(unsigned long target) +{ + /* No need for lock. Not read-modify-write updates. */ + hard_limit = ~0UL; + target_pages = target; + schedule_work(&balloon_worker); +} + +static void balloon_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) +{ + switch ( msg->subtype ) + { + case CMSG_MEM_REQUEST_SET: + { + mem_request_t *req = (mem_request_t *)&msg->msg[0]; + set_new_target(req->target); + req->status = 0; + } + break; + + default: + msg->length = 0; + break; + } + + ctrl_if_send_response(msg); +} + +static int balloon_write(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + char memstring[64], *endchar; + unsigned long long target_bytes; + + if ( !capable(CAP_SYS_ADMIN) ) + return -EPERM; + + if ( count <= 1 ) + return -EBADMSG; /* runt */ + if ( count > sizeof(memstring) ) + return -EFBIG; /* too long */ + + if ( copy_from_user(memstring, buffer, count) ) + return -EFAULT; + memstring[sizeof(memstring)-1] = '\0'; + + target_bytes = memparse(memstring, &endchar); + set_new_target(target_bytes >> PAGE_SHIFT); + + return count; +} + +static int balloon_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + +#define K(_p) ((_p)<<(PAGE_SHIFT-10)) + len = sprintf( + page, + "Current allocation: %8lu kB\n" + "Requested target: %8lu kB\n" + "Low-mem balloon: %8lu kB\n" + "High-mem balloon: %8lu kB\n" + "Xen hard limit: ", + K(current_pages), K(target_pages), K(balloon_low), K(balloon_high)); + + if ( hard_limit != ~0UL ) + len += sprintf( + page + len, + "%8lu kB (inc. %8lu kB driver headroom)\n", + K(hard_limit), K(driver_pages)); + else + len += sprintf( + page + len, + " ??? kB\n"); + + *eof = 1; + return len; +} + +static int __init balloon_init(void) +{ + unsigned long pfn; + struct page *page; + + IPRINTK("Initialising balloon driver.\n"); + + current_pages = min(xen_start_info.nr_pages, max_pfn); + target_pages = current_pages; + balloon_low = 0; + balloon_high = 0; + driver_pages = 0UL; + hard_limit = ~0UL; + + init_timer(&balloon_timer); + balloon_timer.data = 0; + balloon_timer.function = balloon_alarm; + + if ( (balloon_pde = create_xen_proc_entry("balloon", 0644)) == NULL ) + { + WPRINTK("Unable to create /proc/xen/balloon.\n"); + return -1; + } + + balloon_pde->read_proc = balloon_read; + balloon_pde->write_proc = balloon_write; + + (void)ctrl_if_register_receiver(CMSG_MEM_REQUEST, balloon_ctrlif_rx, 0); + + /* Initialise the balloon with excess memory space. */ + for ( pfn = xen_start_info.nr_pages; pfn < max_pfn; pfn++ ) + { + page = &mem_map[pfn]; + if ( !PageReserved(page) ) + balloon_append(page); + } + + return 0; +} + +subsys_initcall(balloon_init); + +void balloon_update_driver_allowance(long delta) +{ + unsigned long flags; + balloon_lock(flags); + driver_pages += delta; /* non-atomic update */ + balloon_unlock(flags); +} + +void balloon_put_pages(unsigned long *mfn_list, unsigned long nr_mfns) +{ + unsigned long flags; + + balloon_lock(flags); + if ( HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation, + mfn_list, nr_mfns, 0) != nr_mfns ) + BUG(); + current_pages -= nr_mfns; /* non-atomic update */ + balloon_unlock(flags); + + schedule_work(&balloon_worker); +} + +EXPORT_SYMBOL(balloon_update_driver_allowance); +EXPORT_SYMBOL(balloon_put_pages); diff --git a/drivers/xen/blkback/Makefile b/drivers/xen/blkback/Makefile new file mode 100644 index 000000000..a27fe65f4 --- /dev/null +++ b/drivers/xen/blkback/Makefile @@ -0,0 +1,2 @@ + +obj-y := blkback.o control.o interface.o vbd.o diff --git a/drivers/xen/blkback/blkback.c b/drivers/xen/blkback/blkback.c new file mode 100644 index 000000000..2554f999d --- /dev/null +++ b/drivers/xen/blkback/blkback.c @@ -0,0 +1,751 @@ +/****************************************************************************** + * arch/xen/drivers/blkif/backend/main.c + * + * Back-end of the driver for virtual block devices. This portion of the + * driver exports a 'unified' block-device interface that can be accessed + * by any operating system that implements a compatible front end. A + * reference front-end implementation can be found in: + * arch/xen/drivers/blkif/frontend + * + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + * Copyright (c) 2005, Christopher Clark + */ + +#include "common.h" +#include +#ifdef CONFIG_XEN_BLKDEV_GRANT +#include +#endif + +/* + * These are rather arbitrary. They are fairly large because adjacent requests + * pulled from a communication ring are quite likely to end up being part of + * the same scatter/gather request at the disc. + * + * ** TRY INCREASING 'MAX_PENDING_REQS' IF WRITE SPEEDS SEEM TOO LOW ** + * This will increase the chances of being able to write whole tracks. + * 64 should be enough to keep us competitive with Linux. + */ +#define MAX_PENDING_REQS 64 +#define BATCH_PER_DOMAIN 16 + +static unsigned long mmap_vstart; +#define MMAP_PAGES \ + (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST) +#define MMAP_VADDR(_req,_seg) \ + (mmap_vstart + \ + ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) + \ + ((_seg) * PAGE_SIZE)) + +/* + * Each outstanding request that we've passed to the lower device layers has a + * 'pending_req' allocated to it. Each buffer_head that completes decrements + * the pendcnt towards zero. When it hits zero, the specified domain has a + * response queued for it, with the saved 'id' passed back. + */ +typedef struct { + blkif_t *blkif; + unsigned long id; + int nr_pages; + atomic_t pendcnt; + unsigned short operation; + int status; +} pending_req_t; + +/* + * We can't allocate pending_req's in order, since they may complete out of + * order. We therefore maintain an allocation ring. This ring also indicates + * when enough work has been passed down -- at that point the allocation ring + * will be empty. + */ +static pending_req_t pending_reqs[MAX_PENDING_REQS]; +static unsigned char pending_ring[MAX_PENDING_REQS]; +static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED; +/* NB. We use a different index type to differentiate from shared blk rings. */ +typedef unsigned int PEND_RING_IDX; +#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1)) +static PEND_RING_IDX pending_prod, pending_cons; +#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +static kmem_cache_t *buffer_head_cachep; +#else +static request_queue_t *plugged_queue; +static inline void flush_plugged_queue(void) +{ + request_queue_t *q = plugged_queue; + if ( q != NULL ) + { + if ( q->unplug_fn != NULL ) + q->unplug_fn(q); + blk_put_queue(q); + plugged_queue = NULL; + } +} +#endif + +#ifdef CONFIG_XEN_BLKDEV_GRANT +/* When using grant tables to map a frame for device access then the + * handle returned must be used to unmap the frame. This is needed to + * drop the ref count on the frame. + */ +static u16 pending_grant_handles[MMAP_PAGES]; +#define pending_handle(_idx, _i) \ + (pending_grant_handles[((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) + (_i)]) +#define BLKBACK_INVALID_HANDLE (0xFFFF) +#endif + +#ifdef CONFIG_XEN_BLKDEV_TAP_BE +/* + * If the tap driver is used, we may get pages belonging to either the tap + * or (more likely) the real frontend. The backend must specify which domain + * a given page belongs to in update_va_mapping though. For the moment, + * the tap rewrites the ID field of the request to contain the request index + * and the id of the real front end domain. + */ +#define BLKTAP_COOKIE 0xbeadfeed +static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); } +#endif + +static int do_block_io_op(blkif_t *blkif, int max_to_do); +static void dispatch_probe(blkif_t *blkif, blkif_request_t *req); +static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req); +static void make_response(blkif_t *blkif, unsigned long id, + unsigned short op, int st); + +static void fast_flush_area(int idx, int nr_pages) +{ +#ifdef CONFIG_XEN_BLKDEV_GRANT + gnttab_op_t aop[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + unsigned int i, invcount = 0; + u16 handle; + + for ( i = 0; i < nr_pages; i++ ) + { + if ( BLKBACK_INVALID_HANDLE != ( handle = pending_handle(idx, i) ) ) + { + aop[i].u.unmap_grant_ref.host_virt_addr = MMAP_VADDR(idx, i); + aop[i].u.unmap_grant_ref.dev_bus_addr = 0; + aop[i].u.unmap_grant_ref.handle = handle; + pending_handle(idx, i) = BLKBACK_INVALID_HANDLE; + invcount++; + } + } + if ( unlikely(HYPERVISOR_grant_table_op( + GNTTABOP_unmap_grant_ref, aop, invcount))) + BUG(); +#else + + multicall_entry_t mcl[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + int i; + + for ( i = 0; i < nr_pages; i++ ) + { + mcl[i].op = __HYPERVISOR_update_va_mapping; + mcl[i].args[0] = MMAP_VADDR(idx, i); + mcl[i].args[1] = 0; + mcl[i].args[2] = 0; + } + + mcl[nr_pages-1].args[2] = UVMF_TLB_FLUSH|UVMF_ALL; + if ( unlikely(HYPERVISOR_multicall(mcl, nr_pages) != 0) ) + BUG(); +#endif +} + + +/****************************************************************** + * BLOCK-DEVICE SCHEDULER LIST MAINTENANCE + */ + +static struct list_head blkio_schedule_list; +static spinlock_t blkio_schedule_list_lock; + +static int __on_blkdev_list(blkif_t *blkif) +{ + return blkif->blkdev_list.next != NULL; +} + +static void remove_from_blkdev_list(blkif_t *blkif) +{ + unsigned long flags; + if ( !__on_blkdev_list(blkif) ) return; + spin_lock_irqsave(&blkio_schedule_list_lock, flags); + if ( __on_blkdev_list(blkif) ) + { + list_del(&blkif->blkdev_list); + blkif->blkdev_list.next = NULL; + blkif_put(blkif); + } + spin_unlock_irqrestore(&blkio_schedule_list_lock, flags); +} + +static void add_to_blkdev_list_tail(blkif_t *blkif) +{ + unsigned long flags; + if ( __on_blkdev_list(blkif) ) return; + spin_lock_irqsave(&blkio_schedule_list_lock, flags); + if ( !__on_blkdev_list(blkif) && (blkif->status == CONNECTED) ) + { + list_add_tail(&blkif->blkdev_list, &blkio_schedule_list); + blkif_get(blkif); + } + spin_unlock_irqrestore(&blkio_schedule_list_lock, flags); +} + + +/****************************************************************** + * SCHEDULER FUNCTIONS + */ + +static DECLARE_WAIT_QUEUE_HEAD(blkio_schedule_wait); + +static int blkio_schedule(void *arg) +{ + DECLARE_WAITQUEUE(wq, current); + + blkif_t *blkif; + struct list_head *ent; + + daemonize( +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + "xenblkd" +#endif + ); + + for ( ; ; ) + { + /* Wait for work to do. */ + add_wait_queue(&blkio_schedule_wait, &wq); + set_current_state(TASK_INTERRUPTIBLE); + if ( (NR_PENDING_REQS == MAX_PENDING_REQS) || + list_empty(&blkio_schedule_list) ) + schedule(); + __set_current_state(TASK_RUNNING); + remove_wait_queue(&blkio_schedule_wait, &wq); + + /* Queue up a batch of requests. */ + while ( (NR_PENDING_REQS < MAX_PENDING_REQS) && + !list_empty(&blkio_schedule_list) ) + { + ent = blkio_schedule_list.next; + blkif = list_entry(ent, blkif_t, blkdev_list); + blkif_get(blkif); + remove_from_blkdev_list(blkif); + if ( do_block_io_op(blkif, BATCH_PER_DOMAIN) ) + add_to_blkdev_list_tail(blkif); + blkif_put(blkif); + } + + /* Push the batch through to disc. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + run_task_queue(&tq_disk); +#else + flush_plugged_queue(); +#endif + } +} + +static void maybe_trigger_blkio_schedule(void) +{ + /* + * Needed so that two processes, who together make the following predicate + * true, don't both read stale values and evaluate the predicate + * incorrectly. Incredibly unlikely to stall the scheduler on x86, but... + */ + smp_mb(); + + if ( (NR_PENDING_REQS < (MAX_PENDING_REQS/2)) && + !list_empty(&blkio_schedule_list) ) + wake_up(&blkio_schedule_wait); +} + + + +/****************************************************************** + * COMPLETION CALLBACK -- Called as bh->b_end_io() + */ + +static void __end_block_io_op(pending_req_t *pending_req, int uptodate) +{ + unsigned long flags; + + /* An error fails the entire request. */ + if ( !uptodate ) + { + DPRINTK("Buffer not up-to-date at end of operation\n"); + pending_req->status = BLKIF_RSP_ERROR; + } + + if ( atomic_dec_and_test(&pending_req->pendcnt) ) + { + int pending_idx = pending_req - pending_reqs; + fast_flush_area(pending_idx, pending_req->nr_pages); + make_response(pending_req->blkif, pending_req->id, + pending_req->operation, pending_req->status); + blkif_put(pending_req->blkif); + spin_lock_irqsave(&pend_prod_lock, flags); + pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; + spin_unlock_irqrestore(&pend_prod_lock, flags); + maybe_trigger_blkio_schedule(); + } +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +static void end_block_io_op(struct buffer_head *bh, int uptodate) +{ + __end_block_io_op(bh->b_private, uptodate); + kmem_cache_free(buffer_head_cachep, bh); +} +#else +static int end_block_io_op(struct bio *bio, unsigned int done, int error) +{ + if ( done || error ) + __end_block_io_op(bio->bi_private, (done && !error)); + bio_put(bio); + return error; +} +#endif + + +/****************************************************************************** + * NOTIFICATION FROM GUEST OS. + */ + +irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs) +{ + blkif_t *blkif = dev_id; + add_to_blkdev_list_tail(blkif); + maybe_trigger_blkio_schedule(); + return IRQ_HANDLED; +} + + + +/****************************************************************** + * DOWNWARD CALLS -- These interface with the block-device layer proper. + */ + +static int do_block_io_op(blkif_t *blkif, int max_to_do) +{ + blkif_back_ring_t *blk_ring = &blkif->blk_ring; + blkif_request_t *req; + RING_IDX i, rp; + int more_to_do = 0; + + rp = blk_ring->sring->req_prod; + rmb(); /* Ensure we see queued requests up to 'rp'. */ + + for ( i = blk_ring->req_cons; + (i != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, i); + i++ ) + { + if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) ) + { + more_to_do = 1; + break; + } + + req = RING_GET_REQUEST(blk_ring, i); + switch ( req->operation ) + { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + dispatch_rw_block_io(blkif, req); + break; + + case BLKIF_OP_PROBE: + dispatch_probe(blkif, req); + break; + + default: + DPRINTK("error: unknown block io operation [%d]\n", + req->operation); + make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); + break; + } + } + + blk_ring->req_cons = i; + return more_to_do; +} + +static void dispatch_probe(blkif_t *blkif, blkif_request_t *req) +{ + int rsp = BLKIF_RSP_ERROR; + int pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; + + /* We expect one buffer only. */ + if ( unlikely(req->nr_segments != 1) ) + goto out; + + /* Make sure the buffer is page-sized. */ + if ( (blkif_first_sect(req->frame_and_sects[0]) != 0) || + (blkif_last_sect(req->frame_and_sects[0]) != 7) ) + goto out; + +#ifdef CONFIG_XEN_BLKDEV_GRANT + { + gnttab_op_t op; + + op.u.map_grant_ref.host_virt_addr = MMAP_VADDR(pending_idx, 0); + op.u.map_grant_ref.flags = GNTMAP_host_map; + op.u.map_grant_ref.ref = blkif_gref_from_fas(req->frame_and_sects[0]); + op.u.map_grant_ref.dom = blkif->domid; + + if ( unlikely(HYPERVISOR_grant_table_op( + GNTTABOP_map_grant_ref, &op, 1))) + BUG(); + + if ( op.u.map_grant_ref.handle < 0 ) + goto out; + + pending_handle(pending_idx, 0) = op.u.map_grant_ref.handle; + } +#else /* else CONFIG_XEN_BLKDEV_GRANT */ + +#ifdef CONFIG_XEN_BLKDEV_TAP_BE + /* Grab the real frontend out of the probe message. */ + if (req->frame_and_sects[1] == BLKTAP_COOKIE) + blkif->is_blktap = 1; +#endif + + +#ifdef CONFIG_XEN_BLKDEV_TAP_BE + if ( HYPERVISOR_update_va_mapping_otherdomain( + MMAP_VADDR(pending_idx, 0), + (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL }, + 0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) ) + + goto out; +#else + if ( HYPERVISOR_update_va_mapping_otherdomain( + MMAP_VADDR(pending_idx, 0), + (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL }, + 0, blkif->domid) ) + + goto out; +#endif +#endif /* endif CONFIG_XEN_BLKDEV_GRANT */ + + rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0), + PAGE_SIZE / sizeof(vdisk_t)); + + out: + fast_flush_area(pending_idx, 1); + make_response(blkif, req->id, req->operation, rsp); +} + +static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req) +{ + extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]); + int operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ; + unsigned long fas = 0; + int i, pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; + pending_req_t *pending_req; +#ifdef CONFIG_XEN_BLKDEV_GRANT + gnttab_op_t aop[BLKIF_MAX_SEGMENTS_PER_REQUEST]; +#else + unsigned long remap_prot; + multicall_entry_t mcl[BLKIF_MAX_SEGMENTS_PER_REQUEST]; +#endif + struct phys_req preq; + struct { + unsigned long buf; unsigned int nsec; + } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + unsigned int nseg; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + struct buffer_head *bh; +#else + struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST]; + int nbio = 0; + request_queue_t *q; +#endif + + /* Check that number of segments is sane. */ + nseg = req->nr_segments; + if ( unlikely(nseg == 0) || + unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) ) + { + DPRINTK("Bad number of segments in request (%d)\n", nseg); + goto bad_descriptor; + } + + preq.dev = req->device; + preq.sector_number = req->sector_number; + preq.nr_sects = 0; + +#ifdef CONFIG_XEN_BLKDEV_GRANT + for ( i = 0; i < nseg; i++ ) + { + fas = req->frame_and_sects[i]; + seg[i].nsec = blkif_last_sect(fas) - blkif_first_sect(fas) + 1; + + if ( seg[i].nsec <= 0 ) + goto bad_descriptor; + preq.nr_sects += seg[i].nsec; + + aop[i].u.map_grant_ref.host_virt_addr = MMAP_VADDR(pending_idx, i); + + aop[i].u.map_grant_ref.dom = blkif->domid; + aop[i].u.map_grant_ref.ref = blkif_gref_from_fas(fas); + aop[i].u.map_grant_ref.flags = ( GNTMAP_host_map | + ( ( operation == READ ) ? + 0 : GNTMAP_readonly ) ); + } + + if ( unlikely(HYPERVISOR_grant_table_op( + GNTTABOP_map_grant_ref, aop, nseg))) + BUG(); + + for ( i = 0; i < nseg; i++ ) + { + if ( unlikely(aop[i].u.map_grant_ref.handle < 0) ) + { + DPRINTK("invalid buffer -- could not remap it\n"); + fast_flush_area(pending_idx, nseg); + goto bad_descriptor; + } + + phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] = + FOREIGN_FRAME(aop[i].u.map_grant_ref.dev_bus_addr); + + pending_handle(pending_idx, i) = aop[i].u.map_grant_ref.handle; + } +#endif + + for ( i = 0; i < nseg; i++ ) + { + fas = req->frame_and_sects[i]; +#ifdef CONFIG_XEN_BLKDEV_GRANT + seg[i].buf = (aop[i].u.map_grant_ref.dev_bus_addr << PAGE_SHIFT) | + (blkif_first_sect(fas) << 9); +#else + seg[i].buf = (fas & PAGE_MASK) | (blkif_first_sect(fas) << 9); + seg[i].nsec = blkif_last_sect(fas) - blkif_first_sect(fas) + 1; + if ( seg[i].nsec <= 0 ) + goto bad_descriptor; + preq.nr_sects += seg[i].nsec; +#endif + } + + if ( vbd_translate(&preq, blkif, operation) != 0 ) + { + DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n", + operation == READ ? "read" : "write", preq.sector_number, + preq.sector_number + preq.nr_sects, preq.dev); + goto bad_descriptor; + } + +#ifndef CONFIG_XEN_BLKDEV_GRANT + if ( operation == READ ) + remap_prot = _PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW; + else + remap_prot = _PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED; + + for ( i = 0; i < nseg; i++ ) + { + mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain; + mcl[i].args[0] = MMAP_VADDR(pending_idx, i); + mcl[i].args[1] = (seg[i].buf & PAGE_MASK) | remap_prot; + mcl[i].args[2] = 0; + mcl[i].args[3] = blkif->domid; +#ifdef CONFIG_XEN_BLKDEV_TAP_BE + if ( blkif->is_blktap ) + mcl[i].args[3] = ID_TO_DOM(req->id); +#endif + phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] = + FOREIGN_FRAME(seg[i].buf >> PAGE_SHIFT); + } + + BUG_ON(HYPERVISOR_multicall(mcl, nseg) != 0); + + for ( i = 0; i < nseg; i++ ) + { + if ( unlikely(mcl[i].args[5] != 0) ) + { + DPRINTK("invalid buffer -- could not remap it\n"); + fast_flush_area(pending_idx, nseg); + goto bad_descriptor; + } + } +#endif /* end ifndef CONFIG_XEN_BLKDEV_GRANT */ + + pending_req = &pending_reqs[pending_idx]; + pending_req->blkif = blkif; + pending_req->id = req->id; + pending_req->operation = operation; + pending_req->status = BLKIF_RSP_OKAY; + pending_req->nr_pages = nseg; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + + atomic_set(&pending_req->pendcnt, nseg); + pending_cons++; + blkif_get(blkif); + + for ( i = 0; i < nseg; i++ ) + { + bh = kmem_cache_alloc(buffer_head_cachep, GFP_KERNEL); + if ( unlikely(bh == NULL) ) + { + __end_block_io_op(pending_req, 0); + continue; + } + + memset(bh, 0, sizeof (struct buffer_head)); + + init_waitqueue_head(&bh->b_wait); + bh->b_size = seg[i].nsec << 9; + bh->b_dev = preq.dev; + bh->b_rdev = preq.dev; + bh->b_rsector = (unsigned long)preq.sector_number; + bh->b_data = (char *)MMAP_VADDR(pending_idx, i) + + (seg[i].buf & ~PAGE_MASK); + bh->b_page = virt_to_page(MMAP_VADDR(pending_idx, i)); + bh->b_end_io = end_block_io_op; + bh->b_private = pending_req; + + bh->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | + (1 << BH_Req) | (1 << BH_Launder); + if ( operation == WRITE ) + bh->b_state |= (1 << BH_JBD) | (1 << BH_Req) | (1 << BH_Uptodate); + + atomic_set(&bh->b_count, 1); + + /* Dispatch a single request. We'll flush it to disc later. */ + generic_make_request(operation, bh); + + preq.sector_number += seg[i].nsec; + } + +#else + + for ( i = 0; i < nseg; i++ ) + { + while ( (bio == NULL) || + (bio_add_page(bio, + virt_to_page(MMAP_VADDR(pending_idx, i)), + seg[i].nsec << 9, + seg[i].buf & ~PAGE_MASK) == 0) ) + { + bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i); + if ( unlikely(bio == NULL) ) + { + for ( i = 0; i < (nbio-1); i++ ) + bio_put(biolist[i]); + fast_flush_area(pending_idx, nseg); + goto bad_descriptor; + } + + bio->bi_bdev = preq.bdev; + bio->bi_private = pending_req; + bio->bi_end_io = end_block_io_op; + bio->bi_sector = preq.sector_number; + } + + preq.sector_number += seg[i].nsec; + } + + if ( (q = bdev_get_queue(bio->bi_bdev)) != plugged_queue ) + { + flush_plugged_queue(); + blk_get_queue(q); + plugged_queue = q; + } + + atomic_set(&pending_req->pendcnt, nbio); + pending_cons++; + blkif_get(blkif); + + for ( i = 0; i < nbio; i++ ) + submit_bio(operation, biolist[i]); + +#endif + + return; + + bad_descriptor: + make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR); +} + + + +/****************************************************************** + * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING + */ + + +static void make_response(blkif_t *blkif, unsigned long id, + unsigned short op, int st) +{ + blkif_response_t *resp; + unsigned long flags; + blkif_back_ring_t *blk_ring = &blkif->blk_ring; + + /* Place on the response ring for the relevant domain. */ + spin_lock_irqsave(&blkif->blk_ring_lock, flags); + resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt); + resp->id = id; + resp->operation = op; + resp->status = st; + wmb(); /* Ensure other side can see the response fields. */ + blk_ring->rsp_prod_pvt++; + RING_PUSH_RESPONSES(blk_ring); + spin_unlock_irqrestore(&blkif->blk_ring_lock, flags); + + /* Kick the relevant domain. */ + notify_via_evtchn(blkif->evtchn); +} + +void blkif_deschedule(blkif_t *blkif) +{ + remove_from_blkdev_list(blkif); +} + +static int __init blkif_init(void) +{ + int i; + + if ( !(xen_start_info.flags & SIF_INITDOMAIN) && + !(xen_start_info.flags & SIF_BLK_BE_DOMAIN) ) + return 0; + + blkif_interface_init(); + + if ( (mmap_vstart = allocate_empty_lowmem_region(MMAP_PAGES)) == 0 ) + BUG(); + + pending_cons = 0; + pending_prod = MAX_PENDING_REQS; + memset(pending_reqs, 0, sizeof(pending_reqs)); + for ( i = 0; i < MAX_PENDING_REQS; i++ ) + pending_ring[i] = i; + + spin_lock_init(&blkio_schedule_list_lock); + INIT_LIST_HEAD(&blkio_schedule_list); + + if ( kernel_thread(blkio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 ) + BUG(); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + buffer_head_cachep = kmem_cache_create( + "buffer_head_cache", sizeof(struct buffer_head), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); +#endif + + blkif_ctrlif_init(); + +#ifdef CONFIG_XEN_BLKDEV_GRANT + memset( pending_grant_handles, BLKBACK_INVALID_HANDLE, MMAP_PAGES ); + printk(KERN_ALERT "Blkif backend is using grant tables.\n"); +#endif + +#ifdef CONFIG_XEN_BLKDEV_TAP_BE + printk(KERN_ALERT "NOTE: Blkif backend is running with tap support on!\n"); +#endif + + return 0; +} + +__initcall(blkif_init); diff --git a/drivers/xen/blkback/common.h b/drivers/xen/blkback/common.h new file mode 100644 index 000000000..a698e01c6 --- /dev/null +++ b/drivers/xen/blkback/common.h @@ -0,0 +1,104 @@ + +#ifndef __BLKIF__BACKEND__COMMON_H__ +#define __BLKIF__BACKEND__COMMON_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define ASSERT(_p) \ + if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ + __LINE__, __FILE__); *(int*)0=0; } +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ + __FILE__ , __LINE__ , ## _a ) +#else +#define ASSERT(_p) ((void)0) +#define DPRINTK(_f, _a...) ((void)0) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +typedef struct rb_root rb_root_t; +typedef struct rb_node rb_node_t; +#else +struct block_device; +#endif + +typedef struct blkif_st { + /* Unique identifier for this interface. */ + domid_t domid; + unsigned int handle; + /* Physical parameters of the comms window. */ + unsigned long shmem_frame; + unsigned int evtchn; + int irq; + /* Comms information. */ + blkif_back_ring_t blk_ring; + /* VBDs attached to this interface. */ + rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs.*/ + spinlock_t vbd_lock; /* Protects VBD mapping. */ + /* Private fields. */ + enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; + /* + * DISCONNECT response is deferred until pending requests are ack'ed. + * We therefore need to store the id from the original request. + */ + u8 disconnect_rspid; +#ifdef CONFIG_XEN_BLKDEV_TAP_BE + /* Is this a blktap frontend */ + unsigned int is_blktap; +#endif + struct blkif_st *hash_next; + struct list_head blkdev_list; + spinlock_t blk_ring_lock; + atomic_t refcnt; + + struct work_struct work; +} blkif_t; + +void blkif_create(blkif_be_create_t *create); +void blkif_destroy(blkif_be_destroy_t *destroy); +void blkif_connect(blkif_be_connect_t *connect); +int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id); +void blkif_disconnect_complete(blkif_t *blkif); +blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle); +#define blkif_get(_b) (atomic_inc(&(_b)->refcnt)) +#define blkif_put(_b) \ + do { \ + if ( atomic_dec_and_test(&(_b)->refcnt) ) \ + blkif_disconnect_complete(_b); \ + } while (0) + +void vbd_create(blkif_be_vbd_create_t *create); +void vbd_destroy(blkif_be_vbd_destroy_t *delete); +int vbd_probe(blkif_t *blkif, vdisk_t *vbd_info, int max_vbds); +void destroy_all_vbds(blkif_t *blkif); + +struct phys_req { + unsigned short dev; + unsigned short nr_sects; + struct block_device *bdev; + blkif_sector_t sector_number; +}; + +int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation); + +void blkif_interface_init(void); +void blkif_ctrlif_init(void); + +void blkif_deschedule(blkif_t *blkif); + +irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs); + +#endif /* __BLKIF__BACKEND__COMMON_H__ */ diff --git a/drivers/xen/blkback/interface.c b/drivers/xen/blkback/interface.c new file mode 100644 index 000000000..46d55d1fd --- /dev/null +++ b/drivers/xen/blkback/interface.c @@ -0,0 +1,249 @@ +/****************************************************************************** + * arch/xen/drivers/blkif/backend/interface.c + * + * Block-device interface management. + * + * Copyright (c) 2004, Keir Fraser + */ + +#include "common.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#endif + +#define BLKIF_HASHSZ 1024 +#define BLKIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(BLKIF_HASHSZ-1)) + +static kmem_cache_t *blkif_cachep; +static blkif_t *blkif_hash[BLKIF_HASHSZ]; + +blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle) +{ + blkif_t *blkif = blkif_hash[BLKIF_HASH(domid, handle)]; + while ( (blkif != NULL) && + ((blkif->domid != domid) || (blkif->handle != handle)) ) + blkif = blkif->hash_next; + return blkif; +} + +static void __blkif_disconnect_complete(void *arg) +{ + blkif_t *blkif = (blkif_t *)arg; + ctrl_msg_t cmsg; + blkif_be_disconnect_t disc; + + /* + * These can't be done in blkif_disconnect() because at that point there + * may be outstanding requests at the disc whose asynchronous responses + * must still be notified to the remote driver. + */ + unbind_evtchn_from_irq(blkif->evtchn); + vfree(blkif->blk_ring.sring); + + /* Construct the deferred response message. */ + cmsg.type = CMSG_BLKIF_BE; + cmsg.subtype = CMSG_BLKIF_BE_DISCONNECT; + cmsg.id = blkif->disconnect_rspid; + cmsg.length = sizeof(blkif_be_disconnect_t); + disc.domid = blkif->domid; + disc.blkif_handle = blkif->handle; + disc.status = BLKIF_BE_STATUS_OKAY; + memcpy(cmsg.msg, &disc, sizeof(disc)); + + /* + * Make sure message is constructed /before/ status change, because + * after the status change the 'blkif' structure could be deallocated at + * any time. Also make sure we send the response /after/ status change, + * as otherwise a subsequent CONNECT request could spuriously fail if + * another CPU doesn't see the status change yet. + */ + mb(); + if ( blkif->status != DISCONNECTING ) + BUG(); + blkif->status = DISCONNECTED; + mb(); + + /* Send the successful response. */ + ctrl_if_send_response(&cmsg); +} + +void blkif_disconnect_complete(blkif_t *blkif) +{ + INIT_WORK(&blkif->work, __blkif_disconnect_complete, (void *)blkif); + schedule_work(&blkif->work); +} + +void blkif_create(blkif_be_create_t *create) +{ + domid_t domid = create->domid; + unsigned int handle = create->blkif_handle; + blkif_t **pblkif, *blkif; + + if ( (blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL)) == NULL ) + { + DPRINTK("Could not create blkif: out of memory\n"); + create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY; + return; + } + + memset(blkif, 0, sizeof(*blkif)); + blkif->domid = domid; + blkif->handle = handle; + blkif->status = DISCONNECTED; + spin_lock_init(&blkif->vbd_lock); + spin_lock_init(&blkif->blk_ring_lock); + atomic_set(&blkif->refcnt, 0); + + pblkif = &blkif_hash[BLKIF_HASH(domid, handle)]; + while ( *pblkif != NULL ) + { + if ( ((*pblkif)->domid == domid) && ((*pblkif)->handle == handle) ) + { + DPRINTK("Could not create blkif: already exists\n"); + create->status = BLKIF_BE_STATUS_INTERFACE_EXISTS; + kmem_cache_free(blkif_cachep, blkif); + return; + } + pblkif = &(*pblkif)->hash_next; + } + + blkif->hash_next = *pblkif; + *pblkif = blkif; + + DPRINTK("Successfully created blkif\n"); + create->status = BLKIF_BE_STATUS_OKAY; +} + +void blkif_destroy(blkif_be_destroy_t *destroy) +{ + domid_t domid = destroy->domid; + unsigned int handle = destroy->blkif_handle; + blkif_t **pblkif, *blkif; + + pblkif = &blkif_hash[BLKIF_HASH(domid, handle)]; + while ( (blkif = *pblkif) != NULL ) + { + if ( (blkif->domid == domid) && (blkif->handle == handle) ) + { + if ( blkif->status != DISCONNECTED ) + goto still_connected; + goto destroy; + } + pblkif = &blkif->hash_next; + } + + destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND; + return; + + still_connected: + destroy->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED; + return; + + destroy: + *pblkif = blkif->hash_next; + destroy_all_vbds(blkif); + kmem_cache_free(blkif_cachep, blkif); + destroy->status = BLKIF_BE_STATUS_OKAY; +} + +void blkif_connect(blkif_be_connect_t *connect) +{ + domid_t domid = connect->domid; + unsigned int handle = connect->blkif_handle; + unsigned int evtchn = connect->evtchn; + unsigned long shmem_frame = connect->shmem_frame; + struct vm_struct *vma; + pgprot_t prot; + int error; + blkif_t *blkif; + blkif_sring_t *sring; + + blkif = blkif_find_by_handle(domid, handle); + if ( unlikely(blkif == NULL) ) + { + DPRINTK("blkif_connect attempted for non-existent blkif (%u,%u)\n", + connect->domid, connect->blkif_handle); + connect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND; + return; + } + + if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL ) + { + connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY; + return; + } + + prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED); + error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr), + shmem_frame<status = BLKIF_BE_STATUS_OUT_OF_MEMORY; + else if ( error == -EFAULT ) + connect->status = BLKIF_BE_STATUS_MAPPING_ERROR; + else + connect->status = BLKIF_BE_STATUS_ERROR; + vfree(vma->addr); + return; + } + + if ( blkif->status != DISCONNECTED ) + { + connect->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED; + vfree(vma->addr); + return; + } + sring = (blkif_sring_t *)vma->addr; + SHARED_RING_INIT(sring); + BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE); + + blkif->evtchn = evtchn; + blkif->irq = bind_evtchn_to_irq(evtchn); + blkif->shmem_frame = shmem_frame; + blkif->status = CONNECTED; + blkif_get(blkif); + + request_irq(blkif->irq, blkif_be_int, 0, "blkif-backend", blkif); + + connect->status = BLKIF_BE_STATUS_OKAY; +} + +int blkif_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id) +{ + domid_t domid = disconnect->domid; + unsigned int handle = disconnect->blkif_handle; + blkif_t *blkif; + + blkif = blkif_find_by_handle(domid, handle); + if ( unlikely(blkif == NULL) ) + { + DPRINTK("blkif_disconnect attempted for non-existent blkif" + " (%u,%u)\n", disconnect->domid, disconnect->blkif_handle); + disconnect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND; + return 1; /* Caller will send response error message. */ + } + + if ( blkif->status == CONNECTED ) + { + blkif->status = DISCONNECTING; + blkif->disconnect_rspid = rsp_id; + wmb(); /* Let other CPUs see the status change. */ + free_irq(blkif->irq, blkif); + blkif_deschedule(blkif); + blkif_put(blkif); + return 0; /* Caller should not send response message. */ + } + + disconnect->status = BLKIF_BE_STATUS_OKAY; + return 1; +} + +void __init blkif_interface_init(void) +{ + blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t), + 0, 0, NULL, NULL); + memset(blkif_hash, 0, sizeof(blkif_hash)); +} diff --git a/drivers/xen/blkback/vbd.c b/drivers/xen/blkback/vbd.c new file mode 100644 index 000000000..f5ee589ee --- /dev/null +++ b/drivers/xen/blkback/vbd.c @@ -0,0 +1,287 @@ +/****************************************************************************** + * blkback/vbd.c + * + * Routines for managing virtual block devices (VBDs). + * + * NOTE: vbd_lock protects updates to the rb_tree against concurrent lookups + * in vbd_translate. All other lookups are implicitly protected because the + * only caller (the control message dispatch routine) serializes the calls. + * + * Copyright (c) 2003-2005, Keir Fraser & Steve Hand + */ + +#include "common.h" + +struct vbd { + blkif_vdev_t vdevice; /* what the domain refers to this vbd as */ + unsigned char readonly; /* Non-zero -> read-only */ + unsigned char type; /* VDISK_TYPE_xxx */ + blkif_pdev_t pdevice; /* phys device that this vbd maps to */ + struct block_device *bdev; + rb_node_t rb; /* for linking into R-B tree lookup struct */ +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static inline dev_t vbd_map_devnum(blkif_pdev_t cookie) +{ return MKDEV(cookie>>8, cookie&0xff); } +#define vbd_sz(_v) ((_v)->bdev->bd_part ? \ + (_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity) +#define bdev_put(_b) blkdev_put(_b) +#else +#define vbd_sz(_v) (blk_size[MAJOR((_v)->pdevice)][MINOR((_v)->pdevice)]*2) +#define bdev_put(_b) ((void)0) +#endif + +void vbd_create(blkif_be_vbd_create_t *create) +{ + struct vbd *vbd; + rb_node_t **rb_p, *rb_parent = NULL; + blkif_t *blkif; + blkif_vdev_t vdevice = create->vdevice; + + blkif = blkif_find_by_handle(create->domid, create->blkif_handle); + if ( unlikely(blkif == NULL) ) + { + DPRINTK("vbd_create attempted for non-existent blkif (%u,%u)\n", + create->domid, create->blkif_handle); + create->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND; + return; + } + + rb_p = &blkif->vbd_rb.rb_node; + while ( *rb_p != NULL ) + { + rb_parent = *rb_p; + vbd = rb_entry(rb_parent, struct vbd, rb); + if ( vdevice < vbd->vdevice ) + { + rb_p = &rb_parent->rb_left; + } + else if ( vdevice > vbd->vdevice ) + { + rb_p = &rb_parent->rb_right; + } + else + { + DPRINTK("vbd_create attempted for already existing vbd\n"); + create->status = BLKIF_BE_STATUS_VBD_EXISTS; + return; + } + } + + if ( unlikely((vbd = kmalloc(sizeof(struct vbd), GFP_KERNEL)) == NULL) ) + { + DPRINTK("vbd_create: out of memory\n"); + create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY; + return; + } + + vbd->vdevice = vdevice; + vbd->readonly = create->readonly; + vbd->type = VDISK_TYPE_DISK | VDISK_FLAG_VIRT; + + /* Mask to 16-bit for compatibility with old tools */ + vbd->pdevice = create->pdevice & 0xffff; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + vbd->bdev = open_by_devnum( + vbd_map_devnum(vbd->pdevice), + vbd->readonly ? FMODE_READ : FMODE_WRITE); + if ( IS_ERR(vbd->bdev) ) + { + DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice); + create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND; + return; + } + + if ( (vbd->bdev->bd_disk == NULL) ) + { + DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice); + create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND; + bdev_put(vbd->bdev); + return; + } +#else + if ( (blk_size[MAJOR(vbd->pdevice)] == NULL) || (vbd_sz(vbd) == 0) ) + { + DPRINTK("vbd_creat: device %08x doesn't exist.\n", vbd->pdevice); + create->status = BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND; + return; + } +#endif + + spin_lock(&blkif->vbd_lock); + rb_link_node(&vbd->rb, rb_parent, rb_p); + rb_insert_color(&vbd->rb, &blkif->vbd_rb); + spin_unlock(&blkif->vbd_lock); + + DPRINTK("Successful creation of vdev=%04x (dom=%u)\n", + vdevice, create->domid); + create->status = BLKIF_BE_STATUS_OKAY; +} + + +void vbd_destroy(blkif_be_vbd_destroy_t *destroy) +{ + blkif_t *blkif; + struct vbd *vbd; + rb_node_t *rb; + blkif_vdev_t vdevice = destroy->vdevice; + + blkif = blkif_find_by_handle(destroy->domid, destroy->blkif_handle); + if ( unlikely(blkif == NULL) ) + { + DPRINTK("vbd_destroy attempted for non-existent blkif (%u,%u)\n", + destroy->domid, destroy->blkif_handle); + destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND; + return; + } + + rb = blkif->vbd_rb.rb_node; + while ( rb != NULL ) + { + vbd = rb_entry(rb, struct vbd, rb); + if ( vdevice < vbd->vdevice ) + rb = rb->rb_left; + else if ( vdevice > vbd->vdevice ) + rb = rb->rb_right; + else + goto found; + } + + destroy->status = BLKIF_BE_STATUS_VBD_NOT_FOUND; + return; + + found: + spin_lock(&blkif->vbd_lock); + rb_erase(rb, &blkif->vbd_rb); + spin_unlock(&blkif->vbd_lock); + bdev_put(vbd->bdev); + kfree(vbd); +} + + +void destroy_all_vbds(blkif_t *blkif) +{ + struct vbd *vbd; + rb_node_t *rb; + + spin_lock(&blkif->vbd_lock); + + while ( (rb = blkif->vbd_rb.rb_node) != NULL ) + { + vbd = rb_entry(rb, struct vbd, rb); + rb_erase(rb, &blkif->vbd_rb); + spin_unlock(&blkif->vbd_lock); + bdev_put(vbd->bdev); + kfree(vbd); + spin_lock(&blkif->vbd_lock); + } + + spin_unlock(&blkif->vbd_lock); +} + + +static void vbd_probe_single( + blkif_t *blkif, vdisk_t *vbd_info, struct vbd *vbd) +{ + vbd_info->device = vbd->vdevice; + vbd_info->info = vbd->type | (vbd->readonly ? VDISK_FLAG_RO : 0); + vbd_info->capacity = vbd_sz(vbd); +} + + +int vbd_probe(blkif_t *blkif, vdisk_t *vbd_info, int max_vbds) +{ + int rc = 0, nr_vbds = 0; + rb_node_t *rb; + + spin_lock(&blkif->vbd_lock); + + if ( (rb = blkif->vbd_rb.rb_node) == NULL ) + goto out; + + new_subtree: + /* STEP 1. Find least node (it'll be left-most). */ + while ( rb->rb_left != NULL ) + rb = rb->rb_left; + + for ( ; ; ) + { + /* STEP 2. Dealt with left subtree. Now process current node. */ + vbd_probe_single(blkif, &vbd_info[nr_vbds], + rb_entry(rb, struct vbd, rb)); + if ( ++nr_vbds == max_vbds ) + goto out; + + /* STEP 3. Process right subtree, if any. */ + if ( rb->rb_right != NULL ) + { + rb = rb->rb_right; + goto new_subtree; + } + + /* STEP 4. Done both subtrees. Head back through ancesstors. */ + for ( ; ; ) + { + /* We're done when we get back to the root node. */ + if ( rb->rb_parent == NULL ) + goto out; + /* If we are left of parent, then parent is next to process. */ + if ( rb->rb_parent->rb_left == rb ) + break; + /* If we are right of parent, then we climb to grandparent. */ + rb = rb->rb_parent; + } + + rb = rb->rb_parent; + } + + out: + spin_unlock(&blkif->vbd_lock); + return (rc == 0) ? nr_vbds : rc; +} + + +int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation) +{ + struct vbd *vbd; + rb_node_t *rb; + int rc = -EACCES; + + /* Take the vbd_lock because another thread could be updating the tree. */ + spin_lock(&blkif->vbd_lock); + + rb = blkif->vbd_rb.rb_node; + while ( rb != NULL ) + { + vbd = rb_entry(rb, struct vbd, rb); + if ( req->dev < vbd->vdevice ) + rb = rb->rb_left; + else if ( req->dev > vbd->vdevice ) + rb = rb->rb_right; + else + goto found; + } + + DPRINTK("vbd_translate; domain %u attempted to access " + "non-existent VBD.\n", blkif->domid); + rc = -ENODEV; + goto out; + + found: + + if ( (operation == WRITE) && vbd->readonly ) + goto out; + + if ( unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)) ) + goto out; + + req->dev = vbd->pdevice; + req->bdev = vbd->bdev; + rc = 0; + + out: + spin_unlock(&blkif->vbd_lock); + return rc; +} diff --git a/drivers/xen/blkfront/Kconfig b/drivers/xen/blkfront/Kconfig new file mode 100644 index 000000000..edde837fa --- /dev/null +++ b/drivers/xen/blkfront/Kconfig @@ -0,0 +1,6 @@ + +config XENBLOCK + tristate "Block device driver" + depends on ARCH_XEN + help + Block device driver for Xen diff --git a/drivers/xen/blkfront/Makefile b/drivers/xen/blkfront/Makefile new file mode 100644 index 000000000..5d1707dd7 --- /dev/null +++ b/drivers/xen/blkfront/Makefile @@ -0,0 +1,3 @@ + +obj-y := blkfront.o vbd.o + diff --git a/drivers/xen/blkfront/blkfront.c b/drivers/xen/blkfront/blkfront.c new file mode 100644 index 000000000..311b8398e --- /dev/null +++ b/drivers/xen/blkfront/blkfront.c @@ -0,0 +1,1480 @@ +/****************************************************************************** + * blkfront.c + * + * XenLinux virtual block-device driver. + * + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + * Modifications by Mark A. Williamson are (c) Intel Research Cambridge + * Copyright (c) 2004, Christian Limpach + * Copyright (c) 2004, Andrew Warfield + * Copyright (c) 2005, Christopher Clark + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#if 1 +#define ASSERT(_p) \ + if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ + __LINE__, __FILE__); *(int*)0=0; } +#else +#define ASSERT(_p) +#endif + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#include "block.h" +#else +#include "common.h" +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_XEN_BLKDEV_GRANT +#include +#include +#endif + +typedef unsigned char byte; /* from linux/ide.h */ + +/* Control whether runtime update of vbds is enabled. */ +#define ENABLE_VBD_UPDATE 1 + +#if ENABLE_VBD_UPDATE +static void vbd_update(void); +#else +static void vbd_update(void){}; +#endif + +#define BLKIF_STATE_CLOSED 0 +#define BLKIF_STATE_DISCONNECTED 1 +#define BLKIF_STATE_CONNECTED 2 + +#define WPRINTK(fmt, args...) printk(KERN_WARNING "xen_blk: " fmt, ##args) + +static int blkif_handle = 0; +static unsigned int blkif_state = BLKIF_STATE_CLOSED; +static unsigned int blkif_evtchn = 0; +static unsigned int blkif_irq = 0; + +static int blkif_control_rsp_valid; +static blkif_response_t blkif_control_rsp; + +static blkif_front_ring_t blk_ring; + +#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE) + +#ifdef CONFIG_XEN_BLKDEV_GRANT +static domid_t rdomid = 0; +static grant_ref_t gref_head, gref_terminal; +#define MAXIMUM_OUTSTANDING_BLOCK_REQS \ + (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLKIF_RING_SIZE) +#define GRANTREF_INVALID (1<<15) +#endif + +static struct blk_shadow { + blkif_request_t req; + unsigned long request; + unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST]; +} blk_shadow[BLK_RING_SIZE]; +unsigned long blk_shadow_free; + +static int recovery = 0; /* Recovery in progress: protected by blkif_io_lock */ + +static void kick_pending_request_queues(void); + +int __init xlblk_init(void); + +static void blkif_completion(struct blk_shadow *s); + +static inline int GET_ID_FROM_FREELIST(void) +{ + unsigned long free = blk_shadow_free; + BUG_ON(free > BLK_RING_SIZE); + blk_shadow_free = blk_shadow[free].req.id; + blk_shadow[free].req.id = 0x0fffffee; /* debug */ + return free; +} + +static inline void ADD_ID_TO_FREELIST(unsigned long id) +{ + blk_shadow[id].req.id = blk_shadow_free; + blk_shadow[id].request = 0; + blk_shadow_free = id; +} + + +/************************ COMMON CODE (inlined) ************************/ + +/* Kernel-specific definitions used in the common code */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#define DISABLE_SCATTERGATHER() +#else +static int sg_operation = -1; +#define DISABLE_SCATTERGATHER() (sg_operation = -1) +#endif + +static inline void pickle_request(struct blk_shadow *s, blkif_request_t *r) +{ +#ifndef CONFIG_XEN_BLKDEV_GRANT + int i; +#endif + + s->req = *r; + +#ifndef CONFIG_XEN_BLKDEV_GRANT + for ( i = 0; i < r->nr_segments; i++ ) + s->req.frame_and_sects[i] = machine_to_phys(r->frame_and_sects[i]); +#endif +} + +static inline void unpickle_request(blkif_request_t *r, struct blk_shadow *s) +{ +#ifndef CONFIG_XEN_BLKDEV_GRANT + int i; +#endif + + *r = s->req; + +#ifndef CONFIG_XEN_BLKDEV_GRANT + for ( i = 0; i < s->req.nr_segments; i++ ) + r->frame_and_sects[i] = phys_to_machine(s->req.frame_and_sects[i]); +#endif +} + + +static inline void flush_requests(void) +{ + DISABLE_SCATTERGATHER(); + RING_PUSH_REQUESTS(&blk_ring); + notify_via_evtchn(blkif_evtchn); +} + + +/************************** KERNEL VERSION 2.6 **************************/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + +module_init(xlblk_init); + +#if ENABLE_VBD_UPDATE +static void update_vbds_task(void *unused) +{ + xlvbd_update_vbds(); +} + +static void vbd_update(void) +{ + static DECLARE_WORK(update_tq, update_vbds_task, NULL); + schedule_work(&update_tq); +} +#endif /* ENABLE_VBD_UPDATE */ + +static void kick_pending_request_queues(void) +{ + if ( (xlbd_blk_queue != NULL) && + test_bit(QUEUE_FLAG_STOPPED, &xlbd_blk_queue->queue_flags) ) + { + blk_start_queue(xlbd_blk_queue); + /* XXXcl call to request_fn should not be needed but + * we get stuck without... needs investigating + */ + xlbd_blk_queue->request_fn(xlbd_blk_queue); + } +} + + +int blkif_open(struct inode *inode, struct file *filep) +{ + struct gendisk *gd = inode->i_bdev->bd_disk; + struct xlbd_disk_info *di = (struct xlbd_disk_info *)gd->private_data; + + /* Update of usage count is protected by per-device semaphore. */ + di->mi->usage++; + + return 0; +} + + +int blkif_release(struct inode *inode, struct file *filep) +{ + struct gendisk *gd = inode->i_bdev->bd_disk; + struct xlbd_disk_info *di = (struct xlbd_disk_info *)gd->private_data; + + /* + * When usage drops to zero it may allow more VBD updates to occur. + * Update of usage count is protected by a per-device semaphore. + */ + if ( --di->mi->usage == 0 ) + vbd_update(); + + return 0; +} + + +int blkif_ioctl(struct inode *inode, struct file *filep, + unsigned command, unsigned long argument) +{ + int i; + + DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n", + command, (long)argument, inode->i_rdev); + + switch ( command ) + { + case HDIO_GETGEO: + /* return ENOSYS to use defaults */ + return -ENOSYS; + + case CDROMMULTISESSION: + DPRINTK("FIXME: support multisession CDs later\n"); + for ( i = 0; i < sizeof(struct cdrom_multisession); i++ ) + if ( put_user(0, (byte *)(argument + i)) ) return -EFAULT; + return 0; + + default: + printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n", + command); + return -ENOSYS; + } + + return 0; +} + + +/* + * blkif_queue_request + * + * request block io + * + * id: for guest use only. + * operation: BLKIF_OP_{READ,WRITE,PROBE} + * buffer: buffer to read/write into. this should be a + * virtual address in the guest os. + */ +static int blkif_queue_request(struct request *req) +{ + struct xlbd_disk_info *di = + (struct xlbd_disk_info *)req->rq_disk->private_data; + unsigned long buffer_ma; + blkif_request_t *ring_req; + struct bio *bio; + struct bio_vec *bvec; + int idx; + unsigned long id; + unsigned int fsect, lsect; +#ifdef CONFIG_XEN_BLKDEV_GRANT + int ref; +#endif + + if ( unlikely(blkif_state != BLKIF_STATE_CONNECTED) ) + return 1; + + /* Fill out a communications ring structure. */ + ring_req = RING_GET_REQUEST(&blk_ring, blk_ring.req_prod_pvt); + id = GET_ID_FROM_FREELIST(); + blk_shadow[id].request = (unsigned long)req; + + ring_req->id = id; + ring_req->operation = rq_data_dir(req) ? BLKIF_OP_WRITE : + BLKIF_OP_READ; + ring_req->sector_number = (blkif_sector_t)req->sector; + ring_req->device = di->xd_device; + + ring_req->nr_segments = 0; + rq_for_each_bio(bio, req) + { + bio_for_each_segment(bvec, bio, idx) + { + if ( ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST ) + BUG(); + buffer_ma = page_to_phys(bvec->bv_page); + fsect = bvec->bv_offset >> 9; + lsect = fsect + (bvec->bv_len >> 9) - 1; +#ifdef CONFIG_XEN_BLKDEV_GRANT + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head, gref_terminal); + ASSERT( ref != -ENOSPC ); + + gnttab_grant_foreign_access_ref( + ref, + rdomid, + buffer_ma >> PAGE_SHIFT, + rq_data_dir(req) ); + + blk_shadow[id].frame[ring_req->nr_segments] = + buffer_ma >> PAGE_SHIFT; + + ring_req->frame_and_sects[ring_req->nr_segments++] = + (((u32) ref) << 16) | (fsect << 3) | lsect; + +#else + ring_req->frame_and_sects[ring_req->nr_segments++] = + buffer_ma | (fsect << 3) | lsect; +#endif + } + } + + blk_ring.req_prod_pvt++; + + /* Keep a private copy so we can reissue requests when recovering. */ + pickle_request(&blk_shadow[id], ring_req); + + return 0; +} + + +/* + * do_blkif_request + * read a block; request is in a request queue + */ +void do_blkif_request(request_queue_t *rq) +{ + struct request *req; + int queued; + + DPRINTK("Entered do_blkif_request\n"); + + queued = 0; + + while ( (req = elv_next_request(rq)) != NULL ) + { + if ( !blk_fs_request(req) ) + { + end_request(req, 0); + continue; + } + + if ( RING_FULL(&blk_ring) ) + { + blk_stop_queue(rq); + break; + } + + DPRINTK("do_blk_req %p: cmd %p, sec %lx, (%u/%li) buffer:%p [%s]\n", + req, req->cmd, req->sector, req->current_nr_sectors, + req->nr_sectors, req->buffer, + rq_data_dir(req) ? "write" : "read"); + + blkdev_dequeue_request(req); + if ( blkif_queue_request(req) ) + { + blk_stop_queue(rq); + break; + } + + queued++; + } + + if ( queued != 0 ) + flush_requests(); +} + + +static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) +{ + struct request *req; + blkif_response_t *bret; + RING_IDX i, rp; + unsigned long flags; + + spin_lock_irqsave(&blkif_io_lock, flags); + + if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) || + unlikely(recovery) ) + { + spin_unlock_irqrestore(&blkif_io_lock, flags); + return IRQ_HANDLED; + } + + rp = blk_ring.sring->rsp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + + for ( i = blk_ring.rsp_cons; i != rp; i++ ) + { + unsigned long id; + + bret = RING_GET_RESPONSE(&blk_ring, i); + id = bret->id; + req = (struct request *)blk_shadow[id].request; + + blkif_completion(&blk_shadow[id]); + + ADD_ID_TO_FREELIST(id); + + switch ( bret->operation ) + { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + if ( unlikely(bret->status != BLKIF_RSP_OKAY) ) + DPRINTK("Bad return from blkdev data request: %x\n", + bret->status); + + if ( unlikely(end_that_request_first + (req, + (bret->status == BLKIF_RSP_OKAY), + req->hard_nr_sectors)) ) + BUG(); + end_that_request_last(req); + + break; + case BLKIF_OP_PROBE: + memcpy(&blkif_control_rsp, bret, sizeof(*bret)); + blkif_control_rsp_valid = 1; + break; + default: + BUG(); + } + } + + blk_ring.rsp_cons = i; + + kick_pending_request_queues(); + + spin_unlock_irqrestore(&blkif_io_lock, flags); + + return IRQ_HANDLED; +} + +#else +/************************** KERNEL VERSION 2.4 **************************/ + +static kdev_t sg_dev; +static unsigned long sg_next_sect; + +/* + * Request queues with outstanding work, but ring is currently full. + * We need no special lock here, as we always access this with the + * blkif_io_lock held. We only need a small maximum list. + */ +#define MAX_PENDING 8 +static request_queue_t *pending_queues[MAX_PENDING]; +static int nr_pending; + + +#define blkif_io_lock io_request_lock + +/*============================================================================*/ +#if ENABLE_VBD_UPDATE + +/* + * blkif_update_int/update-vbds_task - handle VBD update events. + * Schedule a task for keventd to run, which will update the VBDs and perform + * the corresponding updates to our view of VBD state. + */ +static void update_vbds_task(void *unused) +{ + xlvbd_update_vbds(); +} + +static void vbd_update(void) +{ + static struct tq_struct update_tq; + update_tq.routine = update_vbds_task; + schedule_task(&update_tq); +} + +#endif /* ENABLE_VBD_UPDATE */ +/*============================================================================*/ + +static void kick_pending_request_queues(void) +{ + /* We kick pending request queues if the ring is reasonably empty. */ + if ( (nr_pending != 0) && + (RING_PENDING_REQUESTS(&blk_ring) < (BLK_RING_SIZE >> 1)) ) + { + /* Attempt to drain the queue, but bail if the ring becomes full. */ + while ( (nr_pending != 0) && !RING_FULL(&blk_ring) ) + do_blkif_request(pending_queues[--nr_pending]); + } +} + +int blkif_open(struct inode *inode, struct file *filep) +{ + short xldev = inode->i_rdev; + struct gendisk *gd = get_gendisk(xldev); + xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev); + short minor = MINOR(xldev); + + if ( gd->part[minor].nr_sects == 0 ) + { + /* + * Device either doesn't exist, or has zero capacity; we use a few + * cheesy heuristics to return the relevant error code + */ + if ( (gd->sizes[minor >> gd->minor_shift] != 0) || + ((minor & (gd->max_p - 1)) != 0) ) + { + /* + * We have a real device, but no such partition, or we just have a + * partition number so guess this is the problem. + */ + return -ENXIO; /* no such device or address */ + } + else if ( gd->flags[minor >> gd->minor_shift] & GENHD_FL_REMOVABLE ) + { + /* This is a removable device => assume that media is missing. */ + return -ENOMEDIUM; /* media not present (this is a guess) */ + } + else + { + /* Just go for the general 'no such device' error. */ + return -ENODEV; /* no such device */ + } + } + + /* Update of usage count is protected by per-device semaphore. */ + disk->usage++; + + return 0; +} + + +int blkif_release(struct inode *inode, struct file *filep) +{ + xl_disk_t *disk = xldev_to_xldisk(inode->i_rdev); + + /* + * When usage drops to zero it may allow more VBD updates to occur. + * Update of usage count is protected by a per-device semaphore. + */ + if ( --disk->usage == 0 ) { + vbd_update(); + } + + return 0; +} + + +int blkif_ioctl(struct inode *inode, struct file *filep, + unsigned command, unsigned long argument) +{ + kdev_t dev = inode->i_rdev; + struct hd_geometry *geo = (struct hd_geometry *)argument; + struct gendisk *gd; + struct hd_struct *part; + int i; + unsigned short cylinders; + byte heads, sectors; + + /* NB. No need to check permissions. That is done for us. */ + + DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n", + command, (long) argument, dev); + + gd = get_gendisk(dev); + part = &gd->part[MINOR(dev)]; + + switch ( command ) + { + case BLKGETSIZE: + DPRINTK_IOCTL(" BLKGETSIZE: %x %lx\n", BLKGETSIZE, part->nr_sects); + return put_user(part->nr_sects, (unsigned long *) argument); + + case BLKGETSIZE64: + DPRINTK_IOCTL(" BLKGETSIZE64: %x %llx\n", BLKGETSIZE64, + (u64)part->nr_sects * 512); + return put_user((u64)part->nr_sects * 512, (u64 *) argument); + + case BLKRRPART: /* re-read partition table */ + DPRINTK_IOCTL(" BLKRRPART: %x\n", BLKRRPART); + return blkif_revalidate(dev); + + case BLKSSZGET: + return hardsect_size[MAJOR(dev)][MINOR(dev)]; + + case BLKBSZGET: /* get block size */ + DPRINTK_IOCTL(" BLKBSZGET: %x\n", BLKBSZGET); + break; + + case BLKBSZSET: /* set block size */ + DPRINTK_IOCTL(" BLKBSZSET: %x\n", BLKBSZSET); + break; + + case BLKRASET: /* set read-ahead */ + DPRINTK_IOCTL(" BLKRASET: %x\n", BLKRASET); + break; + + case BLKRAGET: /* get read-ahead */ + DPRINTK_IOCTL(" BLKRAFET: %x\n", BLKRAGET); + break; + + case HDIO_GETGEO: + DPRINTK_IOCTL(" HDIO_GETGEO: %x\n", HDIO_GETGEO); + if (!argument) return -EINVAL; + + /* We don't have real geometry info, but let's at least return + values consistent with the size of the device */ + + heads = 0xff; + sectors = 0x3f; + cylinders = part->nr_sects / (heads * sectors); + + if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; + if (put_user(heads, (byte *)&geo->heads)) return -EFAULT; + if (put_user(sectors, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(cylinders, (unsigned short *)&geo->cylinders)) return -EFAULT; + + return 0; + + case HDIO_GETGEO_BIG: + DPRINTK_IOCTL(" HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG); + if (!argument) return -EINVAL; + + /* We don't have real geometry info, but let's at least return + values consistent with the size of the device */ + + heads = 0xff; + sectors = 0x3f; + cylinders = part->nr_sects / (heads * sectors); + + if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; + if (put_user(heads, (byte *)&geo->heads)) return -EFAULT; + if (put_user(sectors, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(cylinders, (unsigned int *) &geo->cylinders)) return -EFAULT; + + return 0; + + case CDROMMULTISESSION: + DPRINTK("FIXME: support multisession CDs later\n"); + for ( i = 0; i < sizeof(struct cdrom_multisession); i++ ) + if ( put_user(0, (byte *)(argument + i)) ) return -EFAULT; + return 0; + + case SCSI_IOCTL_GET_BUS_NUMBER: + DPRINTK("FIXME: SCSI_IOCTL_GET_BUS_NUMBER ioctl in XL blkif"); + return -ENOSYS; + + default: + printk(KERN_ALERT "ioctl %08x not supported by XL blkif\n", command); + return -ENOSYS; + } + + return 0; +} + + + +/* check media change: should probably do something here in some cases :-) */ +int blkif_check(kdev_t dev) +{ + DPRINTK("blkif_check\n"); + return 0; +} + +int blkif_revalidate(kdev_t dev) +{ + struct block_device *bd; + struct gendisk *gd; + xl_disk_t *disk; + unsigned long capacity; + int i, rc = 0; + + if ( (bd = bdget(dev)) == NULL ) + return -EINVAL; + + /* + * Update of partition info, and check of usage count, is protected + * by the per-block-device semaphore. + */ + down(&bd->bd_sem); + + if ( ((gd = get_gendisk(dev)) == NULL) || + ((disk = xldev_to_xldisk(dev)) == NULL) || + ((capacity = gd->part[MINOR(dev)].nr_sects) == 0) ) + { + rc = -EINVAL; + goto out; + } + + if ( disk->usage > 1 ) + { + rc = -EBUSY; + goto out; + } + + /* Only reread partition table if VBDs aren't mapped to partitions. */ + if ( !(gd->flags[MINOR(dev) >> gd->minor_shift] & GENHD_FL_VIRT_PARTNS) ) + { + for ( i = gd->max_p - 1; i >= 0; i-- ) + { + invalidate_device(dev+i, 1); + gd->part[MINOR(dev+i)].start_sect = 0; + gd->part[MINOR(dev+i)].nr_sects = 0; + gd->sizes[MINOR(dev+i)] = 0; + } + + grok_partitions(gd, MINOR(dev)>>gd->minor_shift, gd->max_p, capacity); + } + + out: + up(&bd->bd_sem); + bdput(bd); + return rc; +} + + +/* + * blkif_queue_request + * + * request block io + * + * id: for guest use only. + * operation: BLKIF_OP_{READ,WRITE,PROBE} + * buffer: buffer to read/write into. this should be a + * virtual address in the guest os. + */ +static int blkif_queue_request(unsigned long id, + int operation, + char * buffer, + unsigned long sector_number, + unsigned short nr_sectors, + kdev_t device) +{ + unsigned long buffer_ma = virt_to_bus(buffer); + unsigned long xid; + struct gendisk *gd; + blkif_request_t *req; + struct buffer_head *bh; + unsigned int fsect, lsect; +#ifdef CONFIG_XEN_BLKDEV_GRANT + int ref; +#endif + + fsect = (buffer_ma & ~PAGE_MASK) >> 9; + lsect = fsect + nr_sectors - 1; + + /* Buffer must be sector-aligned. Extent mustn't cross a page boundary. */ + if ( unlikely((buffer_ma & ((1<<9)-1)) != 0) ) + BUG(); + if ( lsect > 7 ) + BUG(); + + buffer_ma &= PAGE_MASK; + + if ( unlikely(blkif_state != BLKIF_STATE_CONNECTED) ) + return 1; + + switch ( operation ) + { + + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + gd = get_gendisk(device); + + /* + * Update the sector_number we'll pass down as appropriate; note that + * we could sanity check that resulting sector will be in this + * partition, but this will happen in driver backend anyhow. + */ + sector_number += gd->part[MINOR(device)].start_sect; + + /* + * If this unit doesn't consist of virtual partitions then we clear + * the partn bits from the device number. + */ + if ( !(gd->flags[MINOR(device)>>gd->minor_shift] & + GENHD_FL_VIRT_PARTNS) ) + device &= ~(gd->max_p - 1); + + if ( (sg_operation == operation) && + (sg_dev == device) && + (sg_next_sect == sector_number) ) + { + req = RING_GET_REQUEST(&blk_ring, + blk_ring.req_prod_pvt - 1); + bh = (struct buffer_head *)id; + + bh->b_reqnext = (struct buffer_head *)blk_shadow[req->id].request; + blk_shadow[req->id].request = (unsigned long)id; + +#ifdef CONFIG_XEN_BLKDEV_GRANT + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head, gref_terminal); + ASSERT( ref != -ENOSPC ); + + gnttab_grant_foreign_access_ref( + ref, + rdomid, + buffer_ma >> PAGE_SHIFT, + ( operation == BLKIF_OP_WRITE ? 1 : 0 ) ); + + blk_shadow[id].frame[req->nr_segments] = + buffer_ma >> PAGE_SHIFT; + + req->frame_and_sects[req->nr_segments] = + (((u32) ref ) << 16) | (fsect << 3) | lsect; +#else + req->frame_and_sects[req->nr_segments] = + buffer_ma | (fsect << 3) | lsect; +#endif + if ( ++req->nr_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST ) + sg_next_sect += nr_sectors; + else + DISABLE_SCATTERGATHER(); + + /* Update the copy of the request in the recovery ring. */ + pickle_request(&blk_shadow[req->id], req ); + + return 0; + } + else if ( RING_FULL(&blk_ring) ) + { + return 1; + } + else + { + sg_operation = operation; + sg_dev = device; + sg_next_sect = sector_number + nr_sectors; + } + break; + + default: + panic("unknown op %d\n", operation); + } + + /* Fill out a communications ring structure. */ + req = RING_GET_REQUEST(&blk_ring, blk_ring.req_prod_pvt); + + xid = GET_ID_FROM_FREELIST(); + blk_shadow[xid].request = (unsigned long)id; + + req->id = xid; + req->operation = operation; + req->sector_number = (blkif_sector_t)sector_number; + req->device = device; + req->nr_segments = 1; +#ifdef CONFIG_XEN_BLKDEV_GRANT + /* install a grant reference. */ + ref = gnttab_claim_grant_reference(&gref_head, gref_terminal); + ASSERT( ref != -ENOSPC ); + + gnttab_grant_foreign_access_ref( + ref, + rdomid, + buffer_ma >> PAGE_SHIFT, + ( operation == BLKIF_OP_WRITE ? 1 : 0 ) ); + + blk_shadow[xid].frame[0] = buffer_ma >> PAGE_SHIFT; + + req->frame_and_sects[0] = (((u32) ref)<<16) | (fsect<<3) | lsect; +#else + req->frame_and_sects[0] = buffer_ma | (fsect<<3) | lsect; +#endif + + /* Keep a private copy so we can reissue requests when recovering. */ + pickle_request(&blk_shadow[xid], req); + + blk_ring.req_prod_pvt++; + + return 0; +} + + +/* + * do_blkif_request + * read a block; request is in a request queue + */ +void do_blkif_request(request_queue_t *rq) +{ + struct request *req; + struct buffer_head *bh, *next_bh; + int rw, nsect, full, queued = 0; + + DPRINTK("Entered do_blkif_request\n"); + + while ( !rq->plugged && !list_empty(&rq->queue_head)) + { + if ( (req = blkdev_entry_next_request(&rq->queue_head)) == NULL ) + goto out; + + DPRINTK("do_blkif_request %p: cmd %i, sec %lx, (%li/%li) bh:%p\n", + req, req->cmd, req->sector, + req->current_nr_sectors, req->nr_sectors, req->bh); + + rw = req->cmd; + if ( rw == READA ) + rw = READ; + if ( unlikely((rw != READ) && (rw != WRITE)) ) + panic("XenoLinux Virtual Block Device: bad cmd: %d\n", rw); + + req->errors = 0; + + bh = req->bh; + while ( bh != NULL ) + { + next_bh = bh->b_reqnext; + bh->b_reqnext = NULL; + + full = blkif_queue_request( + (unsigned long)bh, + (rw == READ) ? BLKIF_OP_READ : BLKIF_OP_WRITE, + bh->b_data, bh->b_rsector, bh->b_size>>9, bh->b_rdev); + + if ( full ) + { + bh->b_reqnext = next_bh; + pending_queues[nr_pending++] = rq; + if ( unlikely(nr_pending >= MAX_PENDING) ) + BUG(); + goto out; + } + + queued++; + + /* Dequeue the buffer head from the request. */ + nsect = bh->b_size >> 9; + bh = req->bh = next_bh; + + if ( bh != NULL ) + { + /* There's another buffer head to do. Update the request. */ + req->hard_sector += nsect; + req->hard_nr_sectors -= nsect; + req->sector = req->hard_sector; + req->nr_sectors = req->hard_nr_sectors; + req->current_nr_sectors = bh->b_size >> 9; + req->buffer = bh->b_data; + } + else + { + /* That was the last buffer head. Finalise the request. */ + if ( unlikely(end_that_request_first(req, 1, "XenBlk")) ) + BUG(); + blkdev_dequeue_request(req); + end_that_request_last(req); + } + } + } + + out: + if ( queued != 0 ) + flush_requests(); +} + + +static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs) +{ + RING_IDX i, rp; + unsigned long flags; + struct buffer_head *bh, *next_bh; + + spin_lock_irqsave(&io_request_lock, flags); + + if ( unlikely(blkif_state == BLKIF_STATE_CLOSED || recovery) ) + { + spin_unlock_irqrestore(&io_request_lock, flags); + return; + } + + rp = blk_ring.sring->rsp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + + for ( i = blk_ring.rsp_cons; i != rp; i++ ) + { + unsigned long id; + blkif_response_t *bret; + + bret = RING_GET_RESPONSE(&blk_ring, i); + id = bret->id; + bh = (struct buffer_head *)blk_shadow[id].request; + + blkif_completion(&blk_shadow[id]); + + ADD_ID_TO_FREELIST(id); + + switch ( bret->operation ) + { + case BLKIF_OP_READ: + case BLKIF_OP_WRITE: + if ( unlikely(bret->status != BLKIF_RSP_OKAY) ) + DPRINTK("Bad return from blkdev data request: %lx\n", + bret->status); + for ( ; bh != NULL; bh = next_bh ) + { + next_bh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, bret->status == BLKIF_RSP_OKAY); + } + + break; + case BLKIF_OP_PROBE: + memcpy(&blkif_control_rsp, bret, sizeof(*bret)); + blkif_control_rsp_valid = 1; + break; + default: + BUG(); + } + + } + blk_ring.rsp_cons = i; + + kick_pending_request_queues(); + + spin_unlock_irqrestore(&io_request_lock, flags); +} + +#endif + +/***************************** COMMON CODE *******************************/ + +#ifdef CONFIG_XEN_BLKDEV_GRANT +void blkif_control_probe_send(blkif_request_t *req, blkif_response_t *rsp, + unsigned long address) +{ + int ref = gnttab_claim_grant_reference(&gref_head, gref_terminal); + ASSERT( ref != -ENOSPC ); + + gnttab_grant_foreign_access_ref( ref, rdomid, address >> PAGE_SHIFT, 0 ); + + req->frame_and_sects[0] = (((u32) ref) << 16) | 7; + + blkif_control_send(req, rsp); +} +#endif + +void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp) +{ + unsigned long flags, id; + blkif_request_t *req_d; + + retry: + while ( RING_FULL(&blk_ring) ) + { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + + spin_lock_irqsave(&blkif_io_lock, flags); + if ( RING_FULL(&blk_ring) ) + { + spin_unlock_irqrestore(&blkif_io_lock, flags); + goto retry; + } + + DISABLE_SCATTERGATHER(); + req_d = RING_GET_REQUEST(&blk_ring, blk_ring.req_prod_pvt); + *req_d = *req; + + id = GET_ID_FROM_FREELIST(); + req_d->id = id; + blk_shadow[id].request = (unsigned long)req; + + pickle_request(&blk_shadow[id], req); + + blk_ring.req_prod_pvt++; + flush_requests(); + + spin_unlock_irqrestore(&blkif_io_lock, flags); + + while ( !blkif_control_rsp_valid ) + { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + + memcpy(rsp, &blkif_control_rsp, sizeof(*rsp)); + blkif_control_rsp_valid = 0; +} + + +/* Send a driver status notification to the domain controller. */ +static void send_driver_status(int ok) +{ + ctrl_msg_t cmsg = { + .type = CMSG_BLKIF_FE, + .subtype = CMSG_BLKIF_FE_DRIVER_STATUS, + .length = sizeof(blkif_fe_driver_status_t), + }; + blkif_fe_driver_status_t *msg = (void*)cmsg.msg; + + msg->status = (ok ? BLKIF_DRIVER_STATUS_UP : BLKIF_DRIVER_STATUS_DOWN); + + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); +} + +/* Tell the controller to bring up the interface. */ +static void blkif_send_interface_connect(void) +{ + ctrl_msg_t cmsg = { + .type = CMSG_BLKIF_FE, + .subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT, + .length = sizeof(blkif_fe_interface_connect_t), + }; + blkif_fe_interface_connect_t *msg = (void*)cmsg.msg; + + msg->handle = 0; + msg->shmem_frame = (virt_to_machine(blk_ring.sring) >> PAGE_SHIFT); + + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); +} + +static void blkif_free(void) +{ + /* Prevent new requests being issued until we fix things up. */ + spin_lock_irq(&blkif_io_lock); + recovery = 1; + blkif_state = BLKIF_STATE_DISCONNECTED; + spin_unlock_irq(&blkif_io_lock); + + /* Free resources associated with old device channel. */ + if ( blk_ring.sring != NULL ) + { + free_page((unsigned long)blk_ring.sring); + blk_ring.sring = NULL; + } + free_irq(blkif_irq, NULL); + blkif_irq = 0; + + unbind_evtchn_from_irq(blkif_evtchn); + blkif_evtchn = 0; +} + +static void blkif_close(void) +{ +} + +/* Move from CLOSED to DISCONNECTED state. */ +static void blkif_disconnect(void) +{ + blkif_sring_t *sring; + + if ( blk_ring.sring != NULL ) + free_page((unsigned long)blk_ring.sring); + + sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL); + SHARED_RING_INIT(sring); + FRONT_RING_INIT(&blk_ring, sring, PAGE_SIZE); + blkif_state = BLKIF_STATE_DISCONNECTED; + blkif_send_interface_connect(); +} + +static void blkif_reset(void) +{ + blkif_free(); + blkif_disconnect(); +} + +static void blkif_recover(void) +{ + int i; + blkif_request_t *req; + struct blk_shadow *copy; +#ifdef CONFIG_XEN_BLKDEV_GRANT + int j; +#endif + + /* Stage 1: Make a safe copy of the shadow state. */ + copy = (struct blk_shadow *)kmalloc(sizeof(blk_shadow), GFP_KERNEL); + BUG_ON(copy == NULL); + memcpy(copy, blk_shadow, sizeof(blk_shadow)); + + /* Stage 2: Set up free list. */ + memset(&blk_shadow, 0, sizeof(blk_shadow)); + for ( i = 0; i < BLK_RING_SIZE; i++ ) + blk_shadow[i].req.id = i+1; + blk_shadow_free = blk_ring.req_prod_pvt; + blk_shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + + /* Stage 3: Find pending requests and requeue them. */ + for ( i = 0; i < BLK_RING_SIZE; i++ ) + { + /* Not in use? */ + if ( copy[i].request == 0 ) + continue; + + /* Grab a request slot and unpickle shadow state into it. */ + req = RING_GET_REQUEST( + &blk_ring, blk_ring.req_prod_pvt); + unpickle_request(req, ©[i]); + + /* We get a new request id, and must reset the shadow state. */ + req->id = GET_ID_FROM_FREELIST(); + memcpy(&blk_shadow[req->id], ©[i], sizeof(copy[i])); + +#ifdef CONFIG_XEN_BLKDEV_GRANT + /* Rewrite any grant references invalidated by suspend/resume. */ + for ( j = 0; j < req->nr_segments; j++ ) + { + if ( req->frame_and_sects[j] & GRANTREF_INVALID ) + gnttab_grant_foreign_access_ref( + blkif_gref_from_fas(req->frame_and_sects[j]), + rdomid, + blk_shadow[req->id].frame[j], + rq_data_dir((struct request *) + blk_shadow[req->id].request)); + req->frame_and_sects[j] &= ~GRANTREF_INVALID; + } + blk_shadow[req->id].req = *req; +#endif + + blk_ring.req_prod_pvt++; + } + + kfree(copy); + + recovery = 0; + + /* blk_ring->req_prod will be set when we flush_requests().*/ + wmb(); + + /* Kicks things back into life. */ + flush_requests(); + + /* Now safe to left other people use the interface. */ + blkif_state = BLKIF_STATE_CONNECTED; +} + +static void blkif_connect(blkif_fe_interface_status_t *status) +{ + int err = 0; + + blkif_evtchn = status->evtchn; + blkif_irq = bind_evtchn_to_irq(blkif_evtchn); +#ifdef CONFIG_XEN_BLKDEV_GRANT + rdomid = status->domid; +#endif + + err = request_irq(blkif_irq, blkif_int, SA_SAMPLE_RANDOM, "blkif", NULL); + if ( err ) + { + printk(KERN_ALERT "xen_blk: request_irq failed (err=%d)\n", err); + return; + } + + if ( recovery ) + { + blkif_recover(); + } + else + { + /* Transition to connected in case we need to do + * a partition probe on a whole disk. */ + blkif_state = BLKIF_STATE_CONNECTED; + + /* Probe for discs attached to the interface. */ + xlvbd_init(); + } + + /* Kick pending requests. */ + spin_lock_irq(&blkif_io_lock); + kick_pending_request_queues(); + spin_unlock_irq(&blkif_io_lock); +} + +static void unexpected(blkif_fe_interface_status_t *status) +{ + DPRINTK(" Unexpected blkif status %u in state %u\n", + status->status, blkif_state); +} + +static void blkif_status(blkif_fe_interface_status_t *status) +{ + if ( status->handle != blkif_handle ) + { + WPRINTK(" Invalid blkif: handle=%u\n", status->handle); + unexpected(status); + return; + } + + switch ( status->status ) + { + case BLKIF_INTERFACE_STATUS_CLOSED: + switch ( blkif_state ) + { + case BLKIF_STATE_CLOSED: + unexpected(status); + break; + case BLKIF_STATE_DISCONNECTED: + case BLKIF_STATE_CONNECTED: + unexpected(status); + blkif_close(); + break; + } + break; + + case BLKIF_INTERFACE_STATUS_DISCONNECTED: + switch ( blkif_state ) + { + case BLKIF_STATE_CLOSED: + blkif_disconnect(); + break; + case BLKIF_STATE_DISCONNECTED: + case BLKIF_STATE_CONNECTED: + /* unexpected(status); */ /* occurs during suspend/resume */ + blkif_reset(); + break; + } + break; + + case BLKIF_INTERFACE_STATUS_CONNECTED: + switch ( blkif_state ) + { + case BLKIF_STATE_CLOSED: + unexpected(status); + blkif_disconnect(); + blkif_connect(status); + break; + case BLKIF_STATE_DISCONNECTED: + blkif_connect(status); + break; + case BLKIF_STATE_CONNECTED: + unexpected(status); + blkif_connect(status); + break; + } + break; + + case BLKIF_INTERFACE_STATUS_CHANGED: + switch ( blkif_state ) + { + case BLKIF_STATE_CLOSED: + case BLKIF_STATE_DISCONNECTED: + unexpected(status); + break; + case BLKIF_STATE_CONNECTED: + vbd_update(); + break; + } + break; + + default: + WPRINTK(" Invalid blkif status: %d\n", status->status); + break; + } +} + + +static void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) +{ + switch ( msg->subtype ) + { + case CMSG_BLKIF_FE_INTERFACE_STATUS: + blkif_status((blkif_fe_interface_status_t *) + &msg->msg[0]); + break; + default: + msg->length = 0; + break; + } + + ctrl_if_send_response(msg); +} + +int wait_for_blkif(void) +{ + int err = 0; + int i; + send_driver_status(1); + + /* + * We should read 'nr_interfaces' from response message and wait + * for notifications before proceeding. For now we assume that we + * will be notified of exactly one interface. + */ + for ( i=0; (blkif_state != BLKIF_STATE_CONNECTED) && (i < 10*HZ); i++ ) + { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + + if ( blkif_state != BLKIF_STATE_CONNECTED ) + { + printk(KERN_INFO "xen_blk: Timeout connecting to device!\n"); + err = -ENOSYS; + } + return err; +} + +int __init xlblk_init(void) +{ + int i; + +#ifdef CONFIG_XEN_BLKDEV_GRANT + if ( 0 > gnttab_alloc_grant_references( MAXIMUM_OUTSTANDING_BLOCK_REQS, + &gref_head, &gref_terminal )) + return 1; + printk(KERN_ALERT "Blkif frontend is using grant tables.\n"); +#endif + + if ( (xen_start_info.flags & SIF_INITDOMAIN) || + (xen_start_info.flags & SIF_BLK_BE_DOMAIN) ) + return 0; + + printk(KERN_INFO "xen_blk: Initialising virtual block device driver\n"); + + blk_shadow_free = 0; + memset(blk_shadow, 0, sizeof(blk_shadow)); + for ( i = 0; i < BLK_RING_SIZE; i++ ) + blk_shadow[i].req.id = i+1; + blk_shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff; + + (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx, + CALLBACK_IN_BLOCKING_CONTEXT); + + wait_for_blkif(); + + return 0; +} + +void blkdev_suspend(void) +{ +} + +void blkdev_resume(void) +{ +#ifdef CONFIG_XEN_BLKDEV_GRANT + int i, j; + for ( i = 0; i < BLK_RING_SIZE; i++ ) + for ( j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++ ) + blk_shadow[i].req.frame_and_sects[j] |= GRANTREF_INVALID; +#endif + send_driver_status(1); +} + +static void blkif_completion(struct blk_shadow *s) +{ + int i; +#ifdef CONFIG_XEN_BLKDEV_GRANT + for ( i = 0; i < s->req.nr_segments; i++ ) + gnttab_release_grant_reference( + &gref_head, blkif_gref_from_fas(s->req.frame_and_sects[i])); +#else + /* This is a hack to get the dirty logging bits set */ + if ( s->req.operation == BLKIF_OP_READ ) + { + for ( i = 0; i < s->req.nr_segments; i++ ) + { + unsigned long pfn = s->req.frame_and_sects[i] >> PAGE_SHIFT; + unsigned long mfn = phys_to_machine_mapping[pfn]; + xen_machphys_update(mfn, pfn); + } + } +#endif +} diff --git a/drivers/xen/blkfront/block.h b/drivers/xen/blkfront/block.h new file mode 100644 index 000000000..ede57abfa --- /dev/null +++ b/drivers/xen/blkfront/block.h @@ -0,0 +1,117 @@ +/****************************************************************************** + * block.h + * + * Shared definitions between all levels of XenLinux Virtual block devices. + * + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + * Modifications by Mark A. Williamson are (c) Intel Research Cambridge + * Copyright (c) 2004-2005, Christian Limpach + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef __XEN_DRIVERS_BLOCK_H__ +#define __XEN_DRIVERS_BLOCK_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DPRINTK(_f, _a...) printk ( KERN_ALERT _f , ## _a ) +#else +#define DPRINTK(_f, _a...) ((void)0) +#endif + +#if 0 +#define DPRINTK_IOCTL(_f, _a...) printk ( KERN_ALERT _f , ## _a ) +#else +#define DPRINTK_IOCTL(_f, _a...) ((void)0) +#endif + +struct xlbd_type_info { + int partn_shift; + int partn_per_major; + int devs_per_major; + char *devname; + char *diskname; +}; + +/* + * We have one of these per vbd, whether ide, scsi or 'other'. They + * hang in private_data off the gendisk structure. We may end up + * putting all kinds of interesting stuff here :-) + */ +struct xlbd_major_info { + int major; + int index; + int usage; + struct xlbd_type_info *type; +}; + +struct xlbd_disk_info { + int xd_device; + struct xlbd_major_info *mi; +}; + +typedef struct xen_block { + int usage; +} xen_block_t; + +extern struct request_queue *xlbd_blk_queue; +extern spinlock_t blkif_io_lock; + +extern int blkif_open(struct inode *inode, struct file *filep); +extern int blkif_release(struct inode *inode, struct file *filep); +extern int blkif_ioctl(struct inode *inode, struct file *filep, + unsigned command, unsigned long argument); +extern int blkif_check(dev_t dev); +extern int blkif_revalidate(dev_t dev); +extern void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp); +#ifdef CONFIG_XEN_BLKDEV_GRANT +extern void blkif_control_probe_send( + blkif_request_t *req, blkif_response_t *rsp, unsigned long address); +#endif +extern void do_blkif_request (request_queue_t *rq); + +extern void xlvbd_update_vbds(void); + +/* Virtual block-device subsystem. */ +extern int xlvbd_init(void); +extern void xlvbd_cleanup(void); + +#endif /* __XEN_DRIVERS_BLOCK_H__ */ diff --git a/drivers/xen/blkfront/vbd.c b/drivers/xen/blkfront/vbd.c new file mode 100644 index 000000000..b5f2b14b4 --- /dev/null +++ b/drivers/xen/blkfront/vbd.c @@ -0,0 +1,507 @@ +/****************************************************************************** + * vbd.c + * + * XenLinux virtual block-device driver (xvd). + * + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + * Modifications by Mark A. Williamson are (c) Intel Research Cambridge + * Copyright (c) 2004-2005, Christian Limpach + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "block.h" +#include +#include + +/* + * For convenience we distinguish between ide, scsi and 'other' (i.e., + * potentially combinations of the two) in the naming scheme and in a few other + * places. + */ + +#define NUM_IDE_MAJORS 10 +#define NUM_SCSI_MAJORS 9 +#define NUM_VBD_MAJORS 1 + +struct lvdisk +{ + blkif_sector_t capacity; /* 0: Size in terms of 512-byte sectors. */ + blkif_vdev_t device; /* 8: Device number (opaque 16 bit value). */ + u16 info; + struct list_head list; +}; + +static struct xlbd_type_info xlbd_ide_type = { + .partn_shift = 6, + .partn_per_major = 2, + .devname = "ide", + .diskname = "hd", +}; + +static struct xlbd_type_info xlbd_scsi_type = { + .partn_shift = 4, + .partn_per_major = 16, + .devname = "sd", + .diskname = "sd", +}; + +static struct xlbd_type_info xlbd_vbd_type = { + .partn_shift = 4, + .partn_per_major = 16, + .devname = "xvd", + .diskname = "xvd", +}; + +static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS + + NUM_VBD_MAJORS]; + +#define XLBD_MAJOR_IDE_START 0 +#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS) +#define XLBD_MAJOR_VBD_START (NUM_IDE_MAJORS + NUM_SCSI_MAJORS) + +#define XLBD_MAJOR_IDE_RANGE XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1 +#define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1 +#define XLBD_MAJOR_VBD_RANGE XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1 + +/* Information about our VBDs. */ +#define MAX_VBDS 64 +struct list_head vbds_list; + +struct request_queue *xlbd_blk_queue = NULL; + +#define MAJOR_XEN(dev) ((dev)>>8) +#define MINOR_XEN(dev) ((dev) & 0xff) + +static struct block_device_operations xlvbd_block_fops = +{ + .owner = THIS_MODULE, + .open = blkif_open, + .release = blkif_release, + .ioctl = blkif_ioctl, +}; + +spinlock_t blkif_io_lock = SPIN_LOCK_UNLOCKED; + +static struct lvdisk * xlvbd_device_alloc(void) +{ + struct lvdisk *ret; + + ret = kmalloc(sizeof(struct lvdisk), GFP_KERNEL); + if ( ret ) { + memset(ret, '\0', sizeof(struct lvdisk)); + INIT_LIST_HEAD(&ret->list); + } + return ret; +} + +static void xlvbd_device_free(struct lvdisk *disk) +{ + list_del(&disk->list); + kfree(disk); +} + +static vdisk_t * xlvbd_probe(int *ret) +{ + blkif_response_t rsp; + blkif_request_t req; + vdisk_t *disk_info = NULL; + unsigned long buf; + int nr; + + buf = __get_free_page(GFP_KERNEL); + if ( !buf ) + goto out; + + memset(&req, 0, sizeof(req)); + req.operation = BLKIF_OP_PROBE; + req.nr_segments = 1; +#ifdef CONFIG_XEN_BLKDEV_GRANT + blkif_control_probe_send(&req, &rsp, + (unsigned long)(virt_to_machine(buf))); +#else + req.frame_and_sects[0] = virt_to_machine(buf) | 7; + + blkif_control_send(&req, &rsp); +#endif + if ( rsp.status <= 0 ) { + printk(KERN_ALERT "Could not probe disks (%d)\n", rsp.status); + goto out; + } + nr = rsp.status; + if ( nr > MAX_VBDS ) + nr = MAX_VBDS; + + disk_info = kmalloc(nr * sizeof(vdisk_t), GFP_KERNEL); + if ( disk_info ) + memcpy(disk_info, (void *) buf, nr * sizeof(vdisk_t)); + if ( ret ) + *ret = nr; +out: + free_page(buf); + return disk_info; +} + +static struct xlbd_major_info *xlbd_alloc_major_info(int major, int minor, int index) +{ + struct xlbd_major_info *ptr; + + ptr = kmalloc(sizeof(struct xlbd_major_info), GFP_KERNEL); + if ( !ptr ) + return NULL; + + memset(ptr, 0, sizeof(struct xlbd_major_info)); + + ptr->major = major; + + switch (index) { + case XLBD_MAJOR_IDE_RANGE: + ptr->type = &xlbd_ide_type; + ptr->index = index - XLBD_MAJOR_IDE_START; + break; + case XLBD_MAJOR_SCSI_RANGE: + ptr->type = &xlbd_scsi_type; + ptr->index = index - XLBD_MAJOR_SCSI_START; + break; + case XLBD_MAJOR_VBD_RANGE: + ptr->type = &xlbd_vbd_type; + ptr->index = index - XLBD_MAJOR_VBD_START; + break; + } + + if ( register_blkdev(ptr->major, ptr->type->devname) ) { + printk(KERN_ALERT "XL VBD: can't get major %d with name %s\n", + ptr->major, ptr->type->devname); + kfree(ptr); + return NULL; + } + + devfs_mk_dir(ptr->type->devname); + major_info[index] = ptr; + return ptr; +} + +static struct xlbd_major_info *xlbd_get_major_info(int device) +{ + int major, minor, index; + + major = MAJOR_XEN(device); + minor = MINOR_XEN(device); + + switch (major) { + case IDE0_MAJOR: index = 0; break; + case IDE1_MAJOR: index = 1; break; + case IDE2_MAJOR: index = 2; break; + case IDE3_MAJOR: index = 3; break; + case IDE4_MAJOR: index = 4; break; + case IDE5_MAJOR: index = 5; break; + case IDE6_MAJOR: index = 6; break; + case IDE7_MAJOR: index = 7; break; + case IDE8_MAJOR: index = 8; break; + case IDE9_MAJOR: index = 9; break; + case SCSI_DISK0_MAJOR: index = 10; break; + case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR: + index = 11 + major - SCSI_DISK1_MAJOR; + break; + case SCSI_CDROM_MAJOR: index = 18; break; + default: index = 19; break; + } + + return major_info[index] + ? major_info[index] + : xlbd_alloc_major_info(major, minor, index); +} + +static int xlvbd_blk_queue_alloc(struct xlbd_type_info *type) +{ + xlbd_blk_queue = blk_init_queue(do_blkif_request, &blkif_io_lock); + if ( !xlbd_blk_queue ) + return -1; + + elevator_init(xlbd_blk_queue, "noop"); + + /* + * Turn off barking 'headactive' mode. We dequeue + * buffer heads as soon as we pass them to back-end + * driver. + */ + blk_queue_headactive(xlbd_blk_queue, 0); + + /* Hard sector size and max sectors impersonate the equiv. hardware. */ + blk_queue_hardsect_size(xlbd_blk_queue, 512); + blk_queue_max_sectors(xlbd_blk_queue, 512); + + /* Each segment in a request is up to an aligned page in size. */ + blk_queue_segment_boundary(xlbd_blk_queue, PAGE_SIZE - 1); + blk_queue_max_segment_size(xlbd_blk_queue, PAGE_SIZE); + + /* Ensure a merged request will fit in a single I/O ring slot. */ + blk_queue_max_phys_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST); + blk_queue_max_hw_segments(xlbd_blk_queue, BLKIF_MAX_SEGMENTS_PER_REQUEST); + + /* Make sure buffer addresses are sector-aligned. */ + blk_queue_dma_alignment(xlbd_blk_queue, 511); + return 0; +} + +struct gendisk *xlvbd_alloc_gendisk(struct xlbd_major_info *mi, int minor, + vdisk_t *disk) +{ + struct gendisk *gd; + struct xlbd_disk_info *di; + int nb_minors; + + di = kmalloc(sizeof(struct xlbd_disk_info), GFP_KERNEL); + if ( !di ) + goto out; + di->mi = mi; + di->xd_device = disk->device; + + nb_minors = ((minor & ((1 << mi->type->partn_shift) - 1)) == 0) + ? mi->type->partn_per_major + : 1; + + gd = alloc_disk(nb_minors); + if ( !gd ) + goto out; + + if ( nb_minors > 1 ) + sprintf(gd->disk_name, "%s%c", mi->type->diskname, + 'a' + mi->index * mi->type->partn_per_major + + (minor >> mi->type->partn_shift)); + else + sprintf(gd->disk_name, "%s%c%d", mi->type->diskname, + 'a' + mi->index * mi->type->partn_per_major + + (minor >> mi->type->partn_shift), + minor & ((1 << mi->type->partn_shift) - 1)); + + gd->major = mi->major; + gd->first_minor = minor; + gd->fops = &xlvbd_block_fops; + gd->private_data = di; + set_capacity(gd, disk->capacity); + + if ( !xlbd_blk_queue ) + if ( xlvbd_blk_queue_alloc(mi->type) ) + goto out_gendisk; + + gd->queue = xlbd_blk_queue; + add_disk(gd); + return gd; +out_gendisk: + printk(KERN_ALERT "error gendisk\n"); + del_gendisk(gd); +out: + printk(KERN_ALERT "error out\n"); + kfree(di); + return NULL; +} + +static int xlvbd_device_add(struct list_head *list, vdisk_t *disk) +{ + struct lvdisk *new; + int minor; + dev_t device; + struct block_device *bd; + struct gendisk *gd; + struct xlbd_major_info *mi; + + mi = xlbd_get_major_info(disk->device); + if ( !mi ) + return -EPERM; + + new = xlvbd_device_alloc(); + if ( !new ) + return -1; + new->capacity = disk->capacity; + new->device = disk->device; + new->info = disk->info; + + minor = MINOR_XEN(disk->device); + device = MKDEV(mi->major, minor); + + bd = bdget(device); + if ( !bd ) + goto out; + + gd = xlvbd_alloc_gendisk(mi, minor, disk); + if ( !gd ) + goto out_bd; + + if ( VDISK_READONLY(disk->info) ) + set_disk_ro(gd, 1); + + switch (VDISK_TYPE(disk->info)) { + case VDISK_TYPE_CDROM: + gd->flags |= GENHD_FL_REMOVABLE | GENHD_FL_CD; + break; + case VDISK_TYPE_FLOPPY: + case VDISK_TYPE_TAPE: + gd->flags |= GENHD_FL_REMOVABLE; + break; + case VDISK_TYPE_DISK: + break; + default: + printk(KERN_ALERT "XenLinux: unknown device type %d\n", + VDISK_TYPE(disk->info)); + break; + } + + list_add(&new->list, list); +out_bd: + bdput(bd); +out: + return 0; +} + +static int xlvbd_device_del(struct lvdisk *disk) +{ + dev_t device; + struct block_device *bd; + struct gendisk *gd; + struct xlbd_disk_info *di; + int ret = 0, unused; + + device = MKDEV(MAJOR_XEN(disk->device), MINOR_XEN(disk->device)); + + bd = bdget(device); + if ( !bd ) + return -1; + + gd = get_gendisk(device, &unused); + di = gd->private_data; + + if ( di->mi->usage != 0 ) { + printk(KERN_ALERT "VBD removal failed: used [dev=%x]\n", device); + ret = -1; + goto out; + } + + del_gendisk(gd); + + xlvbd_device_free(disk); +out: + bdput(bd); + return ret; +} + +static int xlvbd_device_update(struct lvdisk *ldisk, vdisk_t *disk) +{ + dev_t device; + struct block_device *bd; + struct gendisk *gd; + int unused; + + if ( ldisk->capacity == disk->capacity && ldisk->info == disk->info ) + return 0; + + device = MKDEV(MAJOR_XEN(ldisk->device), MINOR_XEN(ldisk->device)); + + bd = bdget(device); + if ( !bd ) + return -1; + + gd = get_gendisk(device, &unused); + set_capacity(gd, disk->capacity); + ldisk->capacity = disk->capacity; + + bdput(bd); + + return 0; +} + +void xlvbd_refresh(void) +{ + vdisk_t *newdisks; + struct list_head *tmp, *tmp2; + struct lvdisk *disk; + int i, nr; + + newdisks = xlvbd_probe(&nr); + if ( !newdisks ) { + printk(KERN_ALERT "failed to probe\n"); + return; + } + + i = 0; + list_for_each_safe(tmp, tmp2, &vbds_list) { + disk = list_entry(tmp, struct lvdisk, list); + + for (i = 0; i < nr; i++) { + if ( !newdisks[i].device ) + continue; + if ( disk->device == newdisks[i].device ) { + xlvbd_device_update(disk, &newdisks[i]); + newdisks[i].device = 0; + break; + } + } + if ( i == nr ) { + xlvbd_device_del(disk); + newdisks[i].device = 0; + } + } + for (i = 0; i < nr; i++) + if ( newdisks[i].device ) + xlvbd_device_add(&vbds_list, &newdisks[i]); + kfree(newdisks); +} + +/* + * xlvbd_update_vbds - reprobes the VBD status and performs updates driver + * state. The VBDs need to be updated in this way when the domain is + * initialised and also each time we receive an XLBLK_UPDATE event. + */ +void xlvbd_update_vbds(void) +{ + xlvbd_refresh(); +} + +/* + * Set up all the linux device goop for the virtual block devices + * (vbd's) that we know about. Note that although from the backend + * driver's p.o.v. VBDs are addressed simply an opaque 16-bit device + * number, the domain creation tools conventionally allocate these + * numbers to correspond to those used by 'real' linux -- this is just + * for convenience as it means e.g. that the same /etc/fstab can be + * used when booting with or without Xen. + */ +int xlvbd_init(void) +{ + int i, nr; + vdisk_t *disks; + + INIT_LIST_HEAD(&vbds_list); + + memset(major_info, 0, sizeof(major_info)); + + disks = xlvbd_probe(&nr); + if ( !disks ) { + printk(KERN_ALERT "failed to probe\n"); + return -1; + } + + for (i = 0; i < nr; i++) + xlvbd_device_add(&vbds_list, &disks[i]); + kfree(disks); + return 0; +} diff --git a/drivers/xen/blktap/Makefile b/drivers/xen/blktap/Makefile new file mode 100644 index 000000000..80b7ca062 --- /dev/null +++ b/drivers/xen/blktap/Makefile @@ -0,0 +1,3 @@ + +obj-y := blktap_userdev.o blktap_datapath.o blktap_controlmsg.o blktap.o + diff --git a/drivers/xen/blktap/blktap.c b/drivers/xen/blktap/blktap.c new file mode 100644 index 000000000..a9a00677b --- /dev/null +++ b/drivers/xen/blktap/blktap.c @@ -0,0 +1,87 @@ +/****************************************************************************** + * blktap.c + * + * XenLinux virtual block-device tap. + * + * Copyright (c) 2004, Andrew Warfield + * + * Based on the original split block driver: + * Copyright (c) 2003-2004, Keir Fraser & Steve Hand + * Modifications by Mark A. Williamson are (c) Intel Research Cambridge + * Copyright (c) 2004, Christian Limpach + * + * Note that unlike the split block driver code, this driver has been developed + * strictly for Linux 2.6 + */ + +#include "blktap.h" + +int __init xlblktap_init(void) +{ + ctrl_msg_t cmsg; + blkif_fe_driver_status_t fe_st; + blkif_be_driver_status_t be_st; + + printk(KERN_INFO "Initialising Xen block tap device\n"); + + DPRINTK(" tap - Backend connection init:\n"); + + + (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx, + CALLBACK_IN_BLOCKING_CONTEXT); + + /* Send a driver-UP notification to the domain controller. */ + cmsg.type = CMSG_BLKIF_FE; + cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS; + cmsg.length = sizeof(blkif_fe_driver_status_t); + fe_st.status = BLKIF_DRIVER_STATUS_UP; + memcpy(cmsg.msg, &fe_st, sizeof(fe_st)); + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); + + DPRINTK(" tap - Frontend connection init:\n"); + + active_reqs_init(); + blkif_interface_init(); + blkdev_schedule_init(); + + (void)ctrl_if_register_receiver(CMSG_BLKIF_BE, blkif_ctrlif_rx, + CALLBACK_IN_BLOCKING_CONTEXT); + + /* Send a driver-UP notification to the domain controller. */ + cmsg.type = CMSG_BLKIF_BE; + cmsg.subtype = CMSG_BLKIF_BE_DRIVER_STATUS; + cmsg.length = sizeof(blkif_be_driver_status_t); + be_st.status = BLKIF_DRIVER_STATUS_UP; + memcpy(cmsg.msg, &be_st, sizeof(be_st)); + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); + + DPRINTK(" tap - Userland channel init:\n"); + + blktap_init(); + + DPRINTK("Blkif tap device initialized.\n"); + + return 0; +} + +#if 0 /* tap doesn't handle suspend/resume */ +void blkdev_suspend(void) +{ +} + +void blkdev_resume(void) +{ + ctrl_msg_t cmsg; + blkif_fe_driver_status_t st; + + /* Send a driver-UP notification to the domain controller. */ + cmsg.type = CMSG_BLKIF_FE; + cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS; + cmsg.length = sizeof(blkif_fe_driver_status_t); + st.status = BLKIF_DRIVER_STATUS_UP; + memcpy(cmsg.msg, &st, sizeof(st)); + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); +} +#endif + +__initcall(xlblktap_init); diff --git a/drivers/xen/console/Makefile b/drivers/xen/console/Makefile new file mode 100644 index 000000000..e4ffdeffc --- /dev/null +++ b/drivers/xen/console/Makefile @@ -0,0 +1,2 @@ + +obj-y := console.o diff --git a/drivers/xen/console/console.c b/drivers/xen/console/console.c new file mode 100644 index 000000000..142ca2baa --- /dev/null +++ b/drivers/xen/console/console.c @@ -0,0 +1,811 @@ +/****************************************************************************** + * console.c + * + * Virtual console driver. + * + * Copyright (c) 2002-2004, K A Fraser. + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Modes: + * 'xencons=off' [XC_OFF]: Console is disabled. + * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'. + * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'. + * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY. + * + * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses + * warnings from standard distro startup scripts. + */ +static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT; +static int xc_num = -1; + +static int __init xencons_setup(char *str) +{ + char *q; + int n; + + if ( !strncmp(str, "ttyS", 4) ) + xc_mode = XC_SERIAL; + else if ( !strncmp(str, "tty", 3) ) + xc_mode = XC_TTY; + else if ( !strncmp(str, "off", 3) ) + xc_mode = XC_OFF; + + switch ( xc_mode ) + { + case XC_SERIAL: + n = simple_strtol( str+4, &q, 10 ); + if ( q > (str + 4) ) xc_num = n; + break; + case XC_TTY: + n = simple_strtol( str+3, &q, 10 ); + if ( q > (str + 3) ) xc_num = n; + break; + default: + break; + } + + return 1; +} +__setup("xencons=", xencons_setup); + +/* The kernel and user-land drivers share a common transmit buffer. */ +static unsigned int wbuf_size = 4096; +#define WBUF_MASK(_i) ((_i)&(wbuf_size-1)) +static char *wbuf; +static unsigned int wc, wp; /* write_cons, write_prod */ + +static int __init xencons_bufsz_setup(char *str) +{ + unsigned int goal; + goal = simple_strtoul(str, NULL, 0); + while ( wbuf_size < goal ) + wbuf_size <<= 1; + return 1; +} +__setup("xencons_bufsz=", xencons_bufsz_setup); + +/* This lock protects accesses to the common transmit buffer. */ +static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED; + +/* Common transmit-kick routine. */ +static void __xencons_tx_flush(void); + +/* This task is used to defer sending console data until there is space. */ +static void xencons_tx_flush_task_routine(void *data); + +static DECLARE_TQUEUE(xencons_tx_flush_task, + xencons_tx_flush_task_routine, + NULL); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static struct tty_driver *xencons_driver; +#else +static struct tty_driver xencons_driver; +#endif + + +/******************** Kernel console driver ********************************/ + +static void kcons_write( + struct console *c, const char *s, unsigned int count) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&xencons_lock, flags); + + for ( i = 0; i < count; i++ ) + { + if ( (wp - wc) >= (wbuf_size - 1) ) + break; + if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' ) + wbuf[WBUF_MASK(wp++)] = '\r'; + } + + __xencons_tx_flush(); + + spin_unlock_irqrestore(&xencons_lock, flags); +} + +static void kcons_write_dom0( + struct console *c, const char *s, unsigned int count) +{ + int rc; + + while ( (count > 0) && + ((rc = HYPERVISOR_console_io( + CONSOLEIO_write, count, (char *)s)) > 0) ) + { + count -= rc; + s += rc; + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static struct tty_driver *kcons_device(struct console *c, int *index) +{ + *index = c->index; + return xencons_driver; +} +#else +static kdev_t kcons_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1); +} +#endif + +static struct console kcons_info = { + device: kcons_device, + flags: CON_PRINTBUFFER, + index: -1 +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#define __RETCODE 0 +static int __init xen_console_init(void) +#else +#define __RETCODE +void xen_console_init(void) +#endif +{ + if ( xen_start_info.flags & SIF_INITDOMAIN ) + { + if ( xc_mode == XC_DEFAULT ) + xc_mode = XC_SERIAL; + kcons_info.write = kcons_write_dom0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + if ( xc_mode == XC_SERIAL ) + kcons_info.flags |= CON_ENABLED; +#endif + } + else + { + if ( xc_mode == XC_DEFAULT ) + xc_mode = XC_TTY; + kcons_info.write = kcons_write; + } + + switch ( xc_mode ) + { + case XC_SERIAL: + strcpy(kcons_info.name, "ttyS"); + if ( xc_num == -1 ) xc_num = 0; + break; + + case XC_TTY: + strcpy(kcons_info.name, "tty"); + if ( xc_num == -1 ) xc_num = 1; + break; + + default: + return __RETCODE; + } + + wbuf = alloc_bootmem(wbuf_size); + + register_console(&kcons_info); + + return __RETCODE; +} +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +console_initcall(xen_console_init); +#endif + +/*** Useful function for console debugging -- goes straight to Xen. ***/ +asmlinkage int xprintk(const char *fmt, ...) +{ + va_list args; + int printk_len; + static char printk_buf[1024]; + + /* Emit the output into the temporary buffer */ + va_start(args, fmt); + printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); + va_end(args); + + /* Send the processed output directly to Xen. */ + kcons_write_dom0(NULL, printk_buf, printk_len); + + return 0; +} + +/*** Forcibly flush console data before dying. ***/ +void xencons_force_flush(void) +{ + ctrl_msg_t msg; + int sz; + + /* Emergency console is synchronous, so there's nothing to flush. */ + if ( xen_start_info.flags & SIF_INITDOMAIN ) + return; + + /* + * We use dangerous control-interface functions that require a quiescent + * system and no interrupts. Try to ensure this with a global cli(). + */ + local_irq_disable(); /* XXXsmp */ + + /* Spin until console data is flushed through to the domain controller. */ + while ( (wc != wp) && !ctrl_if_transmitter_empty() ) + { + /* Interrupts are disabled -- we must manually reap responses. */ + ctrl_if_discard_responses(); + + if ( (sz = wp - wc) == 0 ) + continue; + if ( sz > sizeof(msg.msg) ) + sz = sizeof(msg.msg); + if ( sz > (wbuf_size - WBUF_MASK(wc)) ) + sz = wbuf_size - WBUF_MASK(wc); + + msg.type = CMSG_CONSOLE; + msg.subtype = CMSG_CONSOLE_DATA; + msg.length = sz; + memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz); + + if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 ) + wc += sz; + } +} + + +/******************** User-space console driver (/dev/console) ************/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#define DRV(_d) (_d) +#define TTY_INDEX(_tty) ((_tty)->index) +#else +static int xencons_refcount; +static struct tty_struct *xencons_table[MAX_NR_CONSOLES]; +#define DRV(_d) (&(_d)) +#define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start) +#endif + +static struct termios *xencons_termios[MAX_NR_CONSOLES]; +static struct termios *xencons_termios_locked[MAX_NR_CONSOLES]; +static struct tty_struct *xencons_tty; +static int xencons_priv_irq; +static char x_char; + +/* Non-privileged receive callback. */ +static void xencons_rx(ctrl_msg_t *msg, unsigned long id) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&xencons_lock, flags); + if ( xencons_tty != NULL ) + { + for ( i = 0; i < msg->length; i++ ) + tty_insert_flip_char(xencons_tty, msg->msg[i], 0); + tty_flip_buffer_push(xencons_tty); + } + spin_unlock_irqrestore(&xencons_lock, flags); + + msg->length = 0; + ctrl_if_send_response(msg); +} + +/* Privileged and non-privileged transmit worker. */ +static void __xencons_tx_flush(void) +{ + int sz, work_done = 0; + ctrl_msg_t msg; + + if ( xen_start_info.flags & SIF_INITDOMAIN ) + { + if ( x_char ) + { + kcons_write_dom0(NULL, &x_char, 1); + x_char = 0; + work_done = 1; + } + + while ( wc != wp ) + { + sz = wp - wc; + if ( sz > (wbuf_size - WBUF_MASK(wc)) ) + sz = wbuf_size - WBUF_MASK(wc); + kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz); + wc += sz; + work_done = 1; + } + } + else + { + while ( x_char ) + { + msg.type = CMSG_CONSOLE; + msg.subtype = CMSG_CONSOLE_DATA; + msg.length = 1; + msg.msg[0] = x_char; + + if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 ) + x_char = 0; + else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) ) + break; + + work_done = 1; + } + + while ( wc != wp ) + { + sz = wp - wc; + if ( sz > sizeof(msg.msg) ) + sz = sizeof(msg.msg); + if ( sz > (wbuf_size - WBUF_MASK(wc)) ) + sz = wbuf_size - WBUF_MASK(wc); + + msg.type = CMSG_CONSOLE; + msg.subtype = CMSG_CONSOLE_DATA; + msg.length = sz; + memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz); + + if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 ) + wc += sz; + else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) ) + break; + + work_done = 1; + } + } + + if ( work_done && (xencons_tty != NULL) ) + { + wake_up_interruptible(&xencons_tty->write_wait); + if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + (xencons_tty->ldisc.write_wakeup != NULL) ) + (xencons_tty->ldisc.write_wakeup)(xencons_tty); + } +} + +/* Non-privileged transmit kicker. */ +static void xencons_tx_flush_task_routine(void *data) +{ + unsigned long flags; + spin_lock_irqsave(&xencons_lock, flags); + __xencons_tx_flush(); + spin_unlock_irqrestore(&xencons_lock, flags); +} + +/* Privileged receive callback and transmit kicker. */ +static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + static char rbuf[16]; + int i, l; + unsigned long flags; + + spin_lock_irqsave(&xencons_lock, flags); + + if ( xencons_tty != NULL ) + { + /* Receive work. */ + while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 ) + for ( i = 0; i < l; i++ ) + tty_insert_flip_char(xencons_tty, rbuf[i], 0); + if ( xencons_tty->flip.count != 0 ) + tty_flip_buffer_push(xencons_tty); + } + + /* Transmit work. */ + __xencons_tx_flush(); + + spin_unlock_irqrestore(&xencons_lock, flags); + + return IRQ_HANDLED; +} + +static int xencons_write_room(struct tty_struct *tty) +{ + return wbuf_size - (wp - wc); +} + +static int xencons_chars_in_buffer(struct tty_struct *tty) +{ + return wp - wc; +} + +static void xencons_send_xchar(struct tty_struct *tty, char ch) +{ + unsigned long flags; + + if ( TTY_INDEX(tty) != 0 ) + return; + + spin_lock_irqsave(&xencons_lock, flags); + x_char = ch; + __xencons_tx_flush(); + spin_unlock_irqrestore(&xencons_lock, flags); +} + +static void xencons_throttle(struct tty_struct *tty) +{ + if ( TTY_INDEX(tty) != 0 ) + return; + + if ( I_IXOFF(tty) ) + xencons_send_xchar(tty, STOP_CHAR(tty)); +} + +static void xencons_unthrottle(struct tty_struct *tty) +{ + if ( TTY_INDEX(tty) != 0 ) + return; + + if ( I_IXOFF(tty) ) + { + if ( x_char != 0 ) + x_char = 0; + else + xencons_send_xchar(tty, START_CHAR(tty)); + } +} + +static void xencons_flush_buffer(struct tty_struct *tty) +{ + unsigned long flags; + + if ( TTY_INDEX(tty) != 0 ) + return; + + spin_lock_irqsave(&xencons_lock, flags); + wc = wp = 0; + spin_unlock_irqrestore(&xencons_lock, flags); +} + +static inline int __xencons_put_char(int ch) +{ + char _ch = (char)ch; + if ( (wp - wc) == wbuf_size ) + return 0; + wbuf[WBUF_MASK(wp++)] = _ch; + return 1; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static int xencons_write( + struct tty_struct *tty, + const unsigned char *buf, + int count) +{ + int i; + unsigned long flags; + + if ( TTY_INDEX(tty) != 0 ) + return count; + + spin_lock_irqsave(&xencons_lock, flags); + + for ( i = 0; i < count; i++ ) + if ( !__xencons_put_char(buf[i]) ) + break; + + if ( i != 0 ) + __xencons_tx_flush(); + + spin_unlock_irqrestore(&xencons_lock, flags); + + return i; +} +#else +static int xencons_write( + struct tty_struct *tty, + int from_user, + const u_char *buf, + int count) +{ + int i; + unsigned long flags; + + if ( from_user && verify_area(VERIFY_READ, buf, count) ) + return -EINVAL; + + if ( TTY_INDEX(tty) != 0 ) + return count; + + spin_lock_irqsave(&xencons_lock, flags); + + for ( i = 0; i < count; i++ ) + { + char ch; + if ( from_user ) + __get_user(ch, buf + i); + else + ch = buf[i]; + if ( !__xencons_put_char(ch) ) + break; + } + + if ( i != 0 ) + __xencons_tx_flush(); + + spin_unlock_irqrestore(&xencons_lock, flags); + + return i; +} +#endif + +static void xencons_put_char(struct tty_struct *tty, u_char ch) +{ + unsigned long flags; + + if ( TTY_INDEX(tty) != 0 ) + return; + + spin_lock_irqsave(&xencons_lock, flags); + (void)__xencons_put_char(ch); + spin_unlock_irqrestore(&xencons_lock, flags); +} + +static void xencons_flush_chars(struct tty_struct *tty) +{ + unsigned long flags; + + if ( TTY_INDEX(tty) != 0 ) + return; + + spin_lock_irqsave(&xencons_lock, flags); + __xencons_tx_flush(); + spin_unlock_irqrestore(&xencons_lock, flags); +} + +static void xencons_wait_until_sent(struct tty_struct *tty, int timeout) +{ + unsigned long orig_jiffies = jiffies; + + if ( TTY_INDEX(tty) != 0 ) + return; + + while ( DRV(tty->driver)->chars_in_buffer(tty) ) + { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + if ( signal_pending(current) ) + break; + if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) ) + break; + } + + set_current_state(TASK_RUNNING); +} + +static int xencons_open(struct tty_struct *tty, struct file *filp) +{ + unsigned long flags; + + if ( TTY_INDEX(tty) != 0 ) + return 0; + + spin_lock_irqsave(&xencons_lock, flags); + tty->driver_data = NULL; + if ( xencons_tty == NULL ) + xencons_tty = tty; + __xencons_tx_flush(); + spin_unlock_irqrestore(&xencons_lock, flags); + + return 0; +} + +static void xencons_close(struct tty_struct *tty, struct file *filp) +{ + unsigned long flags; + + if ( TTY_INDEX(tty) != 0 ) + return; + + if ( tty->count == 1 ) + { + tty->closing = 1; + tty_wait_until_sent(tty, 0); + if ( DRV(tty->driver)->flush_buffer != NULL ) + DRV(tty->driver)->flush_buffer(tty); + if ( tty->ldisc.flush_buffer != NULL ) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + spin_lock_irqsave(&xencons_lock, flags); + xencons_tty = NULL; + spin_unlock_irqrestore(&xencons_lock, flags); + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +static struct tty_operations xencons_ops = { + .open = xencons_open, + .close = xencons_close, + .write = xencons_write, + .write_room = xencons_write_room, + .put_char = xencons_put_char, + .flush_chars = xencons_flush_chars, + .chars_in_buffer = xencons_chars_in_buffer, + .send_xchar = xencons_send_xchar, + .flush_buffer = xencons_flush_buffer, + .throttle = xencons_throttle, + .unthrottle = xencons_unthrottle, + .wait_until_sent = xencons_wait_until_sent, +}; + +#ifdef CONFIG_XEN_PRIVILEGED_GUEST +static const char *xennullcon_startup(void) +{ + return NULL; +} + +static int xennullcon_dummy(void) +{ + return 0; +} + +#define DUMMY (void *)xennullcon_dummy + +/* + * The console `switch' structure for the dummy console + * + * Most of the operations are dummies. + */ + +const struct consw xennull_con = { + .owner = THIS_MODULE, + .con_startup = xennullcon_startup, + .con_init = DUMMY, + .con_deinit = DUMMY, + .con_clear = DUMMY, + .con_putc = DUMMY, + .con_putcs = DUMMY, + .con_cursor = DUMMY, + .con_scroll = DUMMY, + .con_bmove = DUMMY, + .con_switch = DUMMY, + .con_blank = DUMMY, + .con_font_set = DUMMY, + .con_font_get = DUMMY, + .con_font_default = DUMMY, + .con_font_copy = DUMMY, + .con_set_palette = DUMMY, + .con_scrolldelta = DUMMY, +}; +#endif +#endif + +static int __init xencons_init(void) +{ + int rc; + + if ( xc_mode == XC_OFF ) + return 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ? + 1 : MAX_NR_CONSOLES); + if ( xencons_driver == NULL ) + return -ENOMEM; +#else + memset(&xencons_driver, 0, sizeof(struct tty_driver)); + xencons_driver.magic = TTY_DRIVER_MAGIC; + xencons_driver.refcount = &xencons_refcount; + xencons_driver.table = xencons_table; + xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES; +#endif + + DRV(xencons_driver)->major = TTY_MAJOR; + DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL; + DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL; + DRV(xencons_driver)->init_termios = tty_std_termios; + DRV(xencons_driver)->flags = + TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS; + DRV(xencons_driver)->termios = xencons_termios; + DRV(xencons_driver)->termios_locked = xencons_termios_locked; + + if ( xc_mode == XC_SERIAL ) + { + DRV(xencons_driver)->name = "ttyS"; + DRV(xencons_driver)->minor_start = 64 + xc_num; + DRV(xencons_driver)->name_base = 0 + xc_num; + } + else + { + DRV(xencons_driver)->name = "tty"; + DRV(xencons_driver)->minor_start = xc_num; + DRV(xencons_driver)->name_base = xc_num; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + tty_set_operations(xencons_driver, &xencons_ops); +#else + xencons_driver.open = xencons_open; + xencons_driver.close = xencons_close; + xencons_driver.write = xencons_write; + xencons_driver.write_room = xencons_write_room; + xencons_driver.put_char = xencons_put_char; + xencons_driver.flush_chars = xencons_flush_chars; + xencons_driver.chars_in_buffer = xencons_chars_in_buffer; + xencons_driver.send_xchar = xencons_send_xchar; + xencons_driver.flush_buffer = xencons_flush_buffer; + xencons_driver.throttle = xencons_throttle; + xencons_driver.unthrottle = xencons_unthrottle; + xencons_driver.wait_until_sent = xencons_wait_until_sent; +#endif + + if ( (rc = tty_register_driver(DRV(xencons_driver))) != 0 ) + { + printk("WARNING: Failed to register Xen virtual " + "console driver as '%s%d'\n", + DRV(xencons_driver)->name, DRV(xencons_driver)->name_base); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + put_tty_driver(xencons_driver); + xencons_driver = NULL; +#endif + return rc; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + tty_register_device(xencons_driver, 0, NULL); +#endif + + if ( xen_start_info.flags & SIF_INITDOMAIN ) + { + xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE); + (void)request_irq(xencons_priv_irq, + xencons_priv_interrupt, 0, "console", NULL); + } + else + { + (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0); + } + + printk("Xen virtual console successfully installed as %s%d\n", + DRV(xencons_driver)->name, + DRV(xencons_driver)->name_base ); + + return 0; +} + +module_init(xencons_init); diff --git a/drivers/xen/evtchn/Makefile b/drivers/xen/evtchn/Makefile new file mode 100644 index 000000000..7b082a081 --- /dev/null +++ b/drivers/xen/evtchn/Makefile @@ -0,0 +1,2 @@ + +obj-y := evtchn.o diff --git a/drivers/xen/evtchn/evtchn.c b/drivers/xen/evtchn/evtchn.c new file mode 100644 index 000000000..f5da4283d --- /dev/null +++ b/drivers/xen/evtchn/evtchn.c @@ -0,0 +1,430 @@ +/****************************************************************************** + * evtchn.c + * + * Xenolinux driver for receiving and demuxing event-channel signals. + * + * Copyright (c) 2004, K A Fraser + * Multi-process extensions Copyright (c) 2004, Steven Smith + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define XEN_EVTCHN_MASK_OPS +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#include +#define OLD_DEVFS +#else +#include +#endif + +#ifdef OLD_DEVFS +/* NB. This must be shared amongst drivers if more things go in /dev/xen */ +static devfs_handle_t xen_dev_dir; +#endif + +struct per_user_data { + /* Notification ring, accessed via /dev/xen/evtchn. */ +# define EVTCHN_RING_SIZE 2048 /* 2048 16-bit entries */ +# define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1)) + u16 *ring; + unsigned int ring_cons, ring_prod, ring_overflow; + + /* Processes wait on this queue when ring is empty. */ + wait_queue_head_t evtchn_wait; + struct fasync_struct *evtchn_async_queue; +}; + +/* Who's bound to each port? */ +static struct per_user_data *port_user[NR_EVENT_CHANNELS]; +static spinlock_t port_user_lock; + +void evtchn_device_upcall(int port) +{ + struct per_user_data *u; + + spin_lock(&port_user_lock); + + mask_evtchn(port); + clear_evtchn(port); + + if ( (u = port_user[port]) != NULL ) + { + if ( (u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE ) + { + u->ring[EVTCHN_RING_MASK(u->ring_prod)] = (u16)port; + if ( u->ring_cons == u->ring_prod++ ) + { + wake_up_interruptible(&u->evtchn_wait); + kill_fasync(&u->evtchn_async_queue, SIGIO, POLL_IN); + } + } + else + { + u->ring_overflow = 1; + } + } + + spin_unlock(&port_user_lock); +} + +static ssize_t evtchn_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + int rc; + unsigned int c, p, bytes1 = 0, bytes2 = 0; + DECLARE_WAITQUEUE(wait, current); + struct per_user_data *u = file->private_data; + + add_wait_queue(&u->evtchn_wait, &wait); + + count &= ~1; /* even number of bytes */ + + if ( count == 0 ) + { + rc = 0; + goto out; + } + + if ( count > PAGE_SIZE ) + count = PAGE_SIZE; + + for ( ; ; ) + { + set_current_state(TASK_INTERRUPTIBLE); + + if ( (c = u->ring_cons) != (p = u->ring_prod) ) + break; + + if ( u->ring_overflow ) + { + rc = -EFBIG; + goto out; + } + + if ( file->f_flags & O_NONBLOCK ) + { + rc = -EAGAIN; + goto out; + } + + if ( signal_pending(current) ) + { + rc = -ERESTARTSYS; + goto out; + } + + schedule(); + } + + /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */ + if ( ((c ^ p) & EVTCHN_RING_SIZE) != 0 ) + { + bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * sizeof(u16); + bytes2 = EVTCHN_RING_MASK(p) * sizeof(u16); + } + else + { + bytes1 = (p - c) * sizeof(u16); + bytes2 = 0; + } + + /* Truncate chunks according to caller's maximum byte count. */ + if ( bytes1 > count ) + { + bytes1 = count; + bytes2 = 0; + } + else if ( (bytes1 + bytes2) > count ) + { + bytes2 = count - bytes1; + } + + if ( copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) || + ((bytes2 != 0) && copy_to_user(&buf[bytes1], &u->ring[0], bytes2)) ) + { + rc = -EFAULT; + goto out; + } + + u->ring_cons += (bytes1 + bytes2) / sizeof(u16); + + rc = bytes1 + bytes2; + + out: + __set_current_state(TASK_RUNNING); + remove_wait_queue(&u->evtchn_wait, &wait); + return rc; +} + +static ssize_t evtchn_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + int rc, i; + u16 *kbuf = (u16 *)__get_free_page(GFP_KERNEL); + struct per_user_data *u = file->private_data; + + if ( kbuf == NULL ) + return -ENOMEM; + + count &= ~1; /* even number of bytes */ + + if ( count == 0 ) + { + rc = 0; + goto out; + } + + if ( count > PAGE_SIZE ) + count = PAGE_SIZE; + + if ( copy_from_user(kbuf, buf, count) != 0 ) + { + rc = -EFAULT; + goto out; + } + + spin_lock_irq(&port_user_lock); + for ( i = 0; i < (count/2); i++ ) + if ( (kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u) ) + unmask_evtchn(kbuf[i]); + spin_unlock_irq(&port_user_lock); + + rc = count; + + out: + free_page((unsigned long)kbuf); + return rc; +} + +static int evtchn_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int rc = 0; + struct per_user_data *u = file->private_data; + + spin_lock_irq(&port_user_lock); + + switch ( cmd ) + { + case EVTCHN_RESET: + /* Initialise the ring to empty. Clear errors. */ + u->ring_cons = u->ring_prod = u->ring_overflow = 0; + break; + + case EVTCHN_BIND: + if ( arg >= NR_EVENT_CHANNELS ) + { + rc = -EINVAL; + } + else if ( port_user[arg] != NULL ) + { + rc = -EISCONN; + } + else + { + port_user[arg] = u; + unmask_evtchn(arg); + } + break; + + case EVTCHN_UNBIND: + if ( arg >= NR_EVENT_CHANNELS ) + { + rc = -EINVAL; + } + else if ( port_user[arg] != u ) + { + rc = -ENOTCONN; + } + else + { + port_user[arg] = NULL; + mask_evtchn(arg); + } + break; + + default: + rc = -ENOSYS; + break; + } + + spin_unlock_irq(&port_user_lock); + + return rc; +} + +static unsigned int evtchn_poll(struct file *file, poll_table *wait) +{ + unsigned int mask = POLLOUT | POLLWRNORM; + struct per_user_data *u = file->private_data; + + poll_wait(file, &u->evtchn_wait, wait); + if ( u->ring_cons != u->ring_prod ) + mask |= POLLIN | POLLRDNORM; + if ( u->ring_overflow ) + mask = POLLERR; + return mask; +} + +static int evtchn_fasync(int fd, struct file *filp, int on) +{ + struct per_user_data *u = filp->private_data; + return fasync_helper(fd, filp, on, &u->evtchn_async_queue); +} + +static int evtchn_open(struct inode *inode, struct file *filp) +{ + struct per_user_data *u; + + if ( (u = kmalloc(sizeof(*u), GFP_KERNEL)) == NULL ) + return -ENOMEM; + + memset(u, 0, sizeof(*u)); + init_waitqueue_head(&u->evtchn_wait); + + if ( (u->ring = (u16 *)__get_free_page(GFP_KERNEL)) == NULL ) + { + kfree(u); + return -ENOMEM; + } + + filp->private_data = u; + + return 0; +} + +static int evtchn_release(struct inode *inode, struct file *filp) +{ + int i; + struct per_user_data *u = filp->private_data; + + spin_lock_irq(&port_user_lock); + + free_page((unsigned long)u->ring); + + for ( i = 0; i < NR_EVENT_CHANNELS; i++ ) + { + if ( port_user[i] == u ) + { + port_user[i] = NULL; + mask_evtchn(i); + } + } + + spin_unlock_irq(&port_user_lock); + + return 0; +} + +static struct file_operations evtchn_fops = { + owner: THIS_MODULE, + read: evtchn_read, + write: evtchn_write, + ioctl: evtchn_ioctl, + poll: evtchn_poll, + fasync: evtchn_fasync, + open: evtchn_open, + release: evtchn_release +}; + +static struct miscdevice evtchn_miscdev = { + .minor = EVTCHN_MINOR, + .name = "evtchn", + .fops = &evtchn_fops, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .devfs_name = "misc/evtchn", +#endif +}; + +static int __init evtchn_init(void) +{ +#ifdef OLD_DEVFS + devfs_handle_t symlink_handle; + int pos; + char link_dest[64]; +#endif + int err; + + spin_lock_init(&port_user_lock); + memset(port_user, 0, sizeof(port_user)); + + /* (DEVFS) create '/dev/misc/evtchn'. */ + err = misc_register(&evtchn_miscdev); + if ( err != 0 ) + { + printk(KERN_ALERT "Could not register /dev/misc/evtchn\n"); + return err; + } + +#ifdef OLD_DEVFS + /* (DEVFS) create directory '/dev/xen'. */ + xen_dev_dir = devfs_mk_dir(NULL, "xen", NULL); + + /* (DEVFS) &link_dest[pos] == '../misc/evtchn'. */ + pos = devfs_generate_path(evtchn_miscdev.devfs_handle, + &link_dest[3], + sizeof(link_dest) - 3); + if ( pos >= 0 ) + strncpy(&link_dest[pos], "../", 3); + + /* (DEVFS) symlink '/dev/xen/evtchn' -> '../misc/evtchn'. */ + (void)devfs_mk_symlink(xen_dev_dir, + "evtchn", + DEVFS_FL_DEFAULT, + &link_dest[pos], + &symlink_handle, + NULL); + + /* (DEVFS) automatically destroy the symlink with its destination. */ + devfs_auto_unregister(evtchn_miscdev.devfs_handle, symlink_handle); +#endif + + printk("Event-channel device installed.\n"); + + return 0; +} + +static void evtchn_cleanup(void) +{ + misc_deregister(&evtchn_miscdev); +} + +module_init(evtchn_init); +module_exit(evtchn_cleanup); diff --git a/drivers/xen/netback/Makefile b/drivers/xen/netback/Makefile new file mode 100644 index 000000000..327944214 --- /dev/null +++ b/drivers/xen/netback/Makefile @@ -0,0 +1,2 @@ + +obj-y := netback.o control.o interface.o diff --git a/drivers/xen/netback/common.h b/drivers/xen/netback/common.h new file mode 100644 index 000000000..dfb750ee3 --- /dev/null +++ b/drivers/xen/netback/common.h @@ -0,0 +1,103 @@ +/****************************************************************************** + * arch/xen/drivers/netif/backend/common.h + */ + +#ifndef __NETIF__BACKEND__COMMON_H__ +#define __NETIF__BACKEND__COMMON_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define ASSERT(_p) \ + if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \ + __LINE__, __FILE__); *(int*)0=0; } +#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \ + __FILE__ , __LINE__ , ## _a ) +#else +#define ASSERT(_p) ((void)0) +#define DPRINTK(_f, _a...) ((void)0) +#endif + +typedef struct netif_st { + /* Unique identifier for this interface. */ + domid_t domid; + unsigned int handle; + + u8 fe_dev_addr[6]; + + /* Physical parameters of the comms window. */ + unsigned long tx_shmem_frame; + unsigned long rx_shmem_frame; + unsigned int evtchn; + int irq; + + /* The shared rings and indexes. */ + netif_tx_interface_t *tx; + netif_rx_interface_t *rx; + + /* Private indexes into shared ring. */ + NETIF_RING_IDX rx_req_cons; + NETIF_RING_IDX rx_resp_prod; /* private version of shared variable */ + NETIF_RING_IDX tx_req_cons; + NETIF_RING_IDX tx_resp_prod; /* private version of shared variable */ + + /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */ + unsigned long credit_bytes; + unsigned long credit_usec; + unsigned long remaining_credit; + struct timer_list credit_timeout; + + /* Miscellaneous private stuff. */ + enum { DISCONNECTED, DISCONNECTING, CONNECTED } status; + int active; + /* + * DISCONNECT response is deferred until pending requests are ack'ed. + * We therefore need to store the id from the original request. + */ + u8 disconnect_rspid; + struct netif_st *hash_next; + struct list_head list; /* scheduling list */ + atomic_t refcnt; + struct net_device *dev; + struct net_device_stats stats; + + struct work_struct work; +} netif_t; + +void netif_create(netif_be_create_t *create); +void netif_destroy(netif_be_destroy_t *destroy); +void netif_creditlimit(netif_be_creditlimit_t *creditlimit); +void netif_connect(netif_be_connect_t *connect); +int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id); +void netif_disconnect_complete(netif_t *netif); +netif_t *netif_find_by_handle(domid_t domid, unsigned int handle); +#define netif_get(_b) (atomic_inc(&(_b)->refcnt)) +#define netif_put(_b) \ + do { \ + if ( atomic_dec_and_test(&(_b)->refcnt) ) \ + netif_disconnect_complete(_b); \ + } while (0) + +void netif_interface_init(void); +void netif_ctrlif_init(void); + +void netif_schedule_work(netif_t *netif); +void netif_deschedule_work(netif_t *netif); + +int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev); +struct net_device_stats *netif_be_get_stats(struct net_device *dev); +irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs); + +#endif /* __NETIF__BACKEND__COMMON_H__ */ diff --git a/drivers/xen/netback/interface.c b/drivers/xen/netback/interface.c new file mode 100644 index 000000000..f509a1b8d --- /dev/null +++ b/drivers/xen/netback/interface.c @@ -0,0 +1,380 @@ +/****************************************************************************** + * arch/xen/drivers/netif/backend/interface.c + * + * Network-device interface management. + * + * Copyright (c) 2004-2005, Keir Fraser + */ + +#include "common.h" +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#endif + +#define NETIF_HASHSZ 1024 +#define NETIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(NETIF_HASHSZ-1)) + +static netif_t *netif_hash[NETIF_HASHSZ]; + +netif_t *netif_find_by_handle(domid_t domid, unsigned int handle) +{ + netif_t *netif = netif_hash[NETIF_HASH(domid, handle)]; + while ( (netif != NULL) && + ((netif->domid != domid) || (netif->handle != handle)) ) + netif = netif->hash_next; + return netif; +} + +static void __netif_up(netif_t *netif) +{ + struct net_device *dev = netif->dev; + spin_lock_bh(&dev->xmit_lock); + netif->active = 1; + spin_unlock_bh(&dev->xmit_lock); + (void)request_irq(netif->irq, netif_be_int, 0, dev->name, netif); + netif_schedule_work(netif); +} + +static void __netif_down(netif_t *netif) +{ + struct net_device *dev = netif->dev; + spin_lock_bh(&dev->xmit_lock); + netif->active = 0; + spin_unlock_bh(&dev->xmit_lock); + free_irq(netif->irq, netif); + netif_deschedule_work(netif); +} + +static int net_open(struct net_device *dev) +{ + netif_t *netif = netdev_priv(dev); + if ( netif->status == CONNECTED ) + __netif_up(netif); + netif_start_queue(dev); + return 0; +} + +static int net_close(struct net_device *dev) +{ + netif_t *netif = netdev_priv(dev); + netif_stop_queue(dev); + if ( netif->status == CONNECTED ) + __netif_down(netif); + return 0; +} + +static void __netif_disconnect_complete(void *arg) +{ + netif_t *netif = (netif_t *)arg; + ctrl_msg_t cmsg; + netif_be_disconnect_t disc; + + /* + * These can't be done in netif_disconnect() because at that point there + * may be outstanding requests in the network stack whose asynchronous + * responses must still be notified to the remote driver. + */ + unbind_evtchn_from_irq(netif->evtchn); + vfree(netif->tx); /* Frees netif->rx as well. */ + + /* Construct the deferred response message. */ + cmsg.type = CMSG_NETIF_BE; + cmsg.subtype = CMSG_NETIF_BE_DISCONNECT; + cmsg.id = netif->disconnect_rspid; + cmsg.length = sizeof(netif_be_disconnect_t); + disc.domid = netif->domid; + disc.netif_handle = netif->handle; + disc.status = NETIF_BE_STATUS_OKAY; + memcpy(cmsg.msg, &disc, sizeof(disc)); + + /* + * Make sure message is constructed /before/ status change, because + * after the status change the 'netif' structure could be deallocated at + * any time. Also make sure we send the response /after/ status change, + * as otherwise a subsequent CONNECT request could spuriously fail if + * another CPU doesn't see the status change yet. + */ + mb(); + if ( netif->status != DISCONNECTING ) + BUG(); + netif->status = DISCONNECTED; + mb(); + + /* Send the successful response. */ + ctrl_if_send_response(&cmsg); +} + +void netif_disconnect_complete(netif_t *netif) +{ + INIT_WORK(&netif->work, __netif_disconnect_complete, (void *)netif); + schedule_work(&netif->work); +} + +void netif_create(netif_be_create_t *create) +{ + int err = 0; + domid_t domid = create->domid; + unsigned int handle = create->netif_handle; + struct net_device *dev; + netif_t **pnetif, *netif; + char name[IFNAMSIZ] = {}; + + snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle); + dev = alloc_netdev(sizeof(netif_t), name, ether_setup); + if ( dev == NULL ) + { + DPRINTK("Could not create netif: out of memory\n"); + create->status = NETIF_BE_STATUS_OUT_OF_MEMORY; + return; + } + + netif = netdev_priv(dev); + memset(netif, 0, sizeof(*netif)); + netif->domid = domid; + netif->handle = handle; + netif->status = DISCONNECTED; + atomic_set(&netif->refcnt, 0); + netif->dev = dev; + + netif->credit_bytes = netif->remaining_credit = ~0UL; + netif->credit_usec = 0UL; + init_timer(&netif->credit_timeout); + + pnetif = &netif_hash[NETIF_HASH(domid, handle)]; + while ( *pnetif != NULL ) + { + if ( ((*pnetif)->domid == domid) && ((*pnetif)->handle == handle) ) + { + DPRINTK("Could not create netif: already exists\n"); + create->status = NETIF_BE_STATUS_INTERFACE_EXISTS; + free_netdev(dev); + return; + } + pnetif = &(*pnetif)->hash_next; + } + + dev->hard_start_xmit = netif_be_start_xmit; + dev->get_stats = netif_be_get_stats; + dev->open = net_open; + dev->stop = net_close; + + /* Disable queuing. */ + dev->tx_queue_len = 0; + + if ( (create->be_mac[0] == 0) && (create->be_mac[1] == 0) && + (create->be_mac[2] == 0) && (create->be_mac[3] == 0) && + (create->be_mac[4] == 0) && (create->be_mac[5] == 0) ) + { + /* + * Initialise a dummy MAC address. We choose the numerically largest + * non-broadcast address to prevent the address getting stolen by an + * Ethernet bridge for STP purposes. (FE:FF:FF:FF:FF:FF) + */ + memset(dev->dev_addr, 0xFF, ETH_ALEN); + dev->dev_addr[0] &= ~0x01; + } + else + { + memcpy(dev->dev_addr, create->be_mac, ETH_ALEN); + } + + memcpy(netif->fe_dev_addr, create->mac, ETH_ALEN); + + rtnl_lock(); + err = register_netdevice(dev); + rtnl_unlock(); + + if ( err != 0 ) + { + DPRINTK("Could not register new net device %s: err=%d\n", + dev->name, err); + create->status = NETIF_BE_STATUS_OUT_OF_MEMORY; + free_netdev(dev); + return; + } + + netif->hash_next = *pnetif; + *pnetif = netif; + + DPRINTK("Successfully created netif\n"); + create->status = NETIF_BE_STATUS_OKAY; +} + +void netif_destroy(netif_be_destroy_t *destroy) +{ + domid_t domid = destroy->domid; + unsigned int handle = destroy->netif_handle; + netif_t **pnetif, *netif; + + pnetif = &netif_hash[NETIF_HASH(domid, handle)]; + while ( (netif = *pnetif) != NULL ) + { + if ( (netif->domid == domid) && (netif->handle == handle) ) + { + if ( netif->status != DISCONNECTED ) + goto still_connected; + goto destroy; + } + pnetif = &netif->hash_next; + } + + destroy->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND; + return; + + still_connected: + destroy->status = NETIF_BE_STATUS_INTERFACE_CONNECTED; + return; + + destroy: + *pnetif = netif->hash_next; + unregister_netdev(netif->dev); + free_netdev(netif->dev); + destroy->status = NETIF_BE_STATUS_OKAY; +} + +void netif_creditlimit(netif_be_creditlimit_t *creditlimit) +{ + domid_t domid = creditlimit->domid; + unsigned int handle = creditlimit->netif_handle; + netif_t *netif; + + netif = netif_find_by_handle(domid, handle); + if ( unlikely(netif == NULL) ) + { + DPRINTK("netif_creditlimit attempted for non-existent netif" + " (%u,%u)\n", creditlimit->domid, creditlimit->netif_handle); + creditlimit->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND; + return; + } + + /* Set the credit limit (reset remaining credit to new limit). */ + netif->credit_bytes = netif->remaining_credit = creditlimit->credit_bytes; + netif->credit_usec = creditlimit->period_usec; + + if ( netif->status == CONNECTED ) + { + /* + * Schedule work so that any packets waiting under previous credit + * limit are dealt with (acts like a replenishment point). + */ + netif->credit_timeout.expires = jiffies; + netif_schedule_work(netif); + } + + creditlimit->status = NETIF_BE_STATUS_OKAY; +} + +void netif_connect(netif_be_connect_t *connect) +{ + domid_t domid = connect->domid; + unsigned int handle = connect->netif_handle; + unsigned int evtchn = connect->evtchn; + unsigned long tx_shmem_frame = connect->tx_shmem_frame; + unsigned long rx_shmem_frame = connect->rx_shmem_frame; + struct vm_struct *vma; + pgprot_t prot; + int error; + netif_t *netif; + + netif = netif_find_by_handle(domid, handle); + if ( unlikely(netif == NULL) ) + { + DPRINTK("netif_connect attempted for non-existent netif (%u,%u)\n", + connect->domid, connect->netif_handle); + connect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND; + return; + } + + if ( netif->status != DISCONNECTED ) + { + connect->status = NETIF_BE_STATUS_INTERFACE_CONNECTED; + return; + } + + if ( (vma = get_vm_area(2*PAGE_SIZE, VM_IOREMAP)) == NULL ) + { + connect->status = NETIF_BE_STATUS_OUT_OF_MEMORY; + return; + } + + prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED); + error = direct_remap_area_pages(&init_mm, + VMALLOC_VMADDR(vma->addr), + tx_shmem_frame<addr) + PAGE_SIZE, + rx_shmem_frame<status = NETIF_BE_STATUS_OUT_OF_MEMORY; + else if ( error == -EFAULT ) + connect->status = NETIF_BE_STATUS_MAPPING_ERROR; + else + connect->status = NETIF_BE_STATUS_ERROR; + vfree(vma->addr); + return; + } + + netif->evtchn = evtchn; + netif->irq = bind_evtchn_to_irq(evtchn); + netif->tx_shmem_frame = tx_shmem_frame; + netif->rx_shmem_frame = rx_shmem_frame; + netif->tx = + (netif_tx_interface_t *)vma->addr; + netif->rx = + (netif_rx_interface_t *)((char *)vma->addr + PAGE_SIZE); + netif->tx->resp_prod = netif->rx->resp_prod = 0; + netif_get(netif); + wmb(); /* Other CPUs see new state before interface is started. */ + + rtnl_lock(); + netif->status = CONNECTED; + wmb(); + if ( netif_running(netif->dev) ) + __netif_up(netif); + rtnl_unlock(); + + connect->status = NETIF_BE_STATUS_OKAY; +} + +int netif_disconnect(netif_be_disconnect_t *disconnect, u8 rsp_id) +{ + domid_t domid = disconnect->domid; + unsigned int handle = disconnect->netif_handle; + netif_t *netif; + + netif = netif_find_by_handle(domid, handle); + if ( unlikely(netif == NULL) ) + { + DPRINTK("netif_disconnect attempted for non-existent netif" + " (%u,%u)\n", disconnect->domid, disconnect->netif_handle); + disconnect->status = NETIF_BE_STATUS_INTERFACE_NOT_FOUND; + return 1; /* Caller will send response error message. */ + } + + if ( netif->status == CONNECTED ) + { + rtnl_lock(); + netif->status = DISCONNECTING; + netif->disconnect_rspid = rsp_id; + wmb(); + if ( netif_running(netif->dev) ) + __netif_down(netif); + rtnl_unlock(); + netif_put(netif); + return 0; /* Caller should not send response message. */ + } + + disconnect->status = NETIF_BE_STATUS_OKAY; + return 1; +} + +void netif_interface_init(void) +{ + memset(netif_hash, 0, sizeof(netif_hash)); +} diff --git a/drivers/xen/netback/netback.c b/drivers/xen/netback/netback.c new file mode 100644 index 000000000..d08c296a0 --- /dev/null +++ b/drivers/xen/netback/netback.c @@ -0,0 +1,819 @@ +/****************************************************************************** + * drivers/xen/netback/netback.c + * + * Back-end of the driver for virtual network devices. This portion of the + * driver exports a 'unified' network-device interface that can be accessed + * by any operating system that implements a compatible front end. A + * reference front-end implementation can be found in: + * drivers/xen/netfront/netfront.c + * + * Copyright (c) 2002-2005, K A Fraser + */ + +#include "common.h" +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#include +#endif + +static void netif_idx_release(u16 pending_idx); +static void netif_page_release(struct page *page); +static void make_tx_response(netif_t *netif, + u16 id, + s8 st); +static int make_rx_response(netif_t *netif, + u16 id, + s8 st, + memory_t addr, + u16 size); + +static void net_tx_action(unsigned long unused); +static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0); + +static void net_rx_action(unsigned long unused); +static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0); + +static struct timer_list net_timer; + +static struct sk_buff_head rx_queue; +static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE*2+1]; +static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE]; +static struct mmuext_op rx_mmuext[NETIF_RX_RING_SIZE]; +static unsigned char rx_notify[NR_EVENT_CHANNELS]; + +/* Don't currently gate addition of an interface to the tx scheduling list. */ +#define tx_work_exists(_if) (1) + +#define MAX_PENDING_REQS 256 +static unsigned long mmap_vstart; +#define MMAP_VADDR(_req) (mmap_vstart + ((_req) * PAGE_SIZE)) + +#define PKT_PROT_LEN 64 + +static struct { + netif_tx_request_t req; + netif_t *netif; +} pending_tx_info[MAX_PENDING_REQS]; +static u16 pending_ring[MAX_PENDING_REQS]; +typedef unsigned int PEND_RING_IDX; +#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1)) +static PEND_RING_IDX pending_prod, pending_cons; +#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons) + +/* Freed TX SKBs get batched on this ring before return to pending_ring. */ +static u16 dealloc_ring[MAX_PENDING_REQS]; +static PEND_RING_IDX dealloc_prod, dealloc_cons; + +static struct sk_buff_head tx_queue; +static multicall_entry_t tx_mcl[MAX_PENDING_REQS]; + +static struct list_head net_schedule_list; +static spinlock_t net_schedule_list_lock; + +#define MAX_MFN_ALLOC 64 +static unsigned long mfn_list[MAX_MFN_ALLOC]; +static unsigned int alloc_index = 0; +static spinlock_t mfn_lock = SPIN_LOCK_UNLOCKED; + +static unsigned long alloc_mfn(void) +{ + unsigned long mfn = 0, flags; + spin_lock_irqsave(&mfn_lock, flags); + if ( unlikely(alloc_index == 0) ) + alloc_index = HYPERVISOR_dom_mem_op( + MEMOP_increase_reservation, mfn_list, MAX_MFN_ALLOC, 0); + if ( alloc_index != 0 ) + mfn = mfn_list[--alloc_index]; + spin_unlock_irqrestore(&mfn_lock, flags); + return mfn; +} + +static void free_mfn(unsigned long mfn) +{ + unsigned long flags; + spin_lock_irqsave(&mfn_lock, flags); + if ( alloc_index != MAX_MFN_ALLOC ) + mfn_list[alloc_index++] = mfn; + else if ( HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation, + &mfn, 1, 0) != 1 ) + BUG(); + spin_unlock_irqrestore(&mfn_lock, flags); +} + +static inline void maybe_schedule_tx_action(void) +{ + smp_mb(); + if ( (NR_PENDING_REQS < (MAX_PENDING_REQS/2)) && + !list_empty(&net_schedule_list) ) + tasklet_schedule(&net_tx_tasklet); +} + +/* + * A gross way of confirming the origin of an skb data page. The slab + * allocator abuses a field in the page struct to cache the kmem_cache_t ptr. + */ +static inline int is_xen_skb(struct sk_buff *skb) +{ + extern kmem_cache_t *skbuff_cachep; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + kmem_cache_t *cp = (kmem_cache_t *)virt_to_page(skb->head)->lru.next; +#else + kmem_cache_t *cp = (kmem_cache_t *)virt_to_page(skb->head)->list.next; +#endif + return (cp == skbuff_cachep); +} + +int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + netif_t *netif = netdev_priv(dev); + + ASSERT(skb->dev == dev); + + /* Drop the packet if the target domain has no receive buffers. */ + if ( !netif->active || + (netif->rx_req_cons == netif->rx->req_prod) || + ((netif->rx_req_cons-netif->rx_resp_prod) == NETIF_RX_RING_SIZE) ) + goto drop; + + /* + * We do not copy the packet unless: + * 1. The data is shared; or + * 2. The data is not allocated from our special cache. + * NB. We also couldn't cope with fragmented packets, but we won't get + * any because we not advertise the NETIF_F_SG feature. + */ + if ( skb_shared(skb) || skb_cloned(skb) || !is_xen_skb(skb) ) + { + int hlen = skb->data - skb->head; + struct sk_buff *nskb = dev_alloc_skb(hlen + skb->len); + if ( unlikely(nskb == NULL) ) + goto drop; + skb_reserve(nskb, hlen); + __skb_put(nskb, skb->len); + (void)skb_copy_bits(skb, -hlen, nskb->data - hlen, skb->len + hlen); + nskb->dev = skb->dev; + dev_kfree_skb(skb); + skb = nskb; + } + + netif->rx_req_cons++; + netif_get(netif); + + skb_queue_tail(&rx_queue, skb); + tasklet_schedule(&net_rx_tasklet); + + return 0; + + drop: + netif->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; +} + +#if 0 +static void xen_network_done_notify(void) +{ + static struct net_device *eth0_dev = NULL; + if ( unlikely(eth0_dev == NULL) ) + eth0_dev = __dev_get_by_name("eth0"); + netif_rx_schedule(eth0_dev); +} +/* + * Add following to poll() function in NAPI driver (Tigon3 is example): + * if ( xen_network_done() ) + * tg3_enable_ints(tp); + */ +int xen_network_done(void) +{ + return skb_queue_empty(&rx_queue); +} +#endif + +static void net_rx_action(unsigned long unused) +{ + netif_t *netif; + s8 status; + u16 size, id, evtchn; + multicall_entry_t *mcl; + mmu_update_t *mmu; + struct mmuext_op *mmuext; + unsigned long vdata, mdata, new_mfn; + struct sk_buff_head rxq; + struct sk_buff *skb; + u16 notify_list[NETIF_RX_RING_SIZE]; + int notify_nr = 0; + + skb_queue_head_init(&rxq); + + mcl = rx_mcl; + mmu = rx_mmu; + mmuext = rx_mmuext; + while ( (skb = skb_dequeue(&rx_queue)) != NULL ) + { + netif = netdev_priv(skb->dev); + vdata = (unsigned long)skb->data; + mdata = virt_to_machine(vdata); + + /* Memory squeeze? Back off for an arbitrary while. */ + if ( (new_mfn = alloc_mfn()) == 0 ) + { + if ( net_ratelimit() ) + printk(KERN_WARNING "Memory squeeze in netback driver.\n"); + mod_timer(&net_timer, jiffies + HZ); + skb_queue_head(&rx_queue, skb); + break; + } + + /* + * Set the new P2M table entry before reassigning the old data page. + * Heed the comment in pgtable-2level.h:pte_page(). :-) + */ + phys_to_machine_mapping[__pa(skb->data) >> PAGE_SHIFT] = new_mfn; + + mcl->op = __HYPERVISOR_update_va_mapping; + mcl->args[0] = vdata; + mcl->args[1] = (new_mfn << PAGE_SHIFT) | __PAGE_KERNEL; + mcl->args[2] = 0; + mcl++; + + mcl->op = __HYPERVISOR_mmuext_op; + mcl->args[0] = (unsigned long)mmuext; + mcl->args[1] = 1; + mcl->args[2] = 0; + mcl->args[3] = netif->domid; + mcl++; + + mmuext->cmd = MMUEXT_REASSIGN_PAGE; + mmuext->mfn = mdata >> PAGE_SHIFT; + mmuext++; + + mmu->ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE; + mmu->val = __pa(vdata) >> PAGE_SHIFT; + mmu++; + + __skb_queue_tail(&rxq, skb); + + /* Filled the batch queue? */ + if ( (mcl - rx_mcl) == ARRAY_SIZE(rx_mcl) ) + break; + } + + if ( mcl == rx_mcl ) + return; + + mcl->op = __HYPERVISOR_mmu_update; + mcl->args[0] = (unsigned long)rx_mmu; + mcl->args[1] = mmu - rx_mmu; + mcl->args[2] = 0; + mcl->args[3] = DOMID_SELF; + mcl++; + + mcl[-3].args[2] = UVMF_TLB_FLUSH|UVMF_ALL; + if ( unlikely(HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl) != 0) ) + BUG(); + + mcl = rx_mcl; + mmuext = rx_mmuext; + while ( (skb = __skb_dequeue(&rxq)) != NULL ) + { + netif = netdev_priv(skb->dev); + size = skb->tail - skb->data; + + /* Rederive the machine addresses. */ + new_mfn = mcl[0].args[1] >> PAGE_SHIFT; + mdata = ((mmuext[0].mfn << PAGE_SHIFT) | + ((unsigned long)skb->data & ~PAGE_MASK)); + + atomic_set(&(skb_shinfo(skb)->dataref), 1); + skb_shinfo(skb)->nr_frags = 0; + skb_shinfo(skb)->frag_list = NULL; + + netif->stats.tx_bytes += size; + netif->stats.tx_packets++; + + /* The update_va_mapping() must not fail. */ + if ( unlikely(mcl[0].args[5] != 0) ) + BUG(); + + /* Check the reassignment error code. */ + status = NETIF_RSP_OKAY; + if ( unlikely(mcl[1].args[5] != 0) ) + { + DPRINTK("Failed MMU update transferring to DOM%u\n", netif->domid); + free_mfn(mdata >> PAGE_SHIFT); + status = NETIF_RSP_ERROR; + } + + evtchn = netif->evtchn; + id = netif->rx->ring[MASK_NETIF_RX_IDX(netif->rx_resp_prod)].req.id; + if ( make_rx_response(netif, id, status, mdata, size) && + (rx_notify[evtchn] == 0) ) + { + rx_notify[evtchn] = 1; + notify_list[notify_nr++] = evtchn; + } + + netif_put(netif); + dev_kfree_skb(skb); + + mcl += 2; + mmuext += 1; + } + + while ( notify_nr != 0 ) + { + evtchn = notify_list[--notify_nr]; + rx_notify[evtchn] = 0; + notify_via_evtchn(evtchn); + } + + /* More work to do? */ + if ( !skb_queue_empty(&rx_queue) && !timer_pending(&net_timer) ) + tasklet_schedule(&net_rx_tasklet); +#if 0 + else + xen_network_done_notify(); +#endif +} + +static void net_alarm(unsigned long unused) +{ + tasklet_schedule(&net_rx_tasklet); +} + +struct net_device_stats *netif_be_get_stats(struct net_device *dev) +{ + netif_t *netif = netdev_priv(dev); + return &netif->stats; +} + +static int __on_net_schedule_list(netif_t *netif) +{ + return netif->list.next != NULL; +} + +static void remove_from_net_schedule_list(netif_t *netif) +{ + spin_lock_irq(&net_schedule_list_lock); + if ( likely(__on_net_schedule_list(netif)) ) + { + list_del(&netif->list); + netif->list.next = NULL; + netif_put(netif); + } + spin_unlock_irq(&net_schedule_list_lock); +} + +static void add_to_net_schedule_list_tail(netif_t *netif) +{ + if ( __on_net_schedule_list(netif) ) + return; + + spin_lock_irq(&net_schedule_list_lock); + if ( !__on_net_schedule_list(netif) && netif->active ) + { + list_add_tail(&netif->list, &net_schedule_list); + netif_get(netif); + } + spin_unlock_irq(&net_schedule_list_lock); +} + +void netif_schedule_work(netif_t *netif) +{ + if ( (netif->tx_req_cons != netif->tx->req_prod) && + ((netif->tx_req_cons-netif->tx_resp_prod) != NETIF_TX_RING_SIZE) ) + { + add_to_net_schedule_list_tail(netif); + maybe_schedule_tx_action(); + } +} + +void netif_deschedule_work(netif_t *netif) +{ + remove_from_net_schedule_list(netif); +} + + +static void tx_credit_callback(unsigned long data) +{ + netif_t *netif = (netif_t *)data; + netif->remaining_credit = netif->credit_bytes; + netif_schedule_work(netif); +} + +static void net_tx_action(unsigned long unused) +{ + struct list_head *ent; + struct sk_buff *skb; + netif_t *netif; + netif_tx_request_t txreq; + u16 pending_idx; + NETIF_RING_IDX i; + multicall_entry_t *mcl; + PEND_RING_IDX dc, dp; + unsigned int data_len; + + if ( (dc = dealloc_cons) == (dp = dealloc_prod) ) + goto skip_dealloc; + + mcl = tx_mcl; + while ( dc != dp ) + { + pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)]; + mcl[0].op = __HYPERVISOR_update_va_mapping; + mcl[0].args[0] = MMAP_VADDR(pending_idx); + mcl[0].args[1] = 0; + mcl[0].args[2] = 0; + mcl++; + } + + mcl[-1].args[2] = UVMF_TLB_FLUSH|UVMF_ALL; + if ( unlikely(HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl) != 0) ) + BUG(); + + mcl = tx_mcl; + while ( dealloc_cons != dp ) + { + /* The update_va_mapping() must not fail. */ + if ( unlikely(mcl[0].args[5] != 0) ) + BUG(); + + pending_idx = dealloc_ring[MASK_PEND_IDX(dealloc_cons++)]; + + netif = pending_tx_info[pending_idx].netif; + + make_tx_response(netif, pending_tx_info[pending_idx].req.id, + NETIF_RSP_OKAY); + + pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; + + /* + * Scheduling checks must happen after the above response is posted. + * This avoids a possible race with a guest OS on another CPU if that + * guest is testing against 'resp_prod' when deciding whether to notify + * us when it queues additional packets. + */ + mb(); + if ( (netif->tx_req_cons != netif->tx->req_prod) && + ((netif->tx_req_cons-netif->tx_resp_prod) != NETIF_TX_RING_SIZE) ) + add_to_net_schedule_list_tail(netif); + + netif_put(netif); + + mcl++; + } + + skip_dealloc: + mcl = tx_mcl; + while ( (NR_PENDING_REQS < MAX_PENDING_REQS) && + !list_empty(&net_schedule_list) ) + { + /* Get a netif from the list with work to do. */ + ent = net_schedule_list.next; + netif = list_entry(ent, netif_t, list); + netif_get(netif); + remove_from_net_schedule_list(netif); + + /* Work to do? */ + i = netif->tx_req_cons; + if ( (i == netif->tx->req_prod) || + ((i-netif->tx_resp_prod) == NETIF_TX_RING_SIZE) ) + { + netif_put(netif); + continue; + } + + rmb(); /* Ensure that we see the request before we copy it. */ + memcpy(&txreq, &netif->tx->ring[MASK_NETIF_TX_IDX(i)].req, + sizeof(txreq)); + + /* Credit-based scheduling. */ + if ( txreq.size > netif->remaining_credit ) + { + unsigned long now = jiffies; + unsigned long next_credit = + netif->credit_timeout.expires + + msecs_to_jiffies(netif->credit_usec / 1000); + + /* Timer could already be pending in some rare cases. */ + if ( timer_pending(&netif->credit_timeout) ) + break; + + /* Already passed the point at which we can replenish credit? */ + if ( time_after_eq(now, next_credit) ) + { + netif->credit_timeout.expires = now; + netif->remaining_credit = netif->credit_bytes; + } + + /* Still too big to send right now? Then set a timer callback. */ + if ( txreq.size > netif->remaining_credit ) + { + netif->remaining_credit = 0; + netif->credit_timeout.expires = next_credit; + netif->credit_timeout.data = (unsigned long)netif; + netif->credit_timeout.function = tx_credit_callback; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + add_timer_on(&netif->credit_timeout, smp_processor_id()); +#else + add_timer(&netif->credit_timeout); +#endif + break; + } + } + netif->remaining_credit -= txreq.size; + + /* + * Why the barrier? It ensures that the frontend sees updated req_cons + * before we check for more work to schedule. + */ + netif->tx->req_cons = ++netif->tx_req_cons; + mb(); + + netif_schedule_work(netif); + + if ( unlikely(txreq.size < ETH_HLEN) || + unlikely(txreq.size > ETH_FRAME_LEN) ) + { + DPRINTK("Bad packet size: %d\n", txreq.size); + make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); + netif_put(netif); + continue; + } + + /* No crossing a page boundary as the payload mustn't fragment. */ + if ( unlikely(((txreq.addr & ~PAGE_MASK) + txreq.size) >= PAGE_SIZE) ) + { + DPRINTK("txreq.addr: %lx, size: %u, end: %lu\n", + txreq.addr, txreq.size, + (txreq.addr &~PAGE_MASK) + txreq.size); + make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); + netif_put(netif); + continue; + } + + pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)]; + + data_len = (txreq.size > PKT_PROT_LEN) ? PKT_PROT_LEN : txreq.size; + + if ( unlikely((skb = alloc_skb(data_len+16, GFP_ATOMIC)) == NULL) ) + { + DPRINTK("Can't allocate a skb in start_xmit.\n"); + make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); + netif_put(netif); + break; + } + + /* Packets passed to netif_rx() must have some headroom. */ + skb_reserve(skb, 16); + + mcl[0].op = __HYPERVISOR_update_va_mapping_otherdomain; + mcl[0].args[0] = MMAP_VADDR(pending_idx); + mcl[0].args[1] = (txreq.addr & PAGE_MASK) | __PAGE_KERNEL; + mcl[0].args[2] = 0; + mcl[0].args[3] = netif->domid; + mcl++; + + memcpy(&pending_tx_info[pending_idx].req, &txreq, sizeof(txreq)); + pending_tx_info[pending_idx].netif = netif; + *((u16 *)skb->data) = pending_idx; + + __skb_queue_tail(&tx_queue, skb); + + pending_cons++; + + /* Filled the batch queue? */ + if ( (mcl - tx_mcl) == ARRAY_SIZE(tx_mcl) ) + break; + } + + if ( mcl == tx_mcl ) + return; + + if ( unlikely(HYPERVISOR_multicall(tx_mcl, mcl - tx_mcl) != 0) ) + BUG(); + + mcl = tx_mcl; + while ( (skb = __skb_dequeue(&tx_queue)) != NULL ) + { + pending_idx = *((u16 *)skb->data); + netif = pending_tx_info[pending_idx].netif; + memcpy(&txreq, &pending_tx_info[pending_idx].req, sizeof(txreq)); + + /* Check the remap error code. */ + if ( unlikely(mcl[0].args[5] != 0) ) + { + DPRINTK("Bad page frame\n"); + make_tx_response(netif, txreq.id, NETIF_RSP_ERROR); + netif_put(netif); + kfree_skb(skb); + mcl++; + pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx; + continue; + } + + phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx)) >> PAGE_SHIFT] = + FOREIGN_FRAME(txreq.addr >> PAGE_SHIFT); + + data_len = (txreq.size > PKT_PROT_LEN) ? PKT_PROT_LEN : txreq.size; + + __skb_put(skb, data_len); + memcpy(skb->data, + (void *)(MMAP_VADDR(pending_idx)|(txreq.addr&~PAGE_MASK)), + data_len); + + if ( data_len < txreq.size ) + { + /* Append the packet payload as a fragment. */ + skb_shinfo(skb)->frags[0].page = + virt_to_page(MMAP_VADDR(pending_idx)); + skb_shinfo(skb)->frags[0].size = txreq.size - data_len; + skb_shinfo(skb)->frags[0].page_offset = + (txreq.addr + data_len) & ~PAGE_MASK; + skb_shinfo(skb)->nr_frags = 1; + } + else + { + /* Schedule a response immediately. */ + netif_idx_release(pending_idx); + } + + skb->data_len = txreq.size - data_len; + skb->len += skb->data_len; + + skb->dev = netif->dev; + skb->protocol = eth_type_trans(skb, skb->dev); + + netif->stats.rx_bytes += txreq.size; + netif->stats.rx_packets++; + + netif_rx(skb); + netif->dev->last_rx = jiffies; + + mcl++; + } +} + +static void netif_idx_release(u16 pending_idx) +{ + static spinlock_t _lock = SPIN_LOCK_UNLOCKED; + unsigned long flags; + + spin_lock_irqsave(&_lock, flags); + dealloc_ring[MASK_PEND_IDX(dealloc_prod++)] = pending_idx; + spin_unlock_irqrestore(&_lock, flags); + + tasklet_schedule(&net_tx_tasklet); +} + +static void netif_page_release(struct page *page) +{ + u16 pending_idx = page - virt_to_page(mmap_vstart); + + /* Ready for next use. */ + set_page_count(page, 1); + + netif_idx_release(pending_idx); +} + +irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs) +{ + netif_t *netif = dev_id; + if ( tx_work_exists(netif) ) + { + add_to_net_schedule_list_tail(netif); + maybe_schedule_tx_action(); + } + return IRQ_HANDLED; +} + +static void make_tx_response(netif_t *netif, + u16 id, + s8 st) +{ + NETIF_RING_IDX i = netif->tx_resp_prod; + netif_tx_response_t *resp; + + resp = &netif->tx->ring[MASK_NETIF_TX_IDX(i)].resp; + resp->id = id; + resp->status = st; + wmb(); + netif->tx->resp_prod = netif->tx_resp_prod = ++i; + + mb(); /* Update producer before checking event threshold. */ + if ( i == netif->tx->event ) + notify_via_evtchn(netif->evtchn); +} + +static int make_rx_response(netif_t *netif, + u16 id, + s8 st, + memory_t addr, + u16 size) +{ + NETIF_RING_IDX i = netif->rx_resp_prod; + netif_rx_response_t *resp; + + resp = &netif->rx->ring[MASK_NETIF_RX_IDX(i)].resp; + resp->addr = addr; + resp->id = id; + resp->status = (s16)size; + if ( st < 0 ) + resp->status = (s16)st; + wmb(); + netif->rx->resp_prod = netif->rx_resp_prod = ++i; + + mb(); /* Update producer before checking event threshold. */ + return (i == netif->rx->event); +} + +static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs) +{ + struct list_head *ent; + netif_t *netif; + int i = 0; + + printk(KERN_ALERT "netif_schedule_list:\n"); + spin_lock_irq(&net_schedule_list_lock); + + list_for_each ( ent, &net_schedule_list ) + { + netif = list_entry(ent, netif_t, list); + printk(KERN_ALERT " %d: private(rx_req_cons=%08x rx_resp_prod=%08x\n", + i, netif->rx_req_cons, netif->rx_resp_prod); + printk(KERN_ALERT " tx_req_cons=%08x tx_resp_prod=%08x)\n", + netif->tx_req_cons, netif->tx_resp_prod); + printk(KERN_ALERT " shared(rx_req_prod=%08x rx_resp_prod=%08x\n", + netif->rx->req_prod, netif->rx->resp_prod); + printk(KERN_ALERT " rx_event=%08x tx_req_prod=%08x\n", + netif->rx->event, netif->tx->req_prod); + printk(KERN_ALERT " tx_resp_prod=%08x, tx_event=%08x)\n", + netif->tx->resp_prod, netif->tx->event); + i++; + } + + spin_unlock_irq(&net_schedule_list_lock); + printk(KERN_ALERT " ** End of netif_schedule_list **\n"); + + return IRQ_HANDLED; +} + +static int __init netback_init(void) +{ + int i; + struct page *page; + + if ( !(xen_start_info.flags & SIF_NET_BE_DOMAIN) && + !(xen_start_info.flags & SIF_INITDOMAIN) ) + return 0; + + printk("Initialising Xen netif backend\n"); + + /* We can increase reservation by this much in net_rx_action(). */ + balloon_update_driver_allowance(NETIF_RX_RING_SIZE); + + skb_queue_head_init(&rx_queue); + skb_queue_head_init(&tx_queue); + + init_timer(&net_timer); + net_timer.data = 0; + net_timer.function = net_alarm; + + netif_interface_init(); + + if ( (mmap_vstart = allocate_empty_lowmem_region(MAX_PENDING_REQS)) == 0 ) + BUG(); + + for ( i = 0; i < MAX_PENDING_REQS; i++ ) + { + page = virt_to_page(MMAP_VADDR(i)); + set_page_count(page, 1); + SetPageForeign(page, netif_page_release); + } + + pending_cons = 0; + pending_prod = MAX_PENDING_REQS; + for ( i = 0; i < MAX_PENDING_REQS; i++ ) + pending_ring[i] = i; + + spin_lock_init(&net_schedule_list_lock); + INIT_LIST_HEAD(&net_schedule_list); + + netif_ctrlif_init(); + + (void)request_irq(bind_virq_to_irq(VIRQ_DEBUG), + netif_be_dbg, SA_SHIRQ, + "net-be-dbg", &netif_be_dbg); + + return 0; +} + +static void netback_cleanup(void) +{ + BUG(); +} + +module_init(netback_init); +module_exit(netback_cleanup); diff --git a/drivers/xen/netfront/Kconfig b/drivers/xen/netfront/Kconfig new file mode 100644 index 000000000..334e6c386 --- /dev/null +++ b/drivers/xen/netfront/Kconfig @@ -0,0 +1,6 @@ + +config XENNET + tristate "Xen network driver" + depends on NETDEVICES && ARCH_XEN + help + Network driver for Xen diff --git a/drivers/xen/netfront/Makefile b/drivers/xen/netfront/Makefile new file mode 100644 index 000000000..7eb07a248 --- /dev/null +++ b/drivers/xen/netfront/Makefile @@ -0,0 +1,2 @@ + +obj-y := netfront.o diff --git a/drivers/xen/netfront/netfront.c b/drivers/xen/netfront/netfront.c new file mode 100644 index 000000000..f72929502 --- /dev/null +++ b/drivers/xen/netfront/netfront.c @@ -0,0 +1,1300 @@ +/****************************************************************************** + * Virtual network driver for conversing with remote driver backends. + * + * Copyright (c) 2002-2004, K A Fraser + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __GFP_NOWARN +#define __GFP_NOWARN 0 +#endif +#define alloc_xen_skb(_l) __dev_alloc_skb((_l), GFP_ATOMIC|__GFP_NOWARN) + +#define init_skb_shinfo(_skb) \ + do { \ + atomic_set(&(skb_shinfo(_skb)->dataref), 1); \ + skb_shinfo(_skb)->nr_frags = 0; \ + skb_shinfo(_skb)->frag_list = NULL; \ + } while (0) + +/* Allow headroom on each rx pkt for Ethernet header, alignment padding, ... */ +#define RX_HEADROOM 200 + +/* + * If the backend driver is pipelining transmit requests then we can be very + * aggressive in avoiding new-packet notifications -- only need to send a + * notification if there are no outstanding unreceived responses. + * If the backend may be buffering our transmit buffers for any reason then we + * are rather more conservative. + */ +#ifdef CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER +#define TX_TEST_IDX resp_prod /* aggressive: any outstanding responses? */ +#else +#define TX_TEST_IDX req_cons /* conservative: not seen all our requests? */ +#endif + +static void network_tx_buf_gc(struct net_device *dev); +static void network_alloc_rx_buffers(struct net_device *dev); + +static unsigned long rx_pfn_array[NETIF_RX_RING_SIZE]; +static multicall_entry_t rx_mcl[NETIF_RX_RING_SIZE+1]; +static mmu_update_t rx_mmu[NETIF_RX_RING_SIZE]; + +static struct list_head dev_list; + +struct net_private +{ + struct list_head list; + struct net_device *dev; + + struct net_device_stats stats; + NETIF_RING_IDX rx_resp_cons, tx_resp_cons; + unsigned int tx_full; + + netif_tx_interface_t *tx; + netif_rx_interface_t *rx; + + spinlock_t tx_lock; + spinlock_t rx_lock; + + unsigned int handle; + unsigned int evtchn; + unsigned int irq; + + /* What is the status of our connection to the remote backend? */ +#define BEST_CLOSED 0 +#define BEST_DISCONNECTED 1 +#define BEST_CONNECTED 2 + unsigned int backend_state; + + /* Is this interface open or closed (down or up)? */ +#define UST_CLOSED 0 +#define UST_OPEN 1 + unsigned int user_state; + + /* Receive-ring batched refills. */ +#define RX_MIN_TARGET 8 +#define RX_MAX_TARGET NETIF_RX_RING_SIZE + int rx_target; + struct sk_buff_head rx_batch; + + /* + * {tx,rx}_skbs store outstanding skbuffs. The first entry in each + * array is an index into a chain of free entries. + */ + struct sk_buff *tx_skbs[NETIF_TX_RING_SIZE+1]; + struct sk_buff *rx_skbs[NETIF_RX_RING_SIZE+1]; +}; + +/* Access macros for acquiring freeing slots in {tx,rx}_skbs[]. */ +#define ADD_ID_TO_FREELIST(_list, _id) \ + (_list)[(_id)] = (_list)[0]; \ + (_list)[0] = (void *)(unsigned long)(_id); +#define GET_ID_FROM_FREELIST(_list) \ + ({ unsigned long _id = (unsigned long)(_list)[0]; \ + (_list)[0] = (_list)[_id]; \ + (unsigned short)_id; }) + +static char *status_name[] = { + [NETIF_INTERFACE_STATUS_CLOSED] = "closed", + [NETIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected", + [NETIF_INTERFACE_STATUS_CONNECTED] = "connected", + [NETIF_INTERFACE_STATUS_CHANGED] = "changed", +}; + +static char *be_state_name[] = { + [BEST_CLOSED] = "closed", + [BEST_DISCONNECTED] = "disconnected", + [BEST_CONNECTED] = "connected", +}; + +#if DEBUG +#define DPRINTK(fmt, args...) \ + printk(KERN_ALERT "xen_net (%s:%d) " fmt, __FUNCTION__, __LINE__, ##args) +#else +#define DPRINTK(fmt, args...) ((void)0) +#endif +#define IPRINTK(fmt, args...) \ + printk(KERN_INFO "xen_net: " fmt, ##args) +#define WPRINTK(fmt, args...) \ + printk(KERN_WARNING "xen_net: " fmt, ##args) + +static struct net_device *find_dev_by_handle(unsigned int handle) +{ + struct list_head *ent; + struct net_private *np; + list_for_each (ent, &dev_list) { + np = list_entry(ent, struct net_private, list); + if (np->handle == handle) + return np->dev; + } + return NULL; +} + +/** Network interface info. */ +struct netif_ctrl { + /** Number of interfaces. */ + int interface_n; + /** Number of connected interfaces. */ + int connected_n; + /** Error code. */ + int err; + int up; +}; + +static struct netif_ctrl netctrl; + +static void netctrl_init(void) +{ + memset(&netctrl, 0, sizeof(netctrl)); + netctrl.up = NETIF_DRIVER_STATUS_DOWN; +} + +/** Get or set a network interface error. + */ +static int netctrl_err(int err) +{ + if ((err < 0) && !netctrl.err) + netctrl.err = err; + return netctrl.err; +} + +/** Test if all network interfaces are connected. + * + * @return 1 if all connected, 0 if not, negative error code otherwise + */ +static int netctrl_connected(void) +{ + int ok; + + if (netctrl.err) + ok = netctrl.err; + else if (netctrl.up == NETIF_DRIVER_STATUS_UP) + ok = (netctrl.connected_n == netctrl.interface_n); + else + ok = 0; + + return ok; +} + +/** Count the connected network interfaces. + * + * @return connected count + */ +static int netctrl_connected_count(void) +{ + + struct list_head *ent; + struct net_private *np; + unsigned int connected; + + connected = 0; + + list_for_each(ent, &dev_list) { + np = list_entry(ent, struct net_private, list); + if (np->backend_state == BEST_CONNECTED) + connected++; + } + + netctrl.connected_n = connected; + DPRINTK("> connected_n=%d interface_n=%d\n", + netctrl.connected_n, netctrl.interface_n); + return connected; +} + +/** Send a packet on a net device to encourage switches to learn the + * MAC. We send a fake ARP request. + * + * @param dev device + * @return 0 on success, error code otherwise + */ +static int send_fake_arp(struct net_device *dev) +{ + struct sk_buff *skb; + u32 src_ip, dst_ip; + + dst_ip = INADDR_BROADCAST; + src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK); + + /* No IP? Then nothing to do. */ + if (src_ip == 0) + return 0; + + skb = arp_create(ARPOP_REPLY, ETH_P_ARP, + dst_ip, dev, src_ip, + /*dst_hw*/ NULL, /*src_hw*/ NULL, + /*target_hw*/ dev->dev_addr); + if (skb == NULL) + return -ENOMEM; + + return dev_queue_xmit(skb); +} + +static int network_open(struct net_device *dev) +{ + struct net_private *np = netdev_priv(dev); + + memset(&np->stats, 0, sizeof(np->stats)); + + np->user_state = UST_OPEN; + + network_alloc_rx_buffers(dev); + np->rx->event = np->rx_resp_cons + 1; + + netif_start_queue(dev); + + return 0; +} + +static void network_tx_buf_gc(struct net_device *dev) +{ + NETIF_RING_IDX i, prod; + unsigned short id; + struct net_private *np = netdev_priv(dev); + struct sk_buff *skb; + + if (np->backend_state != BEST_CONNECTED) + return; + + do { + prod = np->tx->resp_prod; + rmb(); /* Ensure we see responses up to 'rp'. */ + + for (i = np->tx_resp_cons; i != prod; i++) { + id = np->tx->ring[MASK_NETIF_TX_IDX(i)].resp.id; + skb = np->tx_skbs[id]; + ADD_ID_TO_FREELIST(np->tx_skbs, id); + dev_kfree_skb_irq(skb); + } + + np->tx_resp_cons = prod; + + /* + * Set a new event, then check for race with update of tx_cons. Note + * that it is essential to schedule a callback, no matter how few + * buffers are pending. Even if there is space in the transmit ring, + * higher layers may be blocked because too much data is outstanding: + * in such cases notification from Xen is likely to be the only kick + * that we'll get. + */ + np->tx->event = + prod + ((np->tx->req_prod - prod) >> 1) + 1; + mb(); + } while (prod != np->tx->resp_prod); + + if (np->tx_full && ((np->tx->req_prod - prod) < NETIF_TX_RING_SIZE)) { + np->tx_full = 0; + if (np->user_state == UST_OPEN) + netif_wake_queue(dev); + } +} + + +static void network_alloc_rx_buffers(struct net_device *dev) +{ + unsigned short id; + struct net_private *np = netdev_priv(dev); + struct sk_buff *skb; + int i, batch_target; + NETIF_RING_IDX req_prod = np->rx->req_prod; + + if (unlikely(np->backend_state != BEST_CONNECTED)) + return; + + /* + * Allocate skbuffs greedily, even though we batch updates to the + * receive ring. This creates a less bursty demand on the memory allocator, + * so should reduce the chance of failed allocation requests both for + * ourself and for other kernel subsystems. + */ + batch_target = np->rx_target - (req_prod - np->rx_resp_cons); + for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) { + if (unlikely((skb = alloc_xen_skb(dev->mtu + RX_HEADROOM)) == NULL)) + break; + __skb_queue_tail(&np->rx_batch, skb); + } + + /* Is the batch large enough to be worthwhile? */ + if (i < (np->rx_target/2)) + return; + + for (i = 0; ; i++) { + if ((skb = __skb_dequeue(&np->rx_batch)) == NULL) + break; + + skb->dev = dev; + + id = GET_ID_FROM_FREELIST(np->rx_skbs); + + np->rx_skbs[id] = skb; + + np->rx->ring[MASK_NETIF_RX_IDX(req_prod + i)].req.id = id; + + rx_pfn_array[i] = virt_to_machine(skb->head) >> PAGE_SHIFT; + + /* Remove this page from pseudo phys map before passing back to Xen. */ + phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT] + = INVALID_P2M_ENTRY; + + rx_mcl[i].op = __HYPERVISOR_update_va_mapping; + rx_mcl[i].args[0] = (unsigned long)skb->head; + rx_mcl[i].args[1] = 0; + rx_mcl[i].args[2] = 0; + } + + /* After all PTEs have been zapped we blow away stale TLB entries. */ + rx_mcl[i-1].args[2] = UVMF_TLB_FLUSH|UVMF_ALL; + + /* Give away a batch of pages. */ + rx_mcl[i].op = __HYPERVISOR_dom_mem_op; + rx_mcl[i].args[0] = MEMOP_decrease_reservation; + rx_mcl[i].args[1] = (unsigned long)rx_pfn_array; + rx_mcl[i].args[2] = (unsigned long)i; + rx_mcl[i].args[3] = 0; + rx_mcl[i].args[4] = DOMID_SELF; + + /* Tell the ballon driver what is going on. */ + balloon_update_driver_allowance(i); + + /* Zap PTEs and give away pages in one big multicall. */ + (void)HYPERVISOR_multicall(rx_mcl, i+1); + + /* Check return status of HYPERVISOR_dom_mem_op(). */ + if (unlikely(rx_mcl[i].args[5] != i)) + panic("Unable to reduce memory reservation\n"); + + /* Above is a suitable barrier to ensure backend will see requests. */ + np->rx->req_prod = req_prod + i; + + /* Adjust our floating fill target if we risked running out of buffers. */ + if (((req_prod - np->rx->resp_prod) < (np->rx_target / 4)) && + ((np->rx_target *= 2) > RX_MAX_TARGET)) + np->rx_target = RX_MAX_TARGET; +} + + +static int network_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + unsigned short id; + struct net_private *np = netdev_priv(dev); + netif_tx_request_t *tx; + NETIF_RING_IDX i; + + if (unlikely(np->tx_full)) { + printk(KERN_ALERT "%s: full queue wasn't stopped!\n", dev->name); + netif_stop_queue(dev); + goto drop; + } + + if (unlikely((((unsigned long)skb->data & ~PAGE_MASK) + skb->len) >= + PAGE_SIZE)) { + struct sk_buff *nskb; + if (unlikely((nskb = alloc_xen_skb(skb->len)) == NULL)) + goto drop; + skb_put(nskb, skb->len); + memcpy(nskb->data, skb->data, skb->len); + nskb->dev = skb->dev; + dev_kfree_skb(skb); + skb = nskb; + } + + spin_lock_irq(&np->tx_lock); + + if (np->backend_state != BEST_CONNECTED) { + spin_unlock_irq(&np->tx_lock); + goto drop; + } + + i = np->tx->req_prod; + + id = GET_ID_FROM_FREELIST(np->tx_skbs); + np->tx_skbs[id] = skb; + + tx = &np->tx->ring[MASK_NETIF_TX_IDX(i)].req; + + tx->id = id; + tx->addr = virt_to_machine(skb->data); + tx->size = skb->len; + + wmb(); /* Ensure that backend will see the request. */ + np->tx->req_prod = i + 1; + + network_tx_buf_gc(dev); + + if ((i - np->tx_resp_cons) == (NETIF_TX_RING_SIZE - 1)) { + np->tx_full = 1; + netif_stop_queue(dev); + } + + spin_unlock_irq(&np->tx_lock); + + np->stats.tx_bytes += skb->len; + np->stats.tx_packets++; + + /* Only notify Xen if we really have to. */ + mb(); + if (np->tx->TX_TEST_IDX == i) + notify_via_evtchn(np->evtchn); + + return 0; + + drop: + np->stats.tx_dropped++; + dev_kfree_skb(skb); + return 0; +} + +static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs) +{ + struct net_device *dev = dev_id; + struct net_private *np = netdev_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&np->tx_lock, flags); + network_tx_buf_gc(dev); + spin_unlock_irqrestore(&np->tx_lock, flags); + + if ((np->rx_resp_cons != np->rx->resp_prod) && (np->user_state == UST_OPEN)) + netif_rx_schedule(dev); + + return IRQ_HANDLED; +} + + +static int netif_poll(struct net_device *dev, int *pbudget) +{ + struct net_private *np = netdev_priv(dev); + struct sk_buff *skb, *nskb; + netif_rx_response_t *rx; + NETIF_RING_IDX i, rp; + mmu_update_t *mmu = rx_mmu; + multicall_entry_t *mcl = rx_mcl; + int work_done, budget, more_to_do = 1; + struct sk_buff_head rxq; + unsigned long flags; + + spin_lock(&np->rx_lock); + + if (np->backend_state != BEST_CONNECTED) { + spin_unlock(&np->rx_lock); + return 0; + } + + skb_queue_head_init(&rxq); + + if ((budget = *pbudget) > dev->quota) + budget = dev->quota; + + rp = np->rx->resp_prod; + rmb(); /* Ensure we see queued responses up to 'rp'. */ + + for (i = np->rx_resp_cons, work_done = 0; + (i != rp) && (work_done < budget); + i++, work_done++) { + rx = &np->rx->ring[MASK_NETIF_RX_IDX(i)].resp; + + /* + * An error here is very odd. Usually indicates a backend bug, + * low-memory condition, or that we didn't have reservation headroom. + */ + if (unlikely(rx->status <= 0)) { + if (net_ratelimit()) + printk(KERN_WARNING "Bad rx buffer (memory squeeze?).\n"); + np->rx->ring[MASK_NETIF_RX_IDX(np->rx->req_prod)].req.id = rx->id; + wmb(); + np->rx->req_prod++; + work_done--; + continue; + } + + skb = np->rx_skbs[rx->id]; + ADD_ID_TO_FREELIST(np->rx_skbs, rx->id); + + /* NB. We handle skb overflow later. */ + skb->data = skb->head + (rx->addr & ~PAGE_MASK); + skb->len = rx->status; + skb->tail = skb->data + skb->len; + + np->stats.rx_packets++; + np->stats.rx_bytes += rx->status; + + /* Remap the page. */ + mmu->ptr = (rx->addr & PAGE_MASK) | MMU_MACHPHYS_UPDATE; + mmu->val = __pa(skb->head) >> PAGE_SHIFT; + mmu++; + mcl->op = __HYPERVISOR_update_va_mapping; + mcl->args[0] = (unsigned long)skb->head; + mcl->args[1] = (rx->addr & PAGE_MASK) | __PAGE_KERNEL; + mcl->args[2] = 0; + mcl++; + + phys_to_machine_mapping[__pa(skb->head) >> PAGE_SHIFT] = + rx->addr >> PAGE_SHIFT; + + __skb_queue_tail(&rxq, skb); + } + + /* Some pages are no longer absent... */ + balloon_update_driver_allowance(-work_done); + + /* Do all the remapping work, and M->P updates, in one big hypercall. */ + if (likely((mcl - rx_mcl) != 0)) { + mcl->op = __HYPERVISOR_mmu_update; + mcl->args[0] = (unsigned long)rx_mmu; + mcl->args[1] = mmu - rx_mmu; + mcl->args[2] = 0; + mcl->args[3] = DOMID_SELF; + mcl++; + (void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl); + } + + while ((skb = __skb_dequeue(&rxq)) != NULL) { + /* + * Enough room in skbuff for the data we were passed? Also, Linux + * expects at least 16 bytes headroom in each receive buffer. + */ + if (unlikely(skb->tail > skb->end) || + unlikely((skb->data - skb->head) < 16)) { + nskb = NULL; + + /* Only copy the packet if it fits in the current MTU. */ + if (skb->len <= (dev->mtu + ETH_HLEN)) { + if ((skb->tail > skb->end) && net_ratelimit()) + printk(KERN_INFO "Received packet needs %d bytes more " + "headroom.\n", skb->tail - skb->end); + + if ((nskb = alloc_xen_skb(skb->len + 2)) != NULL) { + skb_reserve(nskb, 2); + skb_put(nskb, skb->len); + memcpy(nskb->data, skb->data, skb->len); + nskb->dev = skb->dev; + } + } + else if (net_ratelimit()) + printk(KERN_INFO "Received packet too big for MTU " + "(%d > %d)\n", skb->len - ETH_HLEN, dev->mtu); + + /* Reinitialise and then destroy the old skbuff. */ + skb->len = 0; + skb->tail = skb->data; + init_skb_shinfo(skb); + dev_kfree_skb(skb); + + /* Switch old for new, if we copied the buffer. */ + if ((skb = nskb) == NULL) + continue; + } + + /* Set the shared-info area, which is hidden behind the real data. */ + init_skb_shinfo(skb); + + /* Ethernet-specific work. Delayed to here as it peeks the header. */ + skb->protocol = eth_type_trans(skb, dev); + + /* Pass it up. */ + netif_receive_skb(skb); + dev->last_rx = jiffies; + } + + np->rx_resp_cons = i; + + /* If we get a callback with very few responses, reduce fill target. */ + /* NB. Note exponential increase, linear decrease. */ + if (((np->rx->req_prod - np->rx->resp_prod) > ((3*np->rx_target) / 4)) && + (--np->rx_target < RX_MIN_TARGET)) + np->rx_target = RX_MIN_TARGET; + + network_alloc_rx_buffers(dev); + + *pbudget -= work_done; + dev->quota -= work_done; + + if (work_done < budget) { + local_irq_save(flags); + + np->rx->event = i + 1; + + /* Deal with hypervisor racing our resetting of rx_event. */ + mb(); + if (np->rx->resp_prod == i) { + __netif_rx_complete(dev); + more_to_do = 0; + } + + local_irq_restore(flags); + } + + spin_unlock(&np->rx_lock); + + return more_to_do; +} + + +static int network_close(struct net_device *dev) +{ + struct net_private *np = netdev_priv(dev); + np->user_state = UST_CLOSED; + netif_stop_queue(np->dev); + return 0; +} + + +static struct net_device_stats *network_get_stats(struct net_device *dev) +{ + struct net_private *np = netdev_priv(dev); + return &np->stats; +} + + +static void network_connect(struct net_device *dev, + netif_fe_interface_status_t *status) +{ + struct net_private *np; + int i, requeue_idx; + netif_tx_request_t *tx; + + np = netdev_priv(dev); + spin_lock_irq(&np->tx_lock); + spin_lock(&np->rx_lock); + + /* Recovery procedure: */ + + /* Step 1: Reinitialise variables. */ + np->rx_resp_cons = np->tx_resp_cons = np->tx_full = 0; + np->rx->event = np->tx->event = 1; + + /* Step 2: Rebuild the RX and TX ring contents. + * NB. We could just free the queued TX packets now but we hope + * that sending them out might do some good. We have to rebuild + * the RX ring because some of our pages are currently flipped out + * so we can't just free the RX skbs. + * NB2. Freelist index entries are always going to be less than + * __PAGE_OFFSET, whereas pointers to skbs will always be equal or + * greater than __PAGE_OFFSET: we use this property to distinguish + * them. + */ + + /* Rebuild the TX buffer freelist and the TX ring itself. + * NB. This reorders packets. We could keep more private state + * to avoid this but maybe it doesn't matter so much given the + * interface has been down. + */ + for (requeue_idx = 0, i = 1; i <= NETIF_TX_RING_SIZE; i++) { + if ((unsigned long)np->tx_skbs[i] >= __PAGE_OFFSET) { + struct sk_buff *skb = np->tx_skbs[i]; + + tx = &np->tx->ring[requeue_idx++].req; + + tx->id = i; + tx->addr = virt_to_machine(skb->data); + tx->size = skb->len; + + np->stats.tx_bytes += skb->len; + np->stats.tx_packets++; + } + } + wmb(); + np->tx->req_prod = requeue_idx; + + /* Rebuild the RX buffer freelist and the RX ring itself. */ + for (requeue_idx = 0, i = 1; i <= NETIF_RX_RING_SIZE; i++) + if ((unsigned long)np->rx_skbs[i] >= __PAGE_OFFSET) + np->rx->ring[requeue_idx++].req.id = i; + wmb(); + np->rx->req_prod = requeue_idx; + + /* Step 3: All public and private state should now be sane. Get + * ready to start sending and receiving packets and give the driver + * domain a kick because we've probably just requeued some + * packets. + */ + np->backend_state = BEST_CONNECTED; + wmb(); + notify_via_evtchn(status->evtchn); + network_tx_buf_gc(dev); + + if (np->user_state == UST_OPEN) + netif_start_queue(dev); + + spin_unlock(&np->rx_lock); + spin_unlock_irq(&np->tx_lock); +} + +static void vif_show(struct net_private *np) +{ +#if DEBUG + if (np) { + IPRINTK("\n", + np->handle, + be_state_name[np->backend_state], + np->user_state ? "open" : "closed", + np->evtchn, + np->irq, + np->tx, + np->rx); + } else { + IPRINTK("\n"); + } +#endif +} + +/* Send a connect message to xend to tell it to bring up the interface. */ +static void send_interface_connect(struct net_private *np) +{ + ctrl_msg_t cmsg = { + .type = CMSG_NETIF_FE, + .subtype = CMSG_NETIF_FE_INTERFACE_CONNECT, + .length = sizeof(netif_fe_interface_connect_t), + }; + netif_fe_interface_connect_t *msg = (void*)cmsg.msg; + + msg->handle = np->handle; + msg->tx_shmem_frame = (virt_to_machine(np->tx) >> PAGE_SHIFT); + msg->rx_shmem_frame = (virt_to_machine(np->rx) >> PAGE_SHIFT); + + ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); +} + +/* Send a driver status notification to the domain controller. */ +static int send_driver_status(int ok) +{ + int err = 0; + ctrl_msg_t cmsg = { + .type = CMSG_NETIF_FE, + .subtype = CMSG_NETIF_FE_DRIVER_STATUS, + .length = sizeof(netif_fe_driver_status_t), + }; + netif_fe_driver_status_t *msg = (void*)cmsg.msg; + + msg->status = (ok ? NETIF_DRIVER_STATUS_UP : NETIF_DRIVER_STATUS_DOWN); + err = ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE); + return err; +} + +/* Stop network device and free tx/rx queues and irq. + */ +static void vif_release(struct net_private *np) +{ + /* Stop old i/f to prevent errors whilst we rebuild the state. */ + spin_lock_irq(&np->tx_lock); + spin_lock(&np->rx_lock); + netif_stop_queue(np->dev); + /* np->backend_state = BEST_DISCONNECTED; */ + spin_unlock(&np->rx_lock); + spin_unlock_irq(&np->tx_lock); + + /* Free resources. */ + if(np->tx != NULL){ + free_irq(np->irq, np->dev); + unbind_evtchn_from_irq(np->evtchn); + free_page((unsigned long)np->tx); + free_page((unsigned long)np->rx); + np->irq = 0; + np->evtchn = 0; + np->tx = NULL; + np->rx = NULL; + } +} + +/* Release vif resources and close it down completely. + */ +static void vif_close(struct net_private *np) +{ + WPRINTK("Unexpected netif-CLOSED message in state %s\n", + be_state_name[np->backend_state]); + vif_release(np); + np->backend_state = BEST_CLOSED; + /* todo: take dev down and free. */ + vif_show(np); +} + +/* Move the vif into disconnected state. + * Allocates tx/rx pages. + * Sends connect message to xend. + */ +static void vif_disconnect(struct net_private *np) +{ + if(np->tx) free_page((unsigned long)np->tx); + if(np->rx) free_page((unsigned long)np->rx); + // Before this np->tx and np->rx had better be null. + np->tx = (netif_tx_interface_t *)__get_free_page(GFP_KERNEL); + np->rx = (netif_rx_interface_t *)__get_free_page(GFP_KERNEL); + memset(np->tx, 0, PAGE_SIZE); + memset(np->rx, 0, PAGE_SIZE); + np->backend_state = BEST_DISCONNECTED; + send_interface_connect(np); + vif_show(np); +} + +/* Begin interface recovery. + * + * NB. Whilst we're recovering, we turn the carrier state off. We + * take measures to ensure that this device isn't used for + * anything. We also stop the queue for this device. Various + * different approaches (e.g. continuing to buffer packets) have + * been tested but don't appear to improve the overall impact on + * TCP connections. + * + * TODO: (MAW) Change the Xend<->Guest protocol so that a recovery + * is initiated by a special "RESET" message - disconnect could + * just mean we're not allowed to use this interface any more. + */ +static void vif_reset(struct net_private *np) +{ + IPRINTK("Attempting to reconnect network interface: handle=%u\n", + np->handle); + vif_release(np); + vif_disconnect(np); + vif_show(np); +} + +/* Move the vif into connected state. + * Sets the mac and event channel from the message. + * Binds the irq to the event channel. + */ +static void +vif_connect(struct net_private *np, netif_fe_interface_status_t *status) +{ + struct net_device *dev = np->dev; + memcpy(dev->dev_addr, status->mac, ETH_ALEN); + network_connect(dev, status); + np->evtchn = status->evtchn; + np->irq = bind_evtchn_to_irq(np->evtchn); + (void)request_irq(np->irq, netif_int, SA_SAMPLE_RANDOM, dev->name, dev); + netctrl_connected_count(); + (void)send_fake_arp(dev); + vif_show(np); +} + + +/** Create a network device. + * @param handle device handle + * @param val return parameter for created device + * @return 0 on success, error code otherwise + */ +static int create_netdev(int handle, struct net_device **val) +{ + int i, err = 0; + struct net_device *dev = NULL; + struct net_private *np = NULL; + + if ((dev = alloc_etherdev(sizeof(struct net_private))) == NULL) { + printk(KERN_WARNING "%s> alloc_etherdev failed.\n", __FUNCTION__); + err = -ENOMEM; + goto exit; + } + + np = netdev_priv(dev); + np->backend_state = BEST_CLOSED; + np->user_state = UST_CLOSED; + np->handle = handle; + + spin_lock_init(&np->tx_lock); + spin_lock_init(&np->rx_lock); + + skb_queue_head_init(&np->rx_batch); + np->rx_target = RX_MIN_TARGET; + + /* Initialise {tx,rx}_skbs to be a free chain containing every entry. */ + for (i = 0; i <= NETIF_TX_RING_SIZE; i++) + np->tx_skbs[i] = (void *)(i+1); + for (i = 0; i <= NETIF_RX_RING_SIZE; i++) + np->rx_skbs[i] = (void *)(i+1); + + dev->open = network_open; + dev->hard_start_xmit = network_start_xmit; + dev->stop = network_close; + dev->get_stats = network_get_stats; + dev->poll = netif_poll; + dev->weight = 64; + + if ((err = register_netdev(dev)) != 0) { + printk(KERN_WARNING "%s> register_netdev err=%d\n", __FUNCTION__, err); + goto exit; + } + np->dev = dev; + list_add(&np->list, &dev_list); + + exit: + if ((err != 0) && (dev != NULL )) + kfree(dev); + else if (val != NULL) + *val = dev; + return err; +} + +/* Get the target interface for a status message. + * Creates the interface when it makes sense. + * The returned interface may be null when there is no error. + * + * @param status status message + * @param np return parameter for interface state + * @return 0 on success, error code otherwise + */ +static int +target_vif(netif_fe_interface_status_t *status, struct net_private **np) +{ + int err = 0; + struct net_device *dev; + + DPRINTK("> handle=%d\n", status->handle); + if (status->handle < 0) { + err = -EINVAL; + goto exit; + } + + if ((dev = find_dev_by_handle(status->handle)) != NULL) + goto exit; + + if (status->status == NETIF_INTERFACE_STATUS_CLOSED) + goto exit; + if (status->status == NETIF_INTERFACE_STATUS_CHANGED) + goto exit; + + /* It's a new interface in a good state - create it. */ + DPRINTK("> create device...\n"); + if ((err = create_netdev(status->handle, &dev)) != 0) + goto exit; + + netctrl.interface_n++; + + exit: + if (np != NULL) + *np = ((dev && !err) ? netdev_priv(dev) : NULL); + DPRINTK("< err=%d\n", err); + return err; +} + +/* Handle an interface status message. */ +static void netif_interface_status(netif_fe_interface_status_t *status) +{ + int err = 0; + struct net_private *np = NULL; + + DPRINTK("> status=%s handle=%d\n", + status_name[status->status], status->handle); + + if ((err = target_vif(status, &np)) != 0) { + WPRINTK("Invalid netif: handle=%u\n", status->handle); + return; + } + + if (np == NULL) { + DPRINTK("> no vif\n"); + return; + } + + switch (status->status) { + case NETIF_INTERFACE_STATUS_CLOSED: + switch (np->backend_state) { + case BEST_CLOSED: + case BEST_DISCONNECTED: + case BEST_CONNECTED: + vif_close(np); + break; + } + break; + + case NETIF_INTERFACE_STATUS_DISCONNECTED: + switch (np->backend_state) { + case BEST_CLOSED: + vif_disconnect(np); + break; + case BEST_DISCONNECTED: + case BEST_CONNECTED: + vif_reset(np); + break; + } + break; + + case NETIF_INTERFACE_STATUS_CONNECTED: + switch (np->backend_state) { + case BEST_CLOSED: + WPRINTK("Unexpected netif status %s in state %s\n", + status_name[status->status], + be_state_name[np->backend_state]); + vif_disconnect(np); + vif_connect(np, status); + break; + case BEST_DISCONNECTED: + vif_connect(np, status); + break; + } + break; + + case NETIF_INTERFACE_STATUS_CHANGED: + /* + * The domain controller is notifying us that a device has been + * added or removed. + */ + break; + + default: + WPRINTK("Invalid netif status code %d\n", status->status); + break; + } + + vif_show(np); +} + +/* + * Initialize the network control interface. + */ +static void netif_driver_status(netif_fe_driver_status_t *status) +{ + netctrl.up = status->status; + netctrl_connected_count(); +} + +/* Receive handler for control messages. */ +static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) +{ + + switch (msg->subtype) { + case CMSG_NETIF_FE_INTERFACE_STATUS: + netif_interface_status((netif_fe_interface_status_t *) &msg->msg[0]); + break; + + case CMSG_NETIF_FE_DRIVER_STATUS: + netif_driver_status((netif_fe_driver_status_t *) &msg->msg[0]); + break; + + default: + msg->length = 0; + break; + } + + ctrl_if_send_response(msg); +} + + +#if 1 +/* Wait for all interfaces to be connected. + * + * This works OK, but we'd like to use the probing mode (see below). + */ +static int probe_interfaces(void) +{ + int err = 0, conn = 0; + int wait_i, wait_n = 100; + + DPRINTK(">\n"); + + for (wait_i = 0; wait_i < wait_n; wait_i++) { + DPRINTK("> wait_i=%d\n", wait_i); + conn = netctrl_connected(); + if(conn) break; + DPRINTK("> schedule_timeout...\n"); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(10); + } + + DPRINTK("> wait finished...\n"); + if (conn <= 0) { + err = netctrl_err(-ENETDOWN); + WPRINTK("Failed to connect all virtual interfaces: err=%d\n", err); + } + + DPRINTK("< err=%d\n", err); + + return err; +} +#else +/* Probe for interfaces until no more are found. + * + * This is the mode we'd like to use, but at the moment it panics the kernel. +*/ +static int probe_interfaces(void) +{ + int err = 0; + int wait_i, wait_n = 100; + ctrl_msg_t cmsg = { + .type = CMSG_NETIF_FE, + .subtype = CMSG_NETIF_FE_INTERFACE_STATUS, + .length = sizeof(netif_fe_interface_status_t), + }; + netif_fe_interface_status_t msg = {}; + ctrl_msg_t rmsg = {}; + netif_fe_interface_status_t *reply = (void*)rmsg.msg; + int state = TASK_UNINTERRUPTIBLE; + u32 query = -1; + + DPRINTK(">\n"); + + netctrl.interface_n = 0; + for (wait_i = 0; wait_i < wait_n; wait_i++) { + DPRINTK("> wait_i=%d query=%d\n", wait_i, query); + msg.handle = query; + memcpy(cmsg.msg, &msg, sizeof(msg)); + DPRINTK("> set_current_state...\n"); + set_current_state(state); + DPRINTK("> rmsg=%p msg=%p, reply=%p\n", &rmsg, rmsg.msg, reply); + DPRINTK("> sending...\n"); + err = ctrl_if_send_message_and_get_response(&cmsg, &rmsg, state); + DPRINTK("> err=%d\n", err); + if(err) goto exit; + DPRINTK("> rmsg=%p msg=%p, reply=%p\n", &rmsg, rmsg.msg, reply); + if((int)reply->handle < 0) { + // No more interfaces. + break; + } + query = -reply->handle - 2; + DPRINTK(">netif_interface_status ...\n"); + netif_interface_status(reply); + } + + exit: + if (err) { + err = netctrl_err(-ENETDOWN); + WPRINTK("Connecting virtual network interfaces failed: err=%d\n", err); + } + + DPRINTK("< err=%d\n", err); + return err; +} + +#endif + +/* + * We use this notifier to send out a fake ARP reply to reset switches and + * router ARP caches when an IP interface is brought up on a VIF. + */ +static int +inetdev_notify(struct notifier_block *this, unsigned long event, void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + struct net_device *dev = ifa->ifa_dev->dev; + struct list_head *ent; + struct net_private *np; + + if (event != NETDEV_UP) + goto out; + + list_for_each (ent, &dev_list) { + np = list_entry(ent, struct net_private, list); + if (np->dev == dev) + (void)send_fake_arp(dev); + } + + out: + return NOTIFY_DONE; +} + +static struct notifier_block notifier_inetdev = { + .notifier_call = inetdev_notify, + .next = NULL, + .priority = 0 +}; + +static int __init netif_init(void) +{ + int err = 0; + + if (xen_start_info.flags & SIF_INITDOMAIN) + return 0; + + IPRINTK("Initialising virtual ethernet driver.\n"); + INIT_LIST_HEAD(&dev_list); + (void)register_inetaddr_notifier(¬ifier_inetdev); + netctrl_init(); + (void)ctrl_if_register_receiver(CMSG_NETIF_FE, netif_ctrlif_rx, + CALLBACK_IN_BLOCKING_CONTEXT); + send_driver_status(1); + err = probe_interfaces(); + if (err) + ctrl_if_unregister_receiver(CMSG_NETIF_FE, netif_ctrlif_rx); + + DPRINTK("< err=%d\n", err); + return err; +} + +static void vif_suspend(struct net_private *np) +{ + /* Avoid having tx/rx stuff happen until we're ready. */ + free_irq(np->irq, np->dev); + unbind_evtchn_from_irq(np->evtchn); +} + +static void vif_resume(struct net_private *np) +{ + /* + * Connect regardless of whether IFF_UP flag set. + * Stop bad things from happening until we're back up. + */ + np->backend_state = BEST_DISCONNECTED; + memset(np->tx, 0, PAGE_SIZE); + memset(np->rx, 0, PAGE_SIZE); + + send_interface_connect(np); +} + +void netif_suspend(void) +{ + struct list_head *ent; + struct net_private *np; + + list_for_each (ent, &dev_list) { + np = list_entry(ent, struct net_private, list); + vif_suspend(np); + } +} + +void netif_resume(void) +{ + struct list_head *ent; + struct net_private *np; + + list_for_each (ent, &dev_list) { + np = list_entry(ent, struct net_private, list); + vif_resume(np); + } +} + + +module_init(netif_init); + diff --git a/drivers/xen/privcmd/Makefile b/drivers/xen/privcmd/Makefile new file mode 100644 index 000000000..e21869553 --- /dev/null +++ b/drivers/xen/privcmd/Makefile @@ -0,0 +1,2 @@ + +obj-y := privcmd.o diff --git a/drivers/xen/privcmd/privcmd.c b/drivers/xen/privcmd/privcmd.c new file mode 100644 index 000000000..0b78cc7e8 --- /dev/null +++ b/drivers/xen/privcmd/privcmd.c @@ -0,0 +1,232 @@ +/****************************************************************************** + * privcmd.c + * + * Interface to privileged domain-0 commands. + * + * Copyright (c) 2002-2004, K A Fraser, B Dragovic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) +#define pud_t pgd_t +#define pud_offset(d, va) d +#endif + +static struct proc_dir_entry *privcmd_intf; + +static int privcmd_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long data) +{ + int ret = -ENOSYS; + + switch ( cmd ) + { + case IOCTL_PRIVCMD_HYPERCALL: + { + privcmd_hypercall_t hypercall; + + if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) ) + return -EFAULT; + +#if defined(__i386__) + __asm__ __volatile__ ( + "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; " + "movl 4(%%eax),%%ebx ;" + "movl 8(%%eax),%%ecx ;" + "movl 12(%%eax),%%edx ;" + "movl 16(%%eax),%%esi ;" + "movl 20(%%eax),%%edi ;" + "movl (%%eax),%%eax ;" + TRAP_INSTR "; " + "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx" + : "=a" (ret) : "0" (&hypercall) : "memory" ); +#elif defined (__x86_64__) + __asm__ __volatile__ ( + "movq %5,%%r10; movq %6,%%r8;" TRAP_INSTR + : "=a" (ret) + : "a" ((unsigned long)hypercall.op), + "D" ((unsigned long)hypercall.arg[0]), + "S" ((unsigned long)hypercall.arg[1]), + "d" ((unsigned long)hypercall.arg[2]), + "g" ((unsigned long)hypercall.arg[3]), + "g" ((unsigned long)hypercall.arg[4]) + : "r11","rcx","r8","r10","memory"); +#endif + } + break; + + case IOCTL_PRIVCMD_INITDOMAIN_EVTCHN: + { + extern int initdom_ctrlif_domcontroller_port; + ret = initdom_ctrlif_domcontroller_port; + } + break; + +#if defined(CONFIG_XEN_PRIVILEGED_GUEST) + case IOCTL_PRIVCMD_MMAP: + { +#define PRIVCMD_MMAP_SZ 32 + privcmd_mmap_t mmapcmd; + privcmd_mmap_entry_t msg[PRIVCMD_MMAP_SZ], *p; + int i, rc; + + if ( copy_from_user(&mmapcmd, (void *)data, sizeof(mmapcmd)) ) + return -EFAULT; + + p = mmapcmd.entry; + + for (i=0; iPRIVCMD_MMAP_SZ)? + PRIVCMD_MMAP_SZ:(mmapcmd.num-i); + + + if ( copy_from_user(&msg, p, n*sizeof(privcmd_mmap_entry_t)) ) + return -EFAULT; + + for ( j = 0; j < n; j++ ) + { + struct vm_area_struct *vma = + find_vma( current->mm, msg[j].va ); + + if ( !vma ) + return -EINVAL; + + if ( msg[j].va > PAGE_OFFSET ) + return -EINVAL; + + if ( (msg[j].va + (msg[j].npages< vma->vm_end ) + return -EINVAL; + + if ( (rc = direct_remap_area_pages(vma->vm_mm, + msg[j].va&PAGE_MASK, + msg[j].mfn<vm_page_prot, + mmapcmd.dom)) < 0 ) + return rc; + } + } + ret = 0; + } + break; + + case IOCTL_PRIVCMD_MMAPBATCH: + { + mmu_update_t u; + privcmd_mmapbatch_t m; + struct vm_area_struct *vma = NULL; + unsigned long *p, addr; + unsigned long mfn; + int i; + + if ( copy_from_user(&m, (void *)data, sizeof(m)) ) + { ret = -EFAULT; goto batch_err; } + + vma = find_vma( current->mm, m.addr ); + + if ( !vma ) + { ret = -EINVAL; goto batch_err; } + + if ( m.addr > PAGE_OFFSET ) + { ret = -EFAULT; goto batch_err; } + + if ( (m.addr + (m.num< vma->vm_end ) + { ret = -EFAULT; goto batch_err; } + + p = m.arr; + addr = m.addr; + for ( i = 0; i < m.num; i++, addr += PAGE_SIZE, p++ ) + { + if ( get_user(mfn, p) ) + return -EFAULT; + + u.val = (mfn << PAGE_SHIFT) | pgprot_val(vma->vm_page_prot); + + __direct_remap_area_pages(vma->vm_mm, + addr, + PAGE_SIZE, + &u); + + if ( unlikely(HYPERVISOR_mmu_update(&u, 1, NULL, m.dom) < 0) ) + put_user(0xF0000000 | mfn, p); + } + + ret = 0; + break; + + batch_err: + printk("batch_err ret=%d vma=%p addr=%lx num=%d arr=%p %lx-%lx\n", + ret, vma, m.addr, m.num, m.arr, + vma ? vma->vm_start : 0, vma ? vma->vm_end : 0); + break; + } + break; +#endif + + case IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN: + { + unsigned long m2pv = (unsigned long)machine_to_phys_mapping; + pgd_t *pgd = pgd_offset_k(m2pv); + pud_t *pud = pud_offset(pgd, m2pv); + pmd_t *pmd = pmd_offset(pud, m2pv); + unsigned long m2p_start_mfn = (*(unsigned long *)pmd) >> PAGE_SHIFT; + ret = put_user(m2p_start_mfn, (unsigned long *)data) ? -EFAULT: 0; + } + break; + + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int privcmd_mmap(struct file * file, struct vm_area_struct * vma) +{ + /* DONTCOPY is essential for Xen as copy_page_range is broken. */ + vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY; + + return 0; +} + +static struct file_operations privcmd_file_ops = { + ioctl : privcmd_ioctl, + mmap: privcmd_mmap +}; + + +static int __init privcmd_init(void) +{ + if ( !(xen_start_info.flags & SIF_PRIVILEGED) ) + return 0; + + privcmd_intf = create_xen_proc_entry("privcmd", 0400); + if ( privcmd_intf != NULL ) + privcmd_intf->proc_fops = &privcmd_file_ops; + + return 0; +} + +__initcall(privcmd_init); diff --git a/include/asm-arm/arch-imx/imxfb.h b/include/asm-arm/arch-imx/imxfb.h new file mode 100644 index 000000000..2346d454a --- /dev/null +++ b/include/asm-arm/arch-imx/imxfb.h @@ -0,0 +1,35 @@ +/* + * This structure describes the machine which we are running on. + */ +struct imxfb_mach_info { + u_long pixclock; + + u_short xres; + u_short yres; + + u_char bpp; + u_char hsync_len; + u_char left_margin; + u_char right_margin; + + u_char vsync_len; + u_char upper_margin; + u_char lower_margin; + u_char sync; + + u_int cmap_greyscale:1, + cmap_inverse:1, + cmap_static:1, + unused:29; + + u_int pcr; + u_int pwmr; + u_int lscr1; + + u_char * fixed_screen_cpu; + dma_addr_t fixed_screen_dma; + + void (*lcd_power)(int); + void (*backlight_power)(int); +}; +void set_imx_fb_info(struct imxfb_mach_info *hard_imx_fb_info); diff --git a/include/asm-arm/arch-omap/board-voiceblue.h b/include/asm-arm/arch-omap/board-voiceblue.h new file mode 100644 index 000000000..33977b895 --- /dev/null +++ b/include/asm-arm/arch-omap/board-voiceblue.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl + * + * Hardware definitions for OMAP5910 based VoiceBlue board. + * + * 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. + */ + +#ifndef __ASM_ARCH_VOICEBLUE_H +#define __ASM_ARCH_VOICEBLUE_H + +#if (EXTERNAL_MAX_NR_PORTS < 4) +#undef EXTERNAL_MAX_NR_PORTS +#define EXTERNAL_MAX_NR_PORTS 4 +#endif + +extern void voiceblue_wdt_enable(void); +extern void voiceblue_wdt_disable(void); +extern void voiceblue_wdt_ping(void); +extern void voiceblue_reset(void); + +#endif /* __ASM_ARCH_VOICEBLUE_H */ + diff --git a/include/asm-arm/arch-s3c2410/otom-map.h b/include/asm-arm/arch-s3c2410/otom-map.h new file mode 100644 index 000000000..e40c93429 --- /dev/null +++ b/include/asm-arm/arch-s3c2410/otom-map.h @@ -0,0 +1,30 @@ +/* linux/include/asm-arm/arch-s3c2410/otom-map.h + * + * (c) 2005 Guillaume GOURAT / NexVision + * guillaume.gourat@nexvision.fr + * + * NexVision OTOM board memory map definitions + * + * 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. +*/ + +/* needs arch/map.h including with this */ + +/* ok, we've used up to 0x01300000, now we need to find space for the + * peripherals that live in the nGCS[x] areas, which are quite numerous + * in their space. + */ + +#ifndef __ASM_ARCH_OTOMMAP_H +#define __ASM_ARCH_OTOMMAP_H + +#define OTOM_PA_CS8900A_BASE (S3C2410_CS3 + 0x01000000) /* nGCS3 +0x01000000 */ +#define OTOM_VA_CS8900A_BASE S3C2410_ADDR(0x04000000) /* 0xF4000000 */ + +/* physical offset addresses for the peripherals */ + +#define OTOM_PA_FLASH0_BASE (S3C2410_CS0) /* Bank 0 */ + +#endif /* __ASM_ARCH_OTOMMAP_H */ diff --git a/include/asm-arm/mach/sharpsl_param.h b/include/asm-arm/mach/sharpsl_param.h new file mode 100644 index 000000000..7a24ecf04 --- /dev/null +++ b/include/asm-arm/mach/sharpsl_param.h @@ -0,0 +1,37 @@ +/* + * Hardware parameter area specific to Sharp SL series devices + * + * Copyright (c) 2005 Richard Purdie + * + * Based on Sharp's 2.4 kernel patches + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +struct sharpsl_param_info { + unsigned int comadj_keyword; + unsigned int comadj; + + unsigned int uuid_keyword; + unsigned char uuid[16]; + + unsigned int touch_keyword; + unsigned int touch_xp; + unsigned int touch_yp; + unsigned int touch_xd; + unsigned int touch_yd; + + unsigned int adadj_keyword; + unsigned int adadj; + + unsigned int phad_keyword; + unsigned int phadadj; +} __attribute__((packed)); + + +extern struct sharpsl_param_info sharpsl_param; +extern void sharpsl_save_param(void); + diff --git a/include/asm-generic/ipc.h b/include/asm-generic/ipc.h new file mode 100644 index 000000000..a40407a16 --- /dev/null +++ b/include/asm-generic/ipc.h @@ -0,0 +1,31 @@ +#ifndef _ASM_GENERIC_IPC_H +#define _ASM_GENERIC_IPC_H +/* + * These are used to wrap system calls. + * + * See architecture code for ugly details.. + */ +struct ipc_kludge { + struct msgbuf __user *msgp; + long msgtyp; +}; + +#define SEMOP 1 +#define SEMGET 2 +#define SEMCTL 3 +#define SEMTIMEDOP 4 +#define MSGSND 11 +#define MSGRCV 12 +#define MSGGET 13 +#define MSGCTL 14 +#define SHMAT 21 +#define SHMDT 22 +#define SHMGET 23 +#define SHMCTL 24 + +/* Used by the DIPC package, try and avoid reusing it */ +#define DIPC 25 + +#define IPCCALL(version,op) ((version)<<16 | (op)) + +#endif /* _ASM_GENERIC_IPC_H */ diff --git a/include/asm-i386/seccomp.h b/include/asm-i386/seccomp.h new file mode 100644 index 000000000..18da19e89 --- /dev/null +++ b/include/asm-i386/seccomp.h @@ -0,0 +1,16 @@ +#ifndef _ASM_SECCOMP_H + +#include + +#ifdef TIF_32BIT +#error "unexpected TIF_32BIT on i386" +#endif + +#include + +#define __NR_seccomp_read __NR_read +#define __NR_seccomp_write __NR_write +#define __NR_seccomp_exit __NR_exit +#define __NR_seccomp_sigreturn __NR_sigreturn + +#endif /* _ASM_SECCOMP_H */ diff --git a/include/asm-ia64/sn/tioca.h b/include/asm-ia64/sn/tioca.h new file mode 100644 index 000000000..bc1aacfb9 --- /dev/null +++ b/include/asm-ia64/sn/tioca.h @@ -0,0 +1,596 @@ +#ifndef _ASM_IA64_SN_TIO_TIOCA_H +#define _ASM_IA64_SN_TIO_TIOCA_H + +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2003-2005 Silicon Graphics, Inc. All rights reserved. + */ + + +#define TIOCA_PART_NUM 0xE020 +#define TIOCA_MFGR_NUM 0x24 +#define TIOCA_REV_A 0x1 + +/* + * Register layout for TIO:CA. See below for bitmasks for each register. + */ + +struct tioca { + uint64_t ca_id; /* 0x000000 */ + uint64_t ca_control1; /* 0x000008 */ + uint64_t ca_control2; /* 0x000010 */ + uint64_t ca_status1; /* 0x000018 */ + uint64_t ca_status2; /* 0x000020 */ + uint64_t ca_gart_aperature; /* 0x000028 */ + uint64_t ca_gfx_detach; /* 0x000030 */ + uint64_t ca_inta_dest_addr; /* 0x000038 */ + uint64_t ca_intb_dest_addr; /* 0x000040 */ + uint64_t ca_err_int_dest_addr; /* 0x000048 */ + uint64_t ca_int_status; /* 0x000050 */ + uint64_t ca_int_status_alias; /* 0x000058 */ + uint64_t ca_mult_error; /* 0x000060 */ + uint64_t ca_mult_error_alias; /* 0x000068 */ + uint64_t ca_first_error; /* 0x000070 */ + uint64_t ca_int_mask; /* 0x000078 */ + uint64_t ca_crm_pkterr_type; /* 0x000080 */ + uint64_t ca_crm_pkterr_type_alias; /* 0x000088 */ + uint64_t ca_crm_ct_error_detail_1; /* 0x000090 */ + uint64_t ca_crm_ct_error_detail_2; /* 0x000098 */ + uint64_t ca_crm_tnumto; /* 0x0000A0 */ + uint64_t ca_gart_err; /* 0x0000A8 */ + uint64_t ca_pcierr_type; /* 0x0000B0 */ + uint64_t ca_pcierr_addr; /* 0x0000B8 */ + + uint64_t ca_pad_0000C0[3]; /* 0x0000{C0..D0} */ + + uint64_t ca_pci_rd_buf_flush; /* 0x0000D8 */ + uint64_t ca_pci_dma_addr_extn; /* 0x0000E0 */ + uint64_t ca_agp_dma_addr_extn; /* 0x0000E8 */ + uint64_t ca_force_inta; /* 0x0000F0 */ + uint64_t ca_force_intb; /* 0x0000F8 */ + uint64_t ca_debug_vector_sel; /* 0x000100 */ + uint64_t ca_debug_mux_core_sel; /* 0x000108 */ + uint64_t ca_debug_mux_pci_sel; /* 0x000110 */ + uint64_t ca_debug_domain_sel; /* 0x000118 */ + + uint64_t ca_pad_000120[28]; /* 0x0001{20..F8} */ + + uint64_t ca_gart_ptr_table; /* 0x200 */ + uint64_t ca_gart_tlb_addr[8]; /* 0x2{08..40} */ +}; + +/* + * Mask/shift definitions for TIO:CA registers. The convention here is + * to mainly use the names as they appear in the "TIO AEGIS Programmers' + * Reference" with a CA_ prefix added. Some exceptions were made to fix + * duplicate field names or to generalize fields that are common to + * different registers (ca_debug_mux_core_sel and ca_debug_mux_pci_sel for + * example). + * + * Fields consisting of a single bit have a single #define have a single + * macro declaration to mask the bit. Fields consisting of multiple bits + * have two declarations: one to mask the proper bits in a register, and + * a second with the suffix "_SHFT" to identify how far the mask needs to + * be shifted right to get its base value. + */ + +/* ==== ca_control1 */ +#define CA_SYS_BIG_END (1ull << 0) +#define CA_DMA_AGP_SWAP (1ull << 1) +#define CA_DMA_PCI_SWAP (1ull << 2) +#define CA_PIO_IO_SWAP (1ull << 3) +#define CA_PIO_MEM_SWAP (1ull << 4) +#define CA_GFX_WR_SWAP (1ull << 5) +#define CA_AGP_FW_ENABLE (1ull << 6) +#define CA_AGP_CAL_CYCLE (0x7ull << 7) +#define CA_AGP_CAL_CYCLE_SHFT 7 +#define CA_AGP_CAL_PRSCL_BYP (1ull << 10) +#define CA_AGP_INIT_CAL_ENB (1ull << 11) +#define CA_INJ_ADDR_PERR (1ull << 12) +#define CA_INJ_DATA_PERR (1ull << 13) + /* bits 15:14 unused */ +#define CA_PCIM_IO_NBE_AD (0x7ull << 16) +#define CA_PCIM_IO_NBE_AD_SHFT 16 +#define CA_PCIM_FAST_BTB_ENB (1ull << 19) + /* bits 23:20 unused */ +#define CA_PIO_ADDR_OFFSET (0xffull << 24) +#define CA_PIO_ADDR_OFFSET_SHFT 24 + /* bits 35:32 unused */ +#define CA_AGPDMA_OP_COMBDELAY (0x1full << 36) +#define CA_AGPDMA_OP_COMBDELAY_SHFT 36 + /* bit 41 unused */ +#define CA_AGPDMA_OP_ENB_COMBDELAY (1ull << 42) +#define CA_PCI_INT_LPCNT (0xffull << 44) +#define CA_PCI_INT_LPCNT_SHFT 44 + /* bits 63:52 unused */ + +/* ==== ca_control2 */ +#define CA_AGP_LATENCY_TO (0xffull << 0) +#define CA_AGP_LATENCY_TO_SHFT 0 +#define CA_PCI_LATENCY_TO (0xffull << 8) +#define CA_PCI_LATENCY_TO_SHFT 8 +#define CA_PCI_MAX_RETRY (0x3ffull << 16) +#define CA_PCI_MAX_RETRY_SHFT 16 + /* bits 27:26 unused */ +#define CA_RT_INT_EN (0x3ull << 28) +#define CA_RT_INT_EN_SHFT 28 +#define CA_MSI_INT_ENB (1ull << 30) +#define CA_PCI_ARB_ERR_ENB (1ull << 31) +#define CA_GART_MEM_PARAM (0x3ull << 32) +#define CA_GART_MEM_PARAM_SHFT 32 +#define CA_GART_RD_PREFETCH_ENB (1ull << 34) +#define CA_GART_WR_PREFETCH_ENB (1ull << 35) +#define CA_GART_FLUSH_TLB (1ull << 36) + /* bits 39:37 unused */ +#define CA_CRM_TNUMTO_PERIOD (0x1fffull << 40) +#define CA_CRM_TNUMTO_PERIOD_SHFT 40 + /* bits 55:53 unused */ +#define CA_CRM_TNUMTO_ENB (1ull << 56) +#define CA_CRM_PRESCALER_BYP (1ull << 57) + /* bits 59:58 unused */ +#define CA_CRM_MAX_CREDIT (0x7ull << 60) +#define CA_CRM_MAX_CREDIT_SHFT 60 + /* bit 63 unused */ + +/* ==== ca_status1 */ +#define CA_CORELET_ID (0x3ull << 0) +#define CA_CORELET_ID_SHFT 0 +#define CA_INTA_N (1ull << 2) +#define CA_INTB_N (1ull << 3) +#define CA_CRM_CREDIT_AVAIL (0x7ull << 4) +#define CA_CRM_CREDIT_AVAIL_SHFT 4 + /* bit 7 unused */ +#define CA_CRM_SPACE_AVAIL (0x7full << 8) +#define CA_CRM_SPACE_AVAIL_SHFT 8 + /* bit 15 unused */ +#define CA_GART_TLB_VAL (0xffull << 16) +#define CA_GART_TLB_VAL_SHFT 16 + /* bits 63:24 unused */ + +/* ==== ca_status2 */ +#define CA_GFX_CREDIT_AVAIL (0xffull << 0) +#define CA_GFX_CREDIT_AVAIL_SHFT 0 +#define CA_GFX_OPQ_AVAIL (0xffull << 8) +#define CA_GFX_OPQ_AVAIL_SHFT 8 +#define CA_GFX_WRBUFF_AVAIL (0xffull << 16) +#define CA_GFX_WRBUFF_AVAIL_SHFT 16 +#define CA_ADMA_OPQ_AVAIL (0xffull << 24) +#define CA_ADMA_OPQ_AVAIL_SHFT 24 +#define CA_ADMA_WRBUFF_AVAIL (0xffull << 32) +#define CA_ADMA_WRBUFF_AVAIL_SHFT 32 +#define CA_ADMA_RDBUFF_AVAIL (0x7full << 40) +#define CA_ADMA_RDBUFF_AVAIL_SHFT 40 +#define CA_PCI_PIO_OP_STAT (1ull << 47) +#define CA_PDMA_OPQ_AVAIL (0xfull << 48) +#define CA_PDMA_OPQ_AVAIL_SHFT 48 +#define CA_PDMA_WRBUFF_AVAIL (0xfull << 52) +#define CA_PDMA_WRBUFF_AVAIL_SHFT 52 +#define CA_PDMA_RDBUFF_AVAIL (0x3ull << 56) +#define CA_PDMA_RDBUFF_AVAIL_SHFT 56 + /* bits 63:58 unused */ + +/* ==== ca_gart_aperature */ +#define CA_GART_AP_ENB_AGP (1ull << 0) +#define CA_GART_PAGE_SIZE (1ull << 1) +#define CA_GART_AP_ENB_PCI (1ull << 2) + /* bits 11:3 unused */ +#define CA_GART_AP_SIZE (0x3ffull << 12) +#define CA_GART_AP_SIZE_SHFT 12 +#define CA_GART_AP_BASE (0x3ffffffffffull << 22) +#define CA_GART_AP_BASE_SHFT 22 + +/* ==== ca_inta_dest_addr + ==== ca_intb_dest_addr + ==== ca_err_int_dest_addr */ + /* bits 2:0 unused */ +#define CA_INT_DEST_ADDR (0x7ffffffffffffull << 3) +#define CA_INT_DEST_ADDR_SHFT 3 + /* bits 55:54 unused */ +#define CA_INT_DEST_VECT (0xffull << 56) +#define CA_INT_DEST_VECT_SHFT 56 + +/* ==== ca_int_status */ +/* ==== ca_int_status_alias */ +/* ==== ca_mult_error */ +/* ==== ca_mult_error_alias */ +/* ==== ca_first_error */ +/* ==== ca_int_mask */ +#define CA_PCI_ERR (1ull << 0) + /* bits 3:1 unused */ +#define CA_GART_FETCH_ERR (1ull << 4) +#define CA_GFX_WR_OVFLW (1ull << 5) +#define CA_PIO_REQ_OVFLW (1ull << 6) +#define CA_CRM_PKTERR (1ull << 7) +#define CA_CRM_DVERR (1ull << 8) +#define CA_TNUMTO (1ull << 9) +#define CA_CXM_RSP_CRED_OVFLW (1ull << 10) +#define CA_CXM_REQ_CRED_OVFLW (1ull << 11) +#define CA_PIO_INVALID_ADDR (1ull << 12) +#define CA_PCI_ARB_TO (1ull << 13) +#define CA_AGP_REQ_OFLOW (1ull << 14) +#define CA_SBA_TYPE1_ERR (1ull << 15) + /* bit 16 unused */ +#define CA_INTA (1ull << 17) +#define CA_INTB (1ull << 18) +#define CA_MULT_INTA (1ull << 19) +#define CA_MULT_INTB (1ull << 20) +#define CA_GFX_CREDIT_OVFLW (1ull << 21) + /* bits 63:22 unused */ + +/* ==== ca_crm_pkterr_type */ +/* ==== ca_crm_pkterr_type_alias */ +#define CA_CRM_PKTERR_SBERR_HDR (1ull << 0) +#define CA_CRM_PKTERR_DIDN (1ull << 1) +#define CA_CRM_PKTERR_PACTYPE (1ull << 2) +#define CA_CRM_PKTERR_INV_TNUM (1ull << 3) +#define CA_CRM_PKTERR_ADDR_RNG (1ull << 4) +#define CA_CRM_PKTERR_ADDR_ALGN (1ull << 5) +#define CA_CRM_PKTERR_HDR_PARAM (1ull << 6) +#define CA_CRM_PKTERR_CW_ERR (1ull << 7) +#define CA_CRM_PKTERR_SBERR_NH (1ull << 8) +#define CA_CRM_PKTERR_EARLY_TERM (1ull << 9) +#define CA_CRM_PKTERR_EARLY_TAIL (1ull << 10) +#define CA_CRM_PKTERR_MSSNG_TAIL (1ull << 11) +#define CA_CRM_PKTERR_MSSNG_HDR (1ull << 12) + /* bits 15:13 unused */ +#define CA_FIRST_CRM_PKTERR_SBERR_HDR (1ull << 16) +#define CA_FIRST_CRM_PKTERR_DIDN (1ull << 17) +#define CA_FIRST_CRM_PKTERR_PACTYPE (1ull << 18) +#define CA_FIRST_CRM_PKTERR_INV_TNUM (1ull << 19) +#define CA_FIRST_CRM_PKTERR_ADDR_RNG (1ull << 20) +#define CA_FIRST_CRM_PKTERR_ADDR_ALGN (1ull << 21) +#define CA_FIRST_CRM_PKTERR_HDR_PARAM (1ull << 22) +#define CA_FIRST_CRM_PKTERR_CW_ERR (1ull << 23) +#define CA_FIRST_CRM_PKTERR_SBERR_NH (1ull << 24) +#define CA_FIRST_CRM_PKTERR_EARLY_TERM (1ull << 25) +#define CA_FIRST_CRM_PKTERR_EARLY_TAIL (1ull << 26) +#define CA_FIRST_CRM_PKTERR_MSSNG_TAIL (1ull << 27) +#define CA_FIRST_CRM_PKTERR_MSSNG_HDR (1ull << 28) + /* bits 63:29 unused */ + +/* ==== ca_crm_ct_error_detail_1 */ +#define CA_PKT_TYPE (0xfull << 0) +#define CA_PKT_TYPE_SHFT 0 +#define CA_SRC_ID (0x3ull << 4) +#define CA_SRC_ID_SHFT 4 +#define CA_DATA_SZ (0x3ull << 6) +#define CA_DATA_SZ_SHFT 6 +#define CA_TNUM (0xffull << 8) +#define CA_TNUM_SHFT 8 +#define CA_DW_DATA_EN (0xffull << 16) +#define CA_DW_DATA_EN_SHFT 16 +#define CA_GFX_CRED (0xffull << 24) +#define CA_GFX_CRED_SHFT 24 +#define CA_MEM_RD_PARAM (0x3ull << 32) +#define CA_MEM_RD_PARAM_SHFT 32 +#define CA_PIO_OP (1ull << 34) +#define CA_CW_ERR (1ull << 35) + /* bits 62:36 unused */ +#define CA_VALID (1ull << 63) + +/* ==== ca_crm_ct_error_detail_2 */ + /* bits 2:0 unused */ +#define CA_PKT_ADDR (0x1fffffffffffffull << 3) +#define CA_PKT_ADDR_SHFT 3 + /* bits 63:56 unused */ + +/* ==== ca_crm_tnumto */ +#define CA_CRM_TNUMTO_VAL (0xffull << 0) +#define CA_CRM_TNUMTO_VAL_SHFT 0 +#define CA_CRM_TNUMTO_WR (1ull << 8) + /* bits 63:9 unused */ + +/* ==== ca_gart_err */ +#define CA_GART_ERR_SOURCE (0x3ull << 0) +#define CA_GART_ERR_SOURCE_SHFT 0 + /* bits 3:2 unused */ +#define CA_GART_ERR_ADDR (0xfffffffffull << 4) +#define CA_GART_ERR_ADDR_SHFT 4 + /* bits 63:40 unused */ + +/* ==== ca_pcierr_type */ +#define CA_PCIERR_DATA (0xffffffffull << 0) +#define CA_PCIERR_DATA_SHFT 0 +#define CA_PCIERR_ENB (0xfull << 32) +#define CA_PCIERR_ENB_SHFT 32 +#define CA_PCIERR_CMD (0xfull << 36) +#define CA_PCIERR_CMD_SHFT 36 +#define CA_PCIERR_A64 (1ull << 40) +#define CA_PCIERR_SLV_SERR (1ull << 41) +#define CA_PCIERR_SLV_WR_PERR (1ull << 42) +#define CA_PCIERR_SLV_RD_PERR (1ull << 43) +#define CA_PCIERR_MST_SERR (1ull << 44) +#define CA_PCIERR_MST_WR_PERR (1ull << 45) +#define CA_PCIERR_MST_RD_PERR (1ull << 46) +#define CA_PCIERR_MST_MABT (1ull << 47) +#define CA_PCIERR_MST_TABT (1ull << 48) +#define CA_PCIERR_MST_RETRY_TOUT (1ull << 49) + +#define CA_PCIERR_TYPES \ + (CA_PCIERR_A64|CA_PCIERR_SLV_SERR| \ + CA_PCIERR_SLV_WR_PERR|CA_PCIERR_SLV_RD_PERR| \ + CA_PCIERR_MST_SERR|CA_PCIERR_MST_WR_PERR|CA_PCIERR_MST_RD_PERR| \ + CA_PCIERR_MST_MABT|CA_PCIERR_MST_TABT|CA_PCIERR_MST_RETRY_TOUT) + + /* bits 63:50 unused */ + +/* ==== ca_pci_dma_addr_extn */ +#define CA_UPPER_NODE_OFFSET (0x3full << 0) +#define CA_UPPER_NODE_OFFSET_SHFT 0 + /* bits 7:6 unused */ +#define CA_CHIPLET_ID (0x3ull << 8) +#define CA_CHIPLET_ID_SHFT 8 + /* bits 11:10 unused */ +#define CA_PCI_DMA_NODE_ID (0xffffull << 12) +#define CA_PCI_DMA_NODE_ID_SHFT 12 + /* bits 27:26 unused */ +#define CA_PCI_DMA_PIO_MEM_TYPE (1ull << 28) + /* bits 63:29 unused */ + + +/* ==== ca_agp_dma_addr_extn */ + /* bits 19:0 unused */ +#define CA_AGP_DMA_NODE_ID (0xffffull << 20) +#define CA_AGP_DMA_NODE_ID_SHFT 20 + /* bits 27:26 unused */ +#define CA_AGP_DMA_PIO_MEM_TYPE (1ull << 28) + /* bits 63:29 unused */ + +/* ==== ca_debug_vector_sel */ +#define CA_DEBUG_MN_VSEL (0xfull << 0) +#define CA_DEBUG_MN_VSEL_SHFT 0 +#define CA_DEBUG_PP_VSEL (0xfull << 4) +#define CA_DEBUG_PP_VSEL_SHFT 4 +#define CA_DEBUG_GW_VSEL (0xfull << 8) +#define CA_DEBUG_GW_VSEL_SHFT 8 +#define CA_DEBUG_GT_VSEL (0xfull << 12) +#define CA_DEBUG_GT_VSEL_SHFT 12 +#define CA_DEBUG_PD_VSEL (0xfull << 16) +#define CA_DEBUG_PD_VSEL_SHFT 16 +#define CA_DEBUG_AD_VSEL (0xfull << 20) +#define CA_DEBUG_AD_VSEL_SHFT 20 +#define CA_DEBUG_CX_VSEL (0xfull << 24) +#define CA_DEBUG_CX_VSEL_SHFT 24 +#define CA_DEBUG_CR_VSEL (0xfull << 28) +#define CA_DEBUG_CR_VSEL_SHFT 28 +#define CA_DEBUG_BA_VSEL (0xfull << 32) +#define CA_DEBUG_BA_VSEL_SHFT 32 +#define CA_DEBUG_PE_VSEL (0xfull << 36) +#define CA_DEBUG_PE_VSEL_SHFT 36 +#define CA_DEBUG_BO_VSEL (0xfull << 40) +#define CA_DEBUG_BO_VSEL_SHFT 40 +#define CA_DEBUG_BI_VSEL (0xfull << 44) +#define CA_DEBUG_BI_VSEL_SHFT 44 +#define CA_DEBUG_AS_VSEL (0xfull << 48) +#define CA_DEBUG_AS_VSEL_SHFT 48 +#define CA_DEBUG_PS_VSEL (0xfull << 52) +#define CA_DEBUG_PS_VSEL_SHFT 52 +#define CA_DEBUG_PM_VSEL (0xfull << 56) +#define CA_DEBUG_PM_VSEL_SHFT 56 + /* bits 63:60 unused */ + +/* ==== ca_debug_mux_core_sel */ +/* ==== ca_debug_mux_pci_sel */ +#define CA_DEBUG_MSEL0 (0x7ull << 0) +#define CA_DEBUG_MSEL0_SHFT 0 + /* bit 3 unused */ +#define CA_DEBUG_NSEL0 (0x7ull << 4) +#define CA_DEBUG_NSEL0_SHFT 4 + /* bit 7 unused */ +#define CA_DEBUG_MSEL1 (0x7ull << 8) +#define CA_DEBUG_MSEL1_SHFT 8 + /* bit 11 unused */ +#define CA_DEBUG_NSEL1 (0x7ull << 12) +#define CA_DEBUG_NSEL1_SHFT 12 + /* bit 15 unused */ +#define CA_DEBUG_MSEL2 (0x7ull << 16) +#define CA_DEBUG_MSEL2_SHFT 16 + /* bit 19 unused */ +#define CA_DEBUG_NSEL2 (0x7ull << 20) +#define CA_DEBUG_NSEL2_SHFT 20 + /* bit 23 unused */ +#define CA_DEBUG_MSEL3 (0x7ull << 24) +#define CA_DEBUG_MSEL3_SHFT 24 + /* bit 27 unused */ +#define CA_DEBUG_NSEL3 (0x7ull << 28) +#define CA_DEBUG_NSEL3_SHFT 28 + /* bit 31 unused */ +#define CA_DEBUG_MSEL4 (0x7ull << 32) +#define CA_DEBUG_MSEL4_SHFT 32 + /* bit 35 unused */ +#define CA_DEBUG_NSEL4 (0x7ull << 36) +#define CA_DEBUG_NSEL4_SHFT 36 + /* bit 39 unused */ +#define CA_DEBUG_MSEL5 (0x7ull << 40) +#define CA_DEBUG_MSEL5_SHFT 40 + /* bit 43 unused */ +#define CA_DEBUG_NSEL5 (0x7ull << 44) +#define CA_DEBUG_NSEL5_SHFT 44 + /* bit 47 unused */ +#define CA_DEBUG_MSEL6 (0x7ull << 48) +#define CA_DEBUG_MSEL6_SHFT 48 + /* bit 51 unused */ +#define CA_DEBUG_NSEL6 (0x7ull << 52) +#define CA_DEBUG_NSEL6_SHFT 52 + /* bit 55 unused */ +#define CA_DEBUG_MSEL7 (0x7ull << 56) +#define CA_DEBUG_MSEL7_SHFT 56 + /* bit 59 unused */ +#define CA_DEBUG_NSEL7 (0x7ull << 60) +#define CA_DEBUG_NSEL7_SHFT 60 + /* bit 63 unused */ + + +/* ==== ca_debug_domain_sel */ +#define CA_DEBUG_DOMAIN_L (1ull << 0) +#define CA_DEBUG_DOMAIN_H (1ull << 1) + /* bits 63:2 unused */ + +/* ==== ca_gart_ptr_table */ +#define CA_GART_PTR_VAL (1ull << 0) + /* bits 11:1 unused */ +#define CA_GART_PTR_ADDR (0xfffffffffffull << 12) +#define CA_GART_PTR_ADDR_SHFT 12 + /* bits 63:56 unused */ + +/* ==== ca_gart_tlb_addr[0-7] */ +#define CA_GART_TLB_ADDR (0xffffffffffffffull << 0) +#define CA_GART_TLB_ADDR_SHFT 0 + /* bits 62:56 unused */ +#define CA_GART_TLB_ENTRY_VAL (1ull << 63) + +/* + * PIO address space ranges for TIO:CA + */ + +/* CA internal registers */ +#define CA_PIO_ADMIN 0x00000000 +#define CA_PIO_ADMIN_LEN 0x00010000 + +/* GFX Write Buffer - Diagnostics */ +#define CA_PIO_GFX 0x00010000 +#define CA_PIO_GFX_LEN 0x00010000 + +/* AGP DMA Write Buffer - Diagnostics */ +#define CA_PIO_AGP_DMAWRITE 0x00020000 +#define CA_PIO_AGP_DMAWRITE_LEN 0x00010000 + +/* AGP DMA READ Buffer - Diagnostics */ +#define CA_PIO_AGP_DMAREAD 0x00030000 +#define CA_PIO_AGP_DMAREAD_LEN 0x00010000 + +/* PCI Config Type 0 */ +#define CA_PIO_PCI_TYPE0_CONFIG 0x01000000 +#define CA_PIO_PCI_TYPE0_CONFIG_LEN 0x01000000 + +/* PCI Config Type 1 */ +#define CA_PIO_PCI_TYPE1_CONFIG 0x02000000 +#define CA_PIO_PCI_TYPE1_CONFIG_LEN 0x01000000 + +/* PCI I/O Cycles - mapped to PCI Address 0x00000000-0x04ffffff */ +#define CA_PIO_PCI_IO 0x03000000 +#define CA_PIO_PCI_IO_LEN 0x05000000 + +/* PCI MEM Cycles - mapped to PCI with CA_PIO_ADDR_OFFSET of ca_control1 */ +/* use Fast Write if enabled and coretalk packet type is a GFX request */ +#define CA_PIO_PCI_MEM_OFFSET 0x08000000 +#define CA_PIO_PCI_MEM_OFFSET_LEN 0x08000000 + +/* PCI MEM Cycles - mapped to PCI Address 0x00000000-0xbfffffff */ +/* use Fast Write if enabled and coretalk packet type is a GFX request */ +#define CA_PIO_PCI_MEM 0x40000000 +#define CA_PIO_PCI_MEM_LEN 0xc0000000 + +/* + * DMA space + * + * The CA aperature (ie. bus address range) mapped by the GART is segmented into + * two parts. The lower portion of the aperature is used for mapping 32 bit + * PCI addresses which are managed by the dma interfaces in this file. The + * upper poprtion of the aperature is used for mapping 48 bit AGP addresses. + * The AGP portion of the aperature is managed by the agpgart_be.c driver + * in drivers/linux/agp. There are ca-specific hooks in that driver to + * manipulate the gart, but management of the AGP portion of the aperature + * is the responsibility of that driver. + * + * CA allows three main types of DMA mapping: + * + * PCI 64-bit Managed by this driver + * PCI 32-bit Managed by this driver + * AGP 48-bit Managed by hooks in the /dev/agpgart driver + * + * All of the above can optionally be remapped through the GART. The following + * table lists the combinations of addressing types and GART remapping that + * is currently supported by the driver (h/w supports all, s/w limits this): + * + * PCI64 PCI32 AGP48 + * GART no yes yes + * Direct yes yes no + * + * GART remapping of PCI64 is not done because there is no need to. The + * 64 bit PCI address holds all of the information necessary to target any + * memory in the system. + * + * AGP48 is always mapped through the GART. Management of the AGP48 portion + * of the aperature is the responsibility of code in the agpgart_be driver. + * + * The non-64 bit bus address space will currently be partitioned like this: + * + * 0xffff_ffff_ffff +-------- + * | AGP48 direct + * | Space managed by this driver + * CA_AGP_DIRECT_BASE +-------- + * | AGP GART mapped (gfx aperature) + * | Space managed by /dev/agpgart driver + * | This range is exposed to the agpgart + * | driver as the "graphics aperature" + * CA_AGP_MAPPED_BASE +----- + * | PCI GART mapped + * | Space managed by this driver + * CA_PCI32_MAPPED_BASE +---- + * | PCI32 direct + * | Space managed by this driver + * 0xC000_0000 +-------- + * (CA_PCI32_DIRECT_BASE) + * + * The bus address range CA_PCI32_MAPPED_BASE through CA_AGP_DIRECT_BASE + * is what we call the CA aperature. Addresses falling in this range will + * be remapped using the GART. + * + * The bus address range CA_AGP_MAPPED_BASE through CA_AGP_DIRECT_BASE + * is what we call the graphics aperature. This is a subset of the CA + * aperature and is under the control of the agpgart_be driver. + * + * CA_PCI32_MAPPED_BASE, CA_AGP_MAPPED_BASE, and CA_AGP_DIRECT_BASE are + * somewhat arbitrary values. The known constraints on choosing these is: + * + * 1) CA_AGP_DIRECT_BASE-CA_PCI32_MAPPED_BASE+1 (the CA aperature size) + * must be one of the values supported by the ca_gart_aperature register. + * Currently valid values are: 4MB through 4096MB in powers of 2 increments + * + * 2) CA_AGP_DIRECT_BASE-CA_AGP_MAPPED_BASE+1 (the gfx aperature size) + * must be in MB units since that's what the agpgart driver assumes. + */ + +/* + * Define Bus DMA ranges. These are configurable (see constraints above) + * and will probably need tuning based on experience. + */ + + +/* + * 11/24/03 + * CA has an addressing glitch w.r.t. PCI direct 32 bit DMA that makes it + * generally unusable. The problem is that for PCI direct 32 + * DMA's, all 32 bits of the bus address are used to form the lower 32 bits + * of the coretalk address, and coretalk bits 38:32 come from a register. + * Since only PCI bus addresses 0xC0000000-0xFFFFFFFF (1GB) are available + * for DMA (the rest is allocated to PIO), host node addresses need to be + * such that their lower 32 bits fall in the 0xC0000000-0xffffffff range + * as well. So there can be no PCI32 direct DMA below 3GB!! For this + * reason we set the CA_PCI32_DIRECT_SIZE to 0 which essentially makes + * tioca_dma_direct32() a noop but preserves the code flow should this issue + * be fixed in a respin. + * + * For now, all PCI32 DMA's must be mapped through the GART. + */ + +#define CA_PCI32_DIRECT_BASE 0xC0000000UL /* BASE not configurable */ +#define CA_PCI32_DIRECT_SIZE 0x00000000UL /* 0 MB */ + +#define CA_PCI32_MAPPED_BASE 0xC0000000UL +#define CA_PCI32_MAPPED_SIZE 0x40000000UL /* 2GB */ + +#define CA_AGP_MAPPED_BASE 0x80000000UL +#define CA_AGP_MAPPED_SIZE 0x40000000UL /* 2GB */ + +#define CA_AGP_DIRECT_BASE 0x40000000UL /* 2GB */ +#define CA_AGP_DIRECT_SIZE 0x40000000UL + +#define CA_APERATURE_BASE (CA_AGP_MAPPED_BASE) +#define CA_APERATURE_SIZE (CA_AGP_MAPPED_SIZE+CA_PCI32_MAPPED_SIZE) + +#endif /* _ASM_IA64_SN_TIO_TIOCA_H */ diff --git a/include/asm-ia64/sn/tiocx.h b/include/asm-ia64/sn/tiocx.h new file mode 100644 index 000000000..c5447a504 --- /dev/null +++ b/include/asm-ia64/sn/tiocx.h @@ -0,0 +1,71 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved. + */ + +#ifndef _ASM_IA64_SN_TIO_TIOCX_H +#define _ASM_IA64_SN_TIO_TIOCX_H + +#ifdef __KERNEL__ + +struct cx_id_s { + unsigned int part_num; + unsigned int mfg_num; + int nasid; +}; + +struct cx_dev { + struct cx_id_s cx_id; + void *soft; /* driver specific */ + struct hubdev_info *hubdev; + struct device dev; + struct cx_drv *driver; +}; + +struct cx_device_id { + unsigned int part_num; + unsigned int mfg_num; +}; + +struct cx_drv { + char *name; + const struct cx_device_id *id_table; + struct device_driver driver; + int (*probe) (struct cx_dev * dev, const struct cx_device_id * id); + int (*remove) (struct cx_dev * dev); +}; + +/* create DMA address by stripping AS bits */ +#define TIOCX_DMA_ADDR(a) (uint64_t)((uint64_t)(a) & 0xffffcfffffffffUL) + +#define TIOCX_TO_TIOCX_DMA_ADDR(a) (uint64_t)(((uint64_t)(a) & 0xfffffffff) | \ + ((((uint64_t)(a)) & 0xffffc000000000UL) <<2)) + +#define TIO_CE_ASIC_PARTNUM 0xce00 +#define TIOCX_CORELET 3 + +/* These are taken from tio_mmr_as.h */ +#define TIO_ICE_FRZ_CFG TIO_MMR_ADDR_MOD(0x00000000b0008100UL) +#define TIO_ICE_PMI_TX_CFG TIO_MMR_ADDR_MOD(0x00000000b000b100UL) +#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3 TIO_MMR_ADDR_MOD(0x00000000b000be18UL) +#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK 0x000000000000000fUL + +#define to_cx_dev(n) container_of(n, struct cx_dev, dev) +#define to_cx_driver(drv) container_of(drv, struct cx_drv, driver) + +extern struct sn_irq_info *tiocx_irq_alloc(nasid_t, int, int, nasid_t, int); +extern void tiocx_irq_free(struct sn_irq_info *); +extern int cx_device_unregister(struct cx_dev *); +extern int cx_device_register(nasid_t, int, int, struct hubdev_info *); +extern int cx_driver_unregister(struct cx_drv *); +extern int cx_driver_register(struct cx_drv *); +extern uint64_t tiocx_dma_addr(uint64_t addr); +extern uint64_t tiocx_swin_base(int nasid); +extern void tiocx_mmr_store(int nasid, uint64_t offset, uint64_t value); +extern uint64_t tiocx_mmr_load(int nasid, uint64_t offset); + +#endif // __KERNEL__ +#endif // _ASM_IA64_SN_TIO_TIOCX__ diff --git a/include/asm-mips/vr41xx/pci.h b/include/asm-mips/vr41xx/pci.h new file mode 100644 index 000000000..c473aa78d --- /dev/null +++ b/include/asm-mips/vr41xx/pci.h @@ -0,0 +1,90 @@ +/* + * Include file for NEC VR4100 series PCI Control Unit. + * + * Copyright (C) 2004-2005 Yoichi Yuasa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __NEC_VR41XX_PCI_H +#define __NEC_VR41XX_PCI_H + +#define PCI_MASTER_ADDRESS_MASK 0x7fffffffU + +struct pci_master_address_conversion { + uint32_t bus_base_address; + uint32_t address_mask; + uint32_t pci_base_address; +}; + +struct pci_target_address_conversion { + uint32_t address_mask; + uint32_t bus_base_address; +}; + +typedef enum { + CANNOT_LOCK_FROM_DEVICE, + CAN_LOCK_FROM_DEVICE, +} pci_exclusive_access_t; + +struct pci_mailbox_address { + uint32_t base_address; +}; + +struct pci_target_address_window { + uint32_t base_address; +}; + +typedef enum { + PCI_ARBITRATION_MODE_FAIR, + PCI_ARBITRATION_MODE_ALTERNATE_0, + PCI_ARBITRATION_MODE_ALTERNATE_B, +} pci_arbiter_priority_control_t; + +typedef enum { + PCI_TAKE_AWAY_GNT_DISABLE, + PCI_TAKE_AWAY_GNT_ENABLE, +} pci_take_away_gnt_mode_t; + +struct pci_controller_unit_setup { + struct pci_master_address_conversion *master_memory1; + struct pci_master_address_conversion *master_memory2; + + struct pci_target_address_conversion *target_memory1; + struct pci_target_address_conversion *target_memory2; + + struct pci_master_address_conversion *master_io; + + pci_exclusive_access_t exclusive_access; + + uint32_t pci_clock_max; + uint8_t wait_time_limit_from_irdy_to_trdy; /* Only VR4122 is supported */ + + struct pci_mailbox_address *mailbox; + struct pci_target_address_window *target_window1; + struct pci_target_address_window *target_window2; + + uint8_t master_latency_timer; + uint8_t retry_limit; + + pci_arbiter_priority_control_t arbiter_priority_control; + pci_take_away_gnt_mode_t take_away_gnt_mode; + + struct resource *mem_resource; + struct resource *io_resource; +}; + +extern void vr41xx_pciu_setup(struct pci_controller_unit_setup *setup); + +#endif /* __NEC_VR41XX_PCI_H */ diff --git a/include/asm-mips/vr41xx/siu.h b/include/asm-mips/vr41xx/siu.h new file mode 100644 index 000000000..865cc07dd --- /dev/null +++ b/include/asm-mips/vr41xx/siu.h @@ -0,0 +1,50 @@ +/* + * Include file for NEC VR4100 series Serial Interface Unit. + * + * Copyright (C) 2005 Yoichi Yuasa + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __NEC_VR41XX_SIU_H +#define __NEC_VR41XX_SIU_H + +typedef enum { + SIU_INTERFACE_RS232C, + SIU_INTERFACE_IRDA, +} siu_interface_t; + +extern void vr41xx_select_siu_interface(siu_interface_t interface); + +typedef enum { + SIU_USE_IRDA, + FIR_USE_IRDA, +} irda_use_t; + +extern void vr41xx_use_irda(irda_use_t use); + +typedef enum { + SHARP_IRDA, + TEMIC_IRDA, + HP_IRDA, +} irda_module_t; + +typedef enum { + IRDA_TX_1_5MBPS, + IRDA_TX_4MBPS, +} irda_speed_t; + +extern void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed); + +#endif /* __NEC_VR41XX_SIU_H */ diff --git a/include/asm-ppc/suspend.h b/include/asm-ppc/suspend.h new file mode 100644 index 000000000..3df9f32bd --- /dev/null +++ b/include/asm-ppc/suspend.h @@ -0,0 +1,12 @@ +static inline int arch_prepare_suspend(void) +{ + return 0; +} + +static inline void save_processor_state(void) +{ +} + +static inline void restore_processor_state(void) +{ +} diff --git a/include/asm-sh/cpu-sh4/timer.h b/include/asm-sh/cpu-sh4/timer.h new file mode 100644 index 000000000..8a4af126c --- /dev/null +++ b/include/asm-sh/cpu-sh4/timer.h @@ -0,0 +1,51 @@ +/* + * include/asm-sh/cpu-sh4/timer.h + * + * Copyright (C) 2004 Lineo Solutions, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef __ASM_CPU_SH4_TIMER_H +#define __ASM_CPU_SH4_TIMER_H + +/* + * --------------------------------------------------------------------------- + * TMU Common definitions for SH4 processors + * SH7750S/SH7750R + * SH7751/SH7751R + * SH7760 + * --------------------------------------------------------------------------- + */ + +#if !defined(CONFIG_CPU_SUBTYPE_SH7760) +#define TMU_TOCR 0xffd80000 /* Byte access */ +#endif +#define TMU_TSTR 0xffd80004 /* Byte access */ + +#define TMU0_TCOR 0xffd80008 /* Long access */ +#define TMU0_TCNT 0xffd8000c /* Long access */ +#define TMU0_TCR 0xffd80010 /* Word access */ + +#define TMU1_TCOR 0xffd80014 /* Long access */ +#define TMU1_TCNT 0xffd80018 /* Long access */ +#define TMU1_TCR 0xffd8001c /* Word access */ + +#define TMU2_TCOR 0xffd80020 /* Long access */ +#define TMU2_TCNT 0xffd80024 /* Long access */ +#define TMU2_TCR 0xffd80028 /* Word access */ +#define TMU2_TCPR 0xffd8002c /* Long access */ + +#if !defined(CONFIG_CPU_SUBTYPE_SH7760) +#define TMU3_TCOR 0xfe100008 /* Long access */ +#define TMU3_TCNT 0xfe10000c /* Long access */ +#define TMU3_TCR 0xfe100010 /* Word access */ + +#define TMU4_TCOR 0xfe100014 /* Long access */ +#define TMU4_TCNT 0xfe100018 /* Long access */ +#define TMU4_TCR 0xfe10001c /* Word access */ +#endif + +#endif /* __ASM_CPU_SH4_TIMER_H */ + diff --git a/include/asm-sparc64/rwsem-const.h b/include/asm-sparc64/rwsem-const.h new file mode 100644 index 000000000..a303c9d64 --- /dev/null +++ b/include/asm-sparc64/rwsem-const.h @@ -0,0 +1,12 @@ +/* rwsem-const.h: RW semaphore counter constants. */ +#ifndef _SPARC64_RWSEM_CONST_H +#define _SPARC64_RWSEM_CONST_H + +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS 0xffff0000 +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + +#endif /* _SPARC64_RWSEM_CONST_H */ diff --git a/include/asm-um/elf-i386.h b/include/asm-um/elf-i386.h new file mode 100644 index 000000000..9bab712dc --- /dev/null +++ b/include/asm-um/elf-i386.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ +#ifndef __UM_ELF_I386_H +#define __UM_ELF_I386_H + +#include + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_i387_struct elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) \ + (((x)->e_machine == EM_386) || ((x)->e_machine == EM_486)) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_386 + +#define ELF_PLAT_INIT(regs, load_addr) do { \ + PT_REGS_EBX(regs) = 0; \ + PT_REGS_ECX(regs) = 0; \ + PT_REGS_EDX(regs) = 0; \ + PT_REGS_ESI(regs) = 0; \ + PT_REGS_EDI(regs) = 0; \ + PT_REGS_EBP(regs) = 0; \ + PT_REGS_EAX(regs) = 0; \ +} while(0) + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + +/* Shamelessly stolen from include/asm-i386/elf.h */ + +#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \ + pr_reg[0] = PT_REGS_EBX(regs); \ + pr_reg[1] = PT_REGS_ECX(regs); \ + pr_reg[2] = PT_REGS_EDX(regs); \ + pr_reg[3] = PT_REGS_ESI(regs); \ + pr_reg[4] = PT_REGS_EDI(regs); \ + pr_reg[5] = PT_REGS_EBP(regs); \ + pr_reg[6] = PT_REGS_EAX(regs); \ + pr_reg[7] = PT_REGS_DS(regs); \ + pr_reg[8] = PT_REGS_ES(regs); \ + /* fake once used fs and gs selectors? */ \ + pr_reg[9] = PT_REGS_DS(regs); \ + pr_reg[10] = PT_REGS_DS(regs); \ + pr_reg[11] = PT_REGS_SYSCALL_NR(regs); \ + pr_reg[12] = PT_REGS_IP(regs); \ + pr_reg[13] = PT_REGS_CS(regs); \ + pr_reg[14] = PT_REGS_EFLAGS(regs); \ + pr_reg[15] = PT_REGS_SP(regs); \ + pr_reg[16] = PT_REGS_SS(regs); \ +} while(0); + +extern long elf_aux_hwcap; +#define ELF_HWCAP (elf_aux_hwcap) + +extern char * elf_aux_platform; +#define ELF_PLATFORM (elf_aux_platform) + +#define SET_PERSONALITY(ex, ibcs2) do ; while(0) + +extern unsigned long vsyscall_ehdr; +extern unsigned long vsyscall_end; +extern unsigned long __kernel_vsyscall; + +#define VSYSCALL_BASE vsyscall_ehdr +#define VSYSCALL_END vsyscall_end + +/* + * This is the range that is readable by user mode, and things + * acting like user mode such as get_user_pages. + */ +#define FIXADDR_USER_START VSYSCALL_BASE +#define FIXADDR_USER_END VSYSCALL_END + +/* + * Architecture-neutral AT_ values in 0-17, leave some room + * for more of them, start the x86-specific ones at 32. + */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + +#define ARCH_DLINFO \ +do { \ + if ( vsyscall_ehdr ) { \ + NEW_AUX_ENT(AT_SYSINFO, __kernel_vsyscall); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, vsyscall_ehdr); \ + } \ +} while (0) + +/* + * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out + * extra segments containing the vsyscall DSO contents. Dumping its + * contents makes post-mortem fully interpretable later without matching up + * the same kernel and hardware config to see what PC values meant. + * Dumping its extra ELF program headers includes all the other information + * a debugger needs to easily find how the vsyscall DSO was being used. + */ +#define ELF_CORE_EXTRA_PHDRS \ + (vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0 ) + +#define ELF_CORE_WRITE_EXTRA_PHDRS \ +if ( vsyscall_ehdr ) { \ + const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr; \ + const struct elf_phdr *const phdrp = \ + (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); \ + int i; \ + Elf32_Off ofs = 0; \ + for (i = 0; i < ehdrp->e_phnum; ++i) { \ + struct elf_phdr phdr = phdrp[i]; \ + if (phdr.p_type == PT_LOAD) { \ + ofs = phdr.p_offset = offset; \ + offset += phdr.p_filesz; \ + } \ + else \ + phdr.p_offset += ofs; \ + phdr.p_paddr = 0; /* match other core phdrs */ \ + DUMP_WRITE(&phdr, sizeof(phdr)); \ + } \ +} +#define ELF_CORE_WRITE_EXTRA_DATA \ +if ( vsyscall_ehdr ) { \ + const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr; \ + const struct elf_phdr *const phdrp = \ + (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); \ + int i; \ + for (i = 0; i < ehdrp->e_phnum; ++i) { \ + if (phdrp[i].p_type == PT_LOAD) \ + DUMP_WRITE((void *) phdrp[i].p_vaddr, \ + phdrp[i].p_filesz); \ + } \ +} + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-um/elf-x86_64.h b/include/asm-um/elf-x86_64.h new file mode 100644 index 000000000..8a8246d03 --- /dev/null +++ b/include/asm-um/elf-x86_64.h @@ -0,0 +1,95 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ +#ifndef __UM_ELF_X86_64_H +#define __UM_ELF_X86_64_H + +#include + +/* x86-64 relocation types, taken from asm-x86_64/elf.h */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed pc relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct { } elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) \ + ((x)->e_machine == EM_X86_64) + +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2LSB +#define ELF_ARCH EM_X86_64 + +#define ELF_PLAT_INIT(regs, load_addr) do { \ + PT_REGS_RBX(regs) = 0; \ + PT_REGS_RCX(regs) = 0; \ + PT_REGS_RDX(regs) = 0; \ + PT_REGS_RSI(regs) = 0; \ + PT_REGS_RDI(regs) = 0; \ + PT_REGS_RBP(regs) = 0; \ + PT_REGS_RAX(regs) = 0; \ + PT_REGS_R8(regs) = 0; \ + PT_REGS_R9(regs) = 0; \ + PT_REGS_R10(regs) = 0; \ + PT_REGS_R11(regs) = 0; \ + PT_REGS_R12(regs) = 0; \ + PT_REGS_R13(regs) = 0; \ + PT_REGS_R14(regs) = 0; \ + PT_REGS_R15(regs) = 0; \ +} while (0) + +#ifdef TIF_IA32 /* XXX */ +#error XXX, indeed + clear_thread_flag(TIF_IA32); +#endif + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + +extern long elf_aux_hwcap; +#define ELF_HWCAP (elf_aux_hwcap) + +#define ELF_PLATFORM "x86_64" + +#define SET_PERSONALITY(ex, ibcs2) do ; while(0) + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/include/asm-x86_64/seccomp.h b/include/asm-x86_64/seccomp.h new file mode 100644 index 000000000..553af65a2 --- /dev/null +++ b/include/asm-x86_64/seccomp.h @@ -0,0 +1,24 @@ +#ifndef _ASM_SECCOMP_H + +#include + +#ifdef TIF_32BIT +#error "unexpected TIF_32BIT on x86_64" +#else +#define TIF_32BIT TIF_IA32 +#endif + +#include +#include + +#define __NR_seccomp_read __NR_read +#define __NR_seccomp_write __NR_write +#define __NR_seccomp_exit __NR_exit +#define __NR_seccomp_sigreturn __NR_rt_sigreturn + +#define __NR_seccomp_read_32 __NR_ia32_read +#define __NR_seccomp_write_32 __NR_ia32_write +#define __NR_seccomp_exit_32 __NR_ia32_exit +#define __NR_seccomp_sigreturn_32 __NR_ia32_sigreturn + +#endif /* _ASM_SECCOMP_H */ diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h new file mode 100644 index 000000000..53686c037 --- /dev/null +++ b/include/linux/compiler-gcc4.h @@ -0,0 +1,16 @@ +/* Never include this file directly. Include instead. */ + +/* These definitions are for GCC v4.x. */ +#include + +#define inline inline __attribute__((always_inline)) +#define __inline__ __inline__ __attribute__((always_inline)) +#define __inline __inline __attribute__((always_inline)) +#define __deprecated __attribute__((deprecated)) +#define __attribute_used__ __attribute__((__used__)) +#define __attribute_pure__ __attribute__((pure)) +#define __attribute_const__ __attribute__((__const__)) +#define noinline __attribute__((noinline)) +#define __must_check __attribute__((warn_unused_result)) +#define __compiler_offsetof(a,b) __builtin_offsetof(a,b) + diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h new file mode 100644 index 000000000..c118b2ad9 --- /dev/null +++ b/include/linux/cryptohash.h @@ -0,0 +1,12 @@ +#ifndef __CRYPTOHASH_H +#define __CRYPTOHASH_H + +#define SHA_DIGEST_WORDS 5 +#define SHA_WORKSPACE_WORDS 80 + +void sha_init(__u32 *buf); +void sha_transform(__u32 *digest, const char *data, __u32 *W); + +__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]); + +#endif diff --git a/include/linux/hdpu_features.h b/include/linux/hdpu_features.h new file mode 100644 index 000000000..6a8715431 --- /dev/null +++ b/include/linux/hdpu_features.h @@ -0,0 +1,26 @@ +#include + +struct cpustate_t { + spinlock_t lock; + int excl; + int open_count; + unsigned char cached_val; + int inited; + unsigned long *set_addr; + unsigned long *clr_addr; +}; + + +#define HDPU_CPUSTATE_NAME "hdpu cpustate" +#define HDPU_NEXUS_NAME "hdpu nexus" + +#define CPUSTATE_KERNEL_MAJOR 0x10 + +#define CPUSTATE_KERNEL_INIT_DRV 0 /* CPU State Driver Initialized */ +#define CPUSTATE_KERNEL_INIT_PCI 1 /* 64360 PCI Busses Init */ +#define CPUSTATE_KERNEL_INIT_REG 2 /* 64360 Bridge Init */ +#define CPUSTATE_KERNEL_CPU1_KICK 3 /* Boot cpu 1 */ +#define CPUSTATE_KERNEL_CPU1_OK 4 /* Cpu 1 has checked in */ +#define CPUSTATE_KERNEL_OK 5 /* Terminal state */ +#define CPUSTATE_KERNEL_RESET 14 /* Board reset via SW*/ +#define CPUSTATE_KERNEL_HALT 15 /* Board halted via SW*/ diff --git a/include/linux/ip_mp_alg.h b/include/linux/ip_mp_alg.h new file mode 100644 index 000000000..e234e2008 --- /dev/null +++ b/include/linux/ip_mp_alg.h @@ -0,0 +1,22 @@ +/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values. + * + * Copyright (C) 2004, 2005 Einar Lueck + * Copyright (C) 2005 David S. Miller + */ + +#ifndef _LINUX_IP_MP_ALG_H +#define _LINUX_IP_MP_ALG_H + +enum ip_mp_alg { + IP_MP_ALG_NONE, + IP_MP_ALG_RR, + IP_MP_ALG_DRR, + IP_MP_ALG_RANDOM, + IP_MP_ALG_WRANDOM, + __IP_MP_ALG_MAX +}; + +#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1) + +#endif /* _LINUX_IP_MP_ALG_H */ + diff --git a/include/linux/patchkey.h b/include/linux/patchkey.h new file mode 100644 index 000000000..d974a6e92 --- /dev/null +++ b/include/linux/patchkey.h @@ -0,0 +1,45 @@ +/* + * -- definition of _PATCHKEY macro + * + * Copyright (C) 2005 Stuart Brady + * + * This exists because awe_voice.h defined its own _PATCHKEY and it wasn't + * clear whether removing this would break anything in userspace. + * + * Do not include this file directly. Please use instead. + * For kernel code, use + */ + +#ifndef _LINUX_PATCHKEY_H_INDIRECT +#error "patchkey.h included directly" +#endif + +#ifndef _LINUX_PATCHKEY_H +#define _LINUX_PATCHKEY_H + +/* Endian macros. */ +#ifdef __KERNEL__ +# include +#else +# include +#endif + +#if defined(__KERNEL__) +# if defined(__BIG_ENDIAN) +# define _PATCHKEY(id) (0xfd00|id) +# elif defined(__LITTLE_ENDIAN) +# define _PATCHKEY(id) ((id<<8)|0x00fd) +# else +# error "could not determine byte order" +# endif +#elif defined(__BYTE_ORDER) +# if __BYTE_ORDER == __BIG_ENDIAN +# define _PATCHKEY(id) (0xfd00|id) +# elif __BYTE_ORDER == __LITTLE_ENDIAN +# define _PATCHKEY(id) ((id<<8)|0x00fd) +# else +# error "could not determine byte order" +# endif +#endif + +#endif /* _LINUX_PATCHKEY_H */ diff --git a/include/linux/reboot_fixups.h b/include/linux/reboot_fixups.h new file mode 100644 index 000000000..480ea2d48 --- /dev/null +++ b/include/linux/reboot_fixups.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_REBOOT_FIXUPS_H +#define _LINUX_REBOOT_FIXUPS_H + +#ifdef CONFIG_X86_REBOOTFIXUPS +extern void mach_reboot_fixups(void); +#else +#define mach_reboot_fixups() ((void)(0)) +#endif + +#endif /* _LINUX_REBOOT_FIXUPS_H */ diff --git a/include/linux/sort.h b/include/linux/sort.h new file mode 100644 index 000000000..d534da2b5 --- /dev/null +++ b/include/linux/sort.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_SORT_H +#define _LINUX_SORT_H + +#include + +void sort(void *base, size_t num, size_t size, + int (*cmp)(const void *, const void *), + void (*swap)(void *, void *, int)); + +#endif diff --git a/include/linux/superhyway.h b/include/linux/superhyway.h new file mode 100644 index 000000000..c906c5a0a --- /dev/null +++ b/include/linux/superhyway.h @@ -0,0 +1,79 @@ +/* + * include/linux/superhyway.h + * + * SuperHyway Bus definitions + * + * Copyright (C) 2004, 2005 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#ifndef __LINUX_SUPERHYWAY_H +#define __LINUX_SUPERHYWAY_H + +#include + +/* + * SuperHyway IDs + */ +#define SUPERHYWAY_DEVICE_ID_SH5_DMAC 0x0183 + +struct vcr_info { + u8 perr_flags; /* P-port Error flags */ + u8 merr_flags; /* Module Error flags */ + u16 mod_vers; /* Module Version */ + u16 mod_id; /* Module ID */ + u8 bot_mb; /* Bottom Memory block */ + u8 top_mb; /* Top Memory block */ +}; + +struct superhyway_device_id { + unsigned int id; + unsigned long driver_data; +}; + +struct superhyway_device; +extern struct bus_type superhyway_bus_type; + +struct superhyway_driver { + char *name; + + const struct superhyway_device_id *id_table; + struct device_driver drv; + + int (*probe)(struct superhyway_device *dev, const struct superhyway_device_id *id); + void (*remove)(struct superhyway_device *dev); +}; + +#define to_superhyway_driver(d) container_of((d), struct superhyway_driver, drv) + +struct superhyway_device { + char name[32]; + + struct device dev; + + struct superhyway_device_id id; + struct superhyway_driver *drv; + + struct resource resource; + struct vcr_info vcr; +}; + +#define to_superhyway_device(d) container_of((d), struct superhyway_device, dev) + +#define superhyway_get_drvdata(d) dev_get_drvdata(&(d)->dev) +#define superhyway_set_drvdata(d,p) dev_set_drvdata(&(d)->dev, (p)) + +extern int superhyway_scan_bus(void); + +/* drivers/sh/superhyway/superhyway.c */ +int superhyway_register_driver(struct superhyway_driver *); +void superhyway_unregister_driver(struct superhyway_driver *); +int superhyway_add_device(unsigned int, unsigned long, unsigned long long); + +/* drivers/sh/superhyway/superhyway-sysfs.c */ +extern struct device_attribute superhyway_dev_attrs[]; + +#endif /* __LINUX_SUPERHYWAY_H */ + diff --git a/include/linux/tc_act/tc_defact.h b/include/linux/tc_act/tc_defact.h new file mode 100644 index 000000000..964f473af --- /dev/null +++ b/include/linux/tc_act/tc_defact.h @@ -0,0 +1,21 @@ +#ifndef __LINUX_TC_DEF_H +#define __LINUX_TC_DEF_H + +#include + +struct tc_defact +{ + tc_gen; +}; + +enum +{ + TCA_DEF_UNSPEC, + TCA_DEF_TM, + TCA_DEF_PARMS, + TCA_DEF_DATA, + __TCA_DEF_MAX +}; +#define TCA_DEF_MAX (__TCA_DEF_MAX - 1) + +#endif diff --git a/include/linux/tc_ematch/tc_em_cmp.h b/include/linux/tc_ematch/tc_em_cmp.h new file mode 100644 index 000000000..c7f4d4361 --- /dev/null +++ b/include/linux/tc_ematch/tc_em_cmp.h @@ -0,0 +1,26 @@ +#ifndef __LINUX_TC_EM_CMP_H +#define __LINUX_TC_EM_CMP_H + +#include + +struct tcf_em_cmp +{ + __u32 val; + __u32 mask; + __u16 off; + __u8 align:4; + __u8 flags:4; + __u8 layer:4; + __u8 opnd:4; +}; + +enum +{ + TCF_EM_ALIGN_U8 = 1, + TCF_EM_ALIGN_U16 = 2, + TCF_EM_ALIGN_U32 = 4 +}; + +#define TCF_EM_CMP_TRANS 1 + +#endif diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/linux/tc_ematch/tc_em_meta.h new file mode 100644 index 000000000..a6b2cc530 --- /dev/null +++ b/include/linux/tc_ematch/tc_em_meta.h @@ -0,0 +1,99 @@ +#ifndef __LINUX_TC_EM_META_H +#define __LINUX_TC_EM_META_H + +#include + +enum +{ + TCA_EM_META_UNSPEC, + TCA_EM_META_HDR, + TCA_EM_META_LVALUE, + TCA_EM_META_RVALUE, + __TCA_EM_META_MAX +}; +#define TCA_EM_META_MAX (__TCA_EM_META_MAX - 1) + +struct tcf_meta_val +{ + __u16 kind; + __u8 shift; + __u8 op; +}; + +#define TCF_META_TYPE_MASK (0xf << 12) +#define TCF_META_TYPE(kind) (((kind) & TCF_META_TYPE_MASK) >> 12) +#define TCF_META_ID_MASK 0x7ff +#define TCF_META_ID(kind) ((kind) & TCF_META_ID_MASK) + +enum +{ + TCF_META_TYPE_VAR, + TCF_META_TYPE_INT, + __TCF_META_TYPE_MAX +}; +#define TCF_META_TYPE_MAX (__TCF_META_TYPE_MAX - 1) + +enum +{ + TCF_META_ID_VALUE, + TCF_META_ID_RANDOM, + TCF_META_ID_LOADAVG_0, + TCF_META_ID_LOADAVG_1, + TCF_META_ID_LOADAVG_2, + TCF_META_ID_DEV, + TCF_META_ID_INDEV, + TCF_META_ID_REALDEV, + TCF_META_ID_PRIORITY, + TCF_META_ID_PROTOCOL, + TCF_META_ID_SECURITY, + TCF_META_ID_PKTTYPE, + TCF_META_ID_PKTLEN, + TCF_META_ID_DATALEN, + TCF_META_ID_MACLEN, + TCF_META_ID_NFMARK, + TCF_META_ID_TCINDEX, + TCF_META_ID_TCVERDICT, + TCF_META_ID_TCCLASSID, + TCF_META_ID_RTCLASSID, + TCF_META_ID_RTIIF, + TCF_META_ID_SK_FAMILY, + TCF_META_ID_SK_STATE, + TCF_META_ID_SK_REUSE, + TCF_META_ID_SK_BOUND_IF, + TCF_META_ID_SK_REFCNT, + TCF_META_ID_SK_SHUTDOWN, + TCF_META_ID_SK_PROTO, + TCF_META_ID_SK_TYPE, + TCF_META_ID_SK_RCVBUF, + TCF_META_ID_SK_RMEM_ALLOC, + TCF_META_ID_SK_WMEM_ALLOC, + TCF_META_ID_SK_OMEM_ALLOC, + TCF_META_ID_SK_WMEM_QUEUED, + TCF_META_ID_SK_RCV_QLEN, + TCF_META_ID_SK_SND_QLEN, + TCF_META_ID_SK_ERR_QLEN, + TCF_META_ID_SK_FORWARD_ALLOCS, + TCF_META_ID_SK_SNDBUF, + TCF_META_ID_SK_ALLOCS, + TCF_META_ID_SK_ROUTE_CAPS, + TCF_META_ID_SK_HASHENT, + TCF_META_ID_SK_LINGERTIME, + TCF_META_ID_SK_ACK_BACKLOG, + TCF_META_ID_SK_MAX_ACK_BACKLOG, + TCF_META_ID_SK_PRIO, + TCF_META_ID_SK_RCVLOWAT, + TCF_META_ID_SK_RCVTIMEO, + TCF_META_ID_SK_SNDTIMEO, + TCF_META_ID_SK_SENDMSG_OFF, + TCF_META_ID_SK_WRITE_PENDING, + __TCF_META_ID_MAX +}; +#define TCF_META_ID_MAX (__TCF_META_ID_MAX - 1) + +struct tcf_meta_hdr +{ + struct tcf_meta_val left; + struct tcf_meta_val right; +}; + +#endif diff --git a/include/linux/tc_ematch/tc_em_nbyte.h b/include/linux/tc_ematch/tc_em_nbyte.h new file mode 100644 index 000000000..f19d1f58e --- /dev/null +++ b/include/linux/tc_ematch/tc_em_nbyte.h @@ -0,0 +1,13 @@ +#ifndef __LINUX_TC_EM_NBYTE_H +#define __LINUX_TC_EM_NBYTE_H + +#include + +struct tcf_em_nbyte +{ + __u16 off; + __u16 len:12; + __u8 layer:4; +}; + +#endif diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h new file mode 100644 index 000000000..7fe57f957 --- /dev/null +++ b/include/net/ieee80211.h @@ -0,0 +1,882 @@ +/* + * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 + * remains copyright by the original authors + * + * Portions of the merged code are based on Host AP (software wireless + * LAN access point) driver for Intersil Prism2/2.5/3. + * + * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen + * + * Copyright (c) 2002-2003, Jouni Malinen + * + * Adaption to a generic IEEE 802.11 stack by James Ketrenos + * + * Copyright (c) 2004, Intel Corporation + * + * 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. See README and COPYING for + * more details. + */ +#ifndef IEEE80211_H +#define IEEE80211_H + +#include /* ETH_ALEN */ +#include /* ARRAY_SIZE */ + +#if WIRELESS_EXT < 17 +#define IW_QUAL_QUAL_INVALID 0x10 +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#define IW_QUAL_QUAL_UPDATED 0x1 +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#endif + +#define IEEE80211_DATA_LEN 2304 +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + 6.2.1.1.2. + + The figure in section 7.1.2 suggests a body size of up to 2312 + bytes is allowed, which is a bit confusing, I suspect this + represents the 2304 bytes of real data, plus a possible 8 bytes of + WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ + + +#define IEEE80211_HLEN 30 +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) + +struct ieee80211_hdr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; + u8 addr4[ETH_ALEN]; +} __attribute__ ((packed)); + +struct ieee80211_hdr_3addr { + u16 frame_ctl; + u16 duration_id; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + u16 seq_ctl; +} __attribute__ ((packed)); + +enum eap_type { + EAP_PACKET = 0, + EAPOL_START, + EAPOL_LOGOFF, + EAPOL_KEY, + EAPOL_ENCAP_ASF_ALERT +}; + +static const char *eap_types[] = { + [EAP_PACKET] = "EAP-Packet", + [EAPOL_START] = "EAPOL-Start", + [EAPOL_LOGOFF] = "EAPOL-Logoff", + [EAPOL_KEY] = "EAPOL-Key", + [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" +}; + +static inline const char *eap_get_type(int type) +{ + return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; +} + +struct eapol { + u8 snap[6]; + u16 ethertype; + u8 version; + u8 type; + u16 length; +} __attribute__ ((packed)); + +#define IEEE80211_3ADDR_LEN 24 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_FCS_LEN 4 + +#define MIN_FRAG_THRESHOLD 256U +#define MAX_FRAG_THRESHOLD 2346U + +/* Frame control field constants */ +#define IEEE80211_FCTL_VERS 0x0002 +#define IEEE80211_FCTL_FTYPE 0x000c +#define IEEE80211_FCTL_STYPE 0x00f0 +#define IEEE80211_FCTL_TODS 0x0100 +#define IEEE80211_FCTL_FROMDS 0x0200 +#define IEEE80211_FCTL_MOREFRAGS 0x0400 +#define IEEE80211_FCTL_RETRY 0x0800 +#define IEEE80211_FCTL_PM 0x1000 +#define IEEE80211_FCTL_MOREDATA 0x2000 +#define IEEE80211_FCTL_WEP 0x4000 +#define IEEE80211_FCTL_ORDER 0x8000 + +#define IEEE80211_FTYPE_MGMT 0x0000 +#define IEEE80211_FTYPE_CTL 0x0004 +#define IEEE80211_FTYPE_DATA 0x0008 + +/* management */ +#define IEEE80211_STYPE_ASSOC_REQ 0x0000 +#define IEEE80211_STYPE_ASSOC_RESP 0x0010 +#define IEEE80211_STYPE_REASSOC_REQ 0x0020 +#define IEEE80211_STYPE_REASSOC_RESP 0x0030 +#define IEEE80211_STYPE_PROBE_REQ 0x0040 +#define IEEE80211_STYPE_PROBE_RESP 0x0050 +#define IEEE80211_STYPE_BEACON 0x0080 +#define IEEE80211_STYPE_ATIM 0x0090 +#define IEEE80211_STYPE_DISASSOC 0x00A0 +#define IEEE80211_STYPE_AUTH 0x00B0 +#define IEEE80211_STYPE_DEAUTH 0x00C0 + +/* control */ +#define IEEE80211_STYPE_PSPOLL 0x00A0 +#define IEEE80211_STYPE_RTS 0x00B0 +#define IEEE80211_STYPE_CTS 0x00C0 +#define IEEE80211_STYPE_ACK 0x00D0 +#define IEEE80211_STYPE_CFEND 0x00E0 +#define IEEE80211_STYPE_CFENDACK 0x00F0 + +/* data */ +#define IEEE80211_STYPE_DATA 0x0000 +#define IEEE80211_STYPE_DATA_CFACK 0x0010 +#define IEEE80211_STYPE_DATA_CFPOLL 0x0020 +#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 +#define IEEE80211_STYPE_NULLFUNC 0x0040 +#define IEEE80211_STYPE_CFACK 0x0050 +#define IEEE80211_STYPE_CFPOLL 0x0060 +#define IEEE80211_STYPE_CFACKPOLL 0x0070 + +#define IEEE80211_SCTL_FRAG 0x000F +#define IEEE80211_SCTL_SEQ 0xFFF0 + + +/* debug macros */ + +#ifdef CONFIG_IEEE80211_DEBUG +extern u32 ieee80211_debug_level; +#define IEEE80211_DEBUG(level, fmt, args...) \ +do { if (ieee80211_debug_level & (level)) \ + printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) +#else +#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) +#endif /* CONFIG_IEEE80211_DEBUG */ + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IEEE80211_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your + * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/ipw/debug_level + * + * you simply need to add your entry to the ipw_debug_levels array. + * + * If you do not see debug_level in /proc/net/ipw then you do not have + * CONFIG_IEEE80211_DEBUG defined in your kernel configuration + * + */ + +#define IEEE80211_DL_INFO (1<<0) +#define IEEE80211_DL_WX (1<<1) +#define IEEE80211_DL_SCAN (1<<2) +#define IEEE80211_DL_STATE (1<<3) +#define IEEE80211_DL_MGMT (1<<4) +#define IEEE80211_DL_FRAG (1<<5) +#define IEEE80211_DL_EAP (1<<6) +#define IEEE80211_DL_DROP (1<<7) + +#define IEEE80211_DL_TX (1<<8) +#define IEEE80211_DL_RX (1<<9) + +#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) +#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) +#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) + +#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) +#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) +#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) +#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) +#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) +#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) +#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) +#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) +#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) +#include +#include +#include /* ARPHRD_ETHER */ + +#ifndef WIRELESS_SPY +#define WIRELESS_SPY // enable iwspy support +#endif +#include // new driver API + +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ + +#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ + +#ifndef ETH_P_80211_RAW +#define ETH_P_80211_RAW (ETH_P_ECONET + 1) +#endif + +/* IEEE 802.11 defines */ + +#define P80211_OUI_LEN 3 + +struct ieee80211_snap_hdr { + + u8 dsap; /* always 0xAA */ + u8 ssap; /* always 0xAA */ + u8 ctrl; /* always 0x03 */ + u8 oui[P80211_OUI_LEN]; /* organizational universal id */ + +} __attribute__ ((packed)); + +#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) + +#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) +#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) + +#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) +#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ) + +/* Authentication algorithms */ +#define WLAN_AUTH_OPEN 0 +#define WLAN_AUTH_SHARED_KEY 1 + +#define WLAN_AUTH_CHALLENGE_LEN 128 + +#define WLAN_CAPABILITY_BSS (1<<0) +#define WLAN_CAPABILITY_IBSS (1<<1) +#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) +#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) +#define WLAN_CAPABILITY_PRIVACY (1<<4) +#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) +#define WLAN_CAPABILITY_PBCC (1<<6) +#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) + +/* Status codes */ +#define WLAN_STATUS_SUCCESS 0 +#define WLAN_STATUS_UNSPECIFIED_FAILURE 1 +#define WLAN_STATUS_CAPS_UNSUPPORTED 10 +#define WLAN_STATUS_REASSOC_NO_ASSOC 11 +#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12 +#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13 +#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14 +#define WLAN_STATUS_CHALLENGE_FAIL 15 +#define WLAN_STATUS_AUTH_TIMEOUT 16 +#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17 +#define WLAN_STATUS_ASSOC_DENIED_RATES 18 +/* 802.11b */ +#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19 +#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20 +#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21 + +/* Reason codes */ +#define WLAN_REASON_UNSPECIFIED 1 +#define WLAN_REASON_PREV_AUTH_NOT_VALID 2 +#define WLAN_REASON_DEAUTH_LEAVING 3 +#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4 +#define WLAN_REASON_DISASSOC_AP_BUSY 5 +#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6 +#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7 +#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8 +#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) +#define IEEE80211_STATMASK_RATE (1<<3) +#define IEEE80211_STATMASK_WEMASK 0x7 + + +#define IEEE80211_CCK_MODULATION (1<<0) +#define IEEE80211_OFDM_MODULATION (1<<1) + +#define IEEE80211_24GHZ_BAND (1<<0) +#define IEEE80211_52GHZ_BAND (1<<1) + +#define IEEE80211_CCK_RATE_1MB 0x02 +#define IEEE80211_CCK_RATE_2MB 0x04 +#define IEEE80211_CCK_RATE_5MB 0x0B +#define IEEE80211_CCK_RATE_11MB 0x16 +#define IEEE80211_OFDM_RATE_6MB 0x0C +#define IEEE80211_OFDM_RATE_9MB 0x12 +#define IEEE80211_OFDM_RATE_12MB 0x18 +#define IEEE80211_OFDM_RATE_18MB 0x24 +#define IEEE80211_OFDM_RATE_24MB 0x30 +#define IEEE80211_OFDM_RATE_36MB 0x48 +#define IEEE80211_OFDM_RATE_48MB 0x60 +#define IEEE80211_OFDM_RATE_54MB 0x6C +#define IEEE80211_BASIC_RATE_MASK 0x80 + +#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) +#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) +#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) +#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) +#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) +#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) +#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) +#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) +#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) +#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) +#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) +#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) + +#define IEEE80211_CCK_RATES_MASK 0x0000000F +#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ + IEEE80211_CCK_RATE_2MB_MASK) +#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ + IEEE80211_CCK_RATE_5MB_MASK | \ + IEEE80211_CCK_RATE_11MB_MASK) + +#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 +#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ + IEEE80211_OFDM_RATE_12MB_MASK | \ + IEEE80211_OFDM_RATE_24MB_MASK) +#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ + IEEE80211_OFDM_RATE_9MB_MASK | \ + IEEE80211_OFDM_RATE_18MB_MASK | \ + IEEE80211_OFDM_RATE_36MB_MASK | \ + IEEE80211_OFDM_RATE_48MB_MASK | \ + IEEE80211_OFDM_RATE_54MB_MASK) +#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ + IEEE80211_CCK_DEFAULT_RATES_MASK) + +#define IEEE80211_NUM_OFDM_RATES 8 +#define IEEE80211_NUM_CCK_RATES 4 +#define IEEE80211_OFDM_SHIFT_MASK_A 4 + + + + +/* NOTE: This data is for statistical purposes; not all hardware provides this + * information for frames received. Not setting these will not cause + * any adverse affects. */ +struct ieee80211_rx_stats { + u32 mac_time; + s8 rssi; + u8 signal; + u8 noise; + u16 rate; /* in 100 kbps */ + u8 received_channel; + u8 control; + u8 mask; + u8 freq; + u16 len; +}; + +/* IEEE 802.11 requires that STA supports concurrent reception of at least + * three fragmented frames. This define can be increased to support more + * concurrent frames, but it should be noted that each entry can consume about + * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ +#define IEEE80211_FRAG_CACHE_LEN 4 + +struct ieee80211_frag_entry { + unsigned long first_frag_time; + unsigned int seq; + unsigned int last_frag; + struct sk_buff *skb; + u8 src_addr[ETH_ALEN]; + u8 dst_addr[ETH_ALEN]; +}; + +struct ieee80211_stats { + unsigned int tx_unicast_frames; + unsigned int tx_multicast_frames; + unsigned int tx_fragments; + unsigned int tx_unicast_octets; + unsigned int tx_multicast_octets; + unsigned int tx_deferred_transmissions; + unsigned int tx_single_retry_frames; + unsigned int tx_multiple_retry_frames; + unsigned int tx_retry_limit_exceeded; + unsigned int tx_discards; + unsigned int rx_unicast_frames; + unsigned int rx_multicast_frames; + unsigned int rx_fragments; + unsigned int rx_unicast_octets; + unsigned int rx_multicast_octets; + unsigned int rx_fcs_errors; + unsigned int rx_discards_no_buffer; + unsigned int tx_discards_wrong_sa; + unsigned int rx_discards_undecryptable; + unsigned int rx_message_in_msg_fragments; + unsigned int rx_message_in_bad_msg_fragments; +}; + +struct ieee80211_device; + +#define SEC_KEY_1 (1<<0) +#define SEC_KEY_2 (1<<1) +#define SEC_KEY_3 (1<<2) +#define SEC_KEY_4 (1<<3) +#define SEC_ACTIVE_KEY (1<<4) +#define SEC_AUTH_MODE (1<<5) +#define SEC_UNICAST_GROUP (1<<6) +#define SEC_LEVEL (1<<7) +#define SEC_ENABLED (1<<8) + +#define SEC_LEVEL_0 0 /* None */ +#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ +#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ +#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ +#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ + +#define WEP_KEYS 4 +#define WEP_KEY_LEN 13 + +struct ieee80211_security { + u16 active_key:2, + enabled:1, + auth_mode:2, + auth_algo:4, + unicast_uses_group:1; + u8 key_sizes[WEP_KEYS]; + u8 keys[WEP_KEYS][WEP_KEY_LEN]; + u8 level; + u16 flags; +} __attribute__ ((packed)); + + +/* + + 802.11 data frame from AP + + ,-------------------------------------------------------------------. +Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | + |------|------|---------|---------|---------|------|---------|------| +Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | + | | tion | (BSSID) | | | ence | data | | + `-------------------------------------------------------------------' + +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 */ +#define MFIE_TYPE_SSID 0 +#define MFIE_TYPE_RATES 1 +#define MFIE_TYPE_FH_SET 2 +#define MFIE_TYPE_DS_SET 3 +#define MFIE_TYPE_CF_SET 4 +#define MFIE_TYPE_TIM 5 +#define MFIE_TYPE_IBSS_SET 6 +#define MFIE_TYPE_CHALLENGE 16 +#define MFIE_TYPE_RSN 48 +#define MFIE_TYPE_RATES_EX 50 +#define MFIE_TYPE_GENERIC 221 + +struct ieee80211_info_element_hdr { + u8 id; + u8 len; +} __attribute__ ((packed)); + +struct ieee80211_info_element { + u8 id; + u8 len; + u8 data[0]; +} __attribute__ ((packed)); + +/* + * These are the data types that can make up management packets + * + u16 auth_algorithm; + u16 auth_sequence; + u16 beacon_interval; + u16 capability; + u8 current_ap[ETH_ALEN]; + u16 listen_interval; + struct { + u16 association_id:14, reserved:2; + } __attribute__ ((packed)); + u32 time_stamp[2]; + u16 reason; + u16 status; +*/ + +struct ieee80211_authentication { + struct ieee80211_header_data header; + u16 algorithm; + u16 transaction; + u16 status; + struct ieee80211_info_element info_element; +} __attribute__ ((packed)); + + +struct ieee80211_probe_response { + struct ieee80211_header_data header; + u32 time_stamp[2]; + u16 beacon_interval; + u16 capability; + struct ieee80211_info_element info_element; +} __attribute__ ((packed)); + +struct ieee80211_assoc_request_frame { + u16 capability; + u16 listen_interval; + u8 current_ap[ETH_ALEN]; + struct ieee80211_info_element info_element; +} __attribute__ ((packed)); + +struct ieee80211_assoc_response_frame { + struct ieee80211_hdr_3addr header; + u16 capability; + u16 status; + u16 aid; + struct ieee80211_info_element info_element; /* supported rates */ +} __attribute__ ((packed)); + + +struct ieee80211_txb { + u8 nr_frags; + u8 encrypted; + u16 reserved; + u16 frag_size; + u16 payload_size; + struct sk_buff *fragments[0]; +}; + + +/* SWEEP TABLE ENTRIES NUMBER*/ +#define MAX_SWEEP_TAB_ENTRIES 42 +#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 +/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs + * only use 8, and then use extended rates for the remaining supported + * rates. Other APs, however, stick all of their supported rates on the + * main rates information element... */ +#define MAX_RATES_LENGTH ((u8)12) +#define MAX_RATES_EX_LENGTH ((u8)16) +#define MAX_NETWORK_COUNT 128 + +#define CRC_LENGTH 4U + +#define MAX_WPA_IE_LEN 64 + +#define NETWORK_EMPTY_ESSID (1<<0) +#define NETWORK_HAS_OFDM (1<<1) +#define NETWORK_HAS_CCK (1<<2) + +struct ieee80211_network { + /* These entries are used to identify a unique network */ + u8 bssid[ETH_ALEN]; + u8 channel; + /* Ensure null-terminated for any debug msgs */ + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + + /* These are network statistics */ + struct ieee80211_rx_stats stats; + u16 capability; + u8 rates[MAX_RATES_LENGTH]; + u8 rates_len; + u8 rates_ex[MAX_RATES_EX_LENGTH]; + u8 rates_ex_len; + unsigned long last_scanned; + u8 mode; + u8 flags; + u32 last_associate; + u32 time_stamp[2]; + u16 beacon_interval; + u16 listen_interval; + u16 atim_window; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + u8 rsn_ie[MAX_WPA_IE_LEN]; + size_t rsn_ie_len; + struct list_head list; +}; + +enum ieee80211_state { + IEEE80211_UNINITIALIZED = 0, + IEEE80211_INITIALIZED, + IEEE80211_ASSOCIATING, + IEEE80211_ASSOCIATED, + IEEE80211_AUTHENTICATING, + IEEE80211_AUTHENTICATED, + IEEE80211_SHUTDOWN +}; + +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) +#define DEFAULT_FTS 2346 +#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +#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) + +struct ieee80211_device { + struct net_device *dev; + + /* Bookkeeping structures */ + struct net_device_stats stats; + struct ieee80211_stats ieee_stats; + + /* Probe / Beacon management */ + struct list_head network_free_list; + struct list_head network_list; + struct ieee80211_network *networks; + int scans; + int scan_age; + + int iw_mode; /* operating mode (IW_MODE_*) */ + + spinlock_t lock; + + int tx_headroom; /* Set to size of any additional room needed at front + * of allocated Tx SKBs */ + u32 config; + + /* WEP and other encryption related settings at the device level */ + int open_wep; /* Set to 1 to allow unencrypted frames */ + + int reset_on_keychange; /* Set to 1 if the HW needs to be reset on + * WEP key changes */ + + /* If the host performs {en,de}cryption, then set to 1 */ + int host_encrypt; + int host_decrypt; + int ieee802_1x; /* is IEEE 802.1X used */ + + /* WPA data */ + int wpa_enabled; + int drop_unencrypted; + int tkip_countermeasures; + int privacy_invoked; + size_t wpa_ie_len; + u8 *wpa_ie; + + struct list_head crypt_deinit_list; + struct ieee80211_crypt_data *crypt[WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct timer_list crypt_deinit_timer; + + int bcrx_sta_key; /* use individual keys to override default keys even + * with RX of broad/multicast frames */ + + /* Fragmentation structures */ + struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN]; + unsigned int frag_next_idx; + u16 fts; /* Fragmentation Threshold */ + + /* Association info */ + u8 bssid[ETH_ALEN]; + + enum ieee80211_state state; + + int mode; /* A, B, G */ + int modulation; /* CCK, OFDM */ + int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ + int abg_ture; /* ABG flag */ + + /* Callback functions */ + void (*set_security)(struct net_device *dev, + struct ieee80211_security *sec); + int (*hard_start_xmit)(struct ieee80211_txb *txb, + struct net_device *dev); + int (*reset_port)(struct net_device *dev); + + /* This must be the last item so that it points to the data + * allocated beyond this structure by alloc_ieee80211 */ + u8 priv[0]; +}; + +#define IEEE_A (1<<0) +#define IEEE_B (1<<1) +#define IEEE_G (1<<2) +#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) + +extern inline void *ieee80211_priv(struct net_device *dev) +{ + return ((struct ieee80211_device *)netdev_priv(dev))->priv; +} + +extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len) +{ + /* Single white space is for Linksys APs */ + if (essid_len == 1 && essid[0] == ' ') + return 1; + + /* Otherwise, if the entire essid is 0, we assume it is hidden */ + while (essid_len) { + essid_len--; + if (essid[essid_len] != '\0') + return 0; + } + + return 1; +} + +extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) +{ + /* + * It is possible for both access points and our device to support + * combinations of modes, so as long as there is one valid combination + * of ap/device supported modes, then return success + * + */ + if ((mode & IEEE_A) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_52GHZ_BAND)) + return 1; + + if ((mode & IEEE_G) && + (ieee->modulation & IEEE80211_OFDM_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + if ((mode & IEEE_B) && + (ieee->modulation & IEEE80211_CCK_MODULATION) && + (ieee->freq_band & IEEE80211_24GHZ_BAND)) + return 1; + + return 0; +} + +extern inline int ieee80211_get_hdrlen(u16 fc) +{ + int hdrlen = 24; + + switch (WLAN_FC_GET_TYPE(fc)) { + case IEEE80211_FTYPE_DATA: + if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) + hdrlen = 30; /* Addr4 */ + break; + case IEEE80211_FTYPE_CTL: + switch (WLAN_FC_GET_STYPE(fc)) { + case IEEE80211_STYPE_CTS: + case IEEE80211_STYPE_ACK: + hdrlen = 10; + break; + default: + hdrlen = 16; + break; + } + break; + } + + return hdrlen; +} + + + +/* ieee80211.c */ +extern void free_ieee80211(struct net_device *dev); +extern struct net_device *alloc_ieee80211(int sizeof_priv); + +extern int ieee80211_set_encryption(struct ieee80211_device *ieee); + +/* ieee80211_tx.c */ + + +extern int ieee80211_xmit(struct sk_buff *skb, + struct net_device *dev); +extern void ieee80211_txb_free(struct ieee80211_txb *); + + +/* ieee80211_rx.c */ +extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, + struct ieee80211_rx_stats *rx_stats); +extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, + struct ieee80211_hdr *header, + struct ieee80211_rx_stats *stats); + +/* iee80211_wx.c */ +extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); +extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, + struct iw_request_info *info, + union iwreq_data *wrqu, char *key); + + +extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) +{ + ieee->scans++; +} + +extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) +{ + return ieee->scans; +} + +static inline const char *escape_essid(const char *essid, u8 essid_len) { + static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; + const char *s = essid; + char *d = escaped; + + if (ieee80211_is_empty_essid(essid, essid_len)) { + memcpy(escaped, "", sizeof("")); + return escaped; + } + + essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); + while (essid_len--) { + if (*s == '\0') { + *d++ = '\\'; + *d++ = '0'; + s++; + } else { + *d++ = *s++; + } + } + *d = '\0'; + return escaped; +} + +#endif /* IEEE80211_H */ diff --git a/kernel/seccomp.c b/kernel/seccomp.c new file mode 100644 index 000000000..c3391b602 --- /dev/null +++ b/kernel/seccomp.c @@ -0,0 +1,56 @@ +/* + * linux/kernel/seccomp.c + * + * Copyright 2004-2005 Andrea Arcangeli + * + * This defines a simple but solid secure-computing mode. + */ + +#include +#include + +/* #define SECCOMP_DEBUG 1 */ + +/* + * Secure computing mode 1 allows only read/write/exit/sigreturn. + * To be fully secure this must be combined with rlimit + * to limit the stack allocations too. + */ +static int mode1_syscalls[] = { + __NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn, + 0, /* null terminated */ +}; + +#ifdef TIF_32BIT +static int mode1_syscalls_32[] = { + __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32, + 0, /* null terminated */ +}; +#endif + +void __secure_computing(int this_syscall) +{ + int mode = current->seccomp.mode; + int * syscall; + + switch (mode) { + case 1: + syscall = mode1_syscalls; +#ifdef TIF_32BIT + if (test_thread_flag(TIF_32BIT)) + syscall = mode1_syscalls_32; +#endif + do { + if (*syscall == this_syscall) + return; + } while (*++syscall); + break; + default: + BUG(); + } + +#ifdef SECCOMP_DEBUG + dump_stack(); +#endif + do_exit(SIGKILL); +} diff --git a/lib/halfmd4.c b/lib/halfmd4.c new file mode 100644 index 000000000..e11db26f8 --- /dev/null +++ b/lib/halfmd4.c @@ -0,0 +1,66 @@ +#include +#include +#include + +/* F, G and H are basic MD4 functions: selection, majority, parity */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* + * The generic round function. The application is so specific that + * we don't bother protecting all the arguments with parens, as is generally + * good macro practice, in favor of extra legibility. + * Rotation is separate from addition to prevent recomputation + */ +#define ROUND(f, a, b, c, d, x, s) \ + (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s))) +#define K1 0 +#define K2 013240474631UL +#define K3 015666365641UL + +/* + * Basic cut-down MD4 transform. Returns only 32 bits of result. + */ +__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]) +{ + __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ + ROUND(F, a, b, c, d, in[0] + K1, 3); + ROUND(F, d, a, b, c, in[1] + K1, 7); + ROUND(F, c, d, a, b, in[2] + K1, 11); + ROUND(F, b, c, d, a, in[3] + K1, 19); + ROUND(F, a, b, c, d, in[4] + K1, 3); + ROUND(F, d, a, b, c, in[5] + K1, 7); + ROUND(F, c, d, a, b, in[6] + K1, 11); + ROUND(F, b, c, d, a, in[7] + K1, 19); + + /* Round 2 */ + ROUND(G, a, b, c, d, in[1] + K2, 3); + ROUND(G, d, a, b, c, in[3] + K2, 5); + ROUND(G, c, d, a, b, in[5] + K2, 9); + ROUND(G, b, c, d, a, in[7] + K2, 13); + ROUND(G, a, b, c, d, in[0] + K2, 3); + ROUND(G, d, a, b, c, in[2] + K2, 5); + ROUND(G, c, d, a, b, in[4] + K2, 9); + ROUND(G, b, c, d, a, in[6] + K2, 13); + + /* Round 3 */ + ROUND(H, a, b, c, d, in[3] + K3, 3); + ROUND(H, d, a, b, c, in[7] + K3, 9); + ROUND(H, c, d, a, b, in[2] + K3, 11); + ROUND(H, b, c, d, a, in[6] + K3, 15); + ROUND(H, a, b, c, d, in[1] + K3, 3); + ROUND(H, d, a, b, c, in[5] + K3, 9); + ROUND(H, c, d, a, b, in[0] + K3, 11); + ROUND(H, b, c, d, a, in[4] + K3, 15); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; + + return buf[1]; /* "most hashed" word */ +} +EXPORT_SYMBOL(half_md4_transform); diff --git a/net/ipv4/multipath.c b/net/ipv4/multipath.c new file mode 100644 index 000000000..4e9ca7c76 --- /dev/null +++ b/net/ipv4/multipath.c @@ -0,0 +1,55 @@ +/* multipath.c: IPV4 multipath algorithm support. + * + * Copyright (C) 2004, 2005 Einar Lueck + * Copyright (C) 2005 David S. Miller + */ + +#include +#include +#include +#include + +#include + +static DEFINE_SPINLOCK(alg_table_lock); +struct ip_mp_alg_ops *ip_mp_alg_table[IP_MP_ALG_MAX + 1]; + +int multipath_alg_register(struct ip_mp_alg_ops *ops, enum ip_mp_alg n) +{ + struct ip_mp_alg_ops **slot; + int err; + + if (n < IP_MP_ALG_NONE || n > IP_MP_ALG_MAX || + !ops->mp_alg_select_route) + return -EINVAL; + + spin_lock(&alg_table_lock); + slot = &ip_mp_alg_table[n]; + if (*slot != NULL) { + err = -EBUSY; + } else { + *slot = ops; + err = 0; + } + spin_unlock(&alg_table_lock); + + return err; +} +EXPORT_SYMBOL(multipath_alg_register); + +void multipath_alg_unregister(struct ip_mp_alg_ops *ops, enum ip_mp_alg n) +{ + struct ip_mp_alg_ops **slot; + + if (n < IP_MP_ALG_NONE || n > IP_MP_ALG_MAX) + return; + + spin_lock(&alg_table_lock); + slot = &ip_mp_alg_table[n]; + if (*slot == ops) + *slot = NULL; + spin_unlock(&alg_table_lock); + + synchronize_net(); +} +EXPORT_SYMBOL(multipath_alg_unregister); diff --git a/scripts/kconfig/.kxgettext.o.cmd b/scripts/kconfig/.kxgettext.o.cmd new file mode 100644 index 000000000..1ef4182d0 --- /dev/null +++ b/scripts/kconfig/.kxgettext.o.cmd @@ -0,0 +1,48 @@ +cmd_scripts/kconfig/kxgettext.o := gcc -Wp,-MD,scripts/kconfig/.kxgettext.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -c -o scripts/kconfig/kxgettext.o scripts/kconfig/kxgettext.c + +deps_scripts/kconfig/kxgettext.o := \ + scripts/kconfig/kxgettext.c \ + /usr/include/stdlib.h \ + /usr/include/features.h \ + /usr/include/sys/cdefs.h \ + /usr/include/gnu/stubs.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.2/include/stddef.h \ + /usr/include/sys/types.h \ + /usr/include/bits/types.h \ + /usr/include/bits/wordsize.h \ + /usr/include/bits/typesizes.h \ + /usr/include/time.h \ + /usr/include/endian.h \ + /usr/include/bits/endian.h \ + /usr/include/sys/select.h \ + /usr/include/bits/select.h \ + /usr/include/bits/sigset.h \ + /usr/include/bits/time.h \ + /usr/include/sys/sysmacros.h \ + /usr/include/bits/pthreadtypes.h \ + /usr/include/bits/sched.h \ + /usr/include/alloca.h \ + /usr/include/string.h \ + /usr/include/bits/string.h \ + /usr/include/bits/string2.h \ + scripts/kconfig/lkc.h \ + scripts/kconfig/expr.h \ + /usr/include/stdio.h \ + /usr/include/libio.h \ + /usr/include/_G_config.h \ + /usr/include/wchar.h \ + /usr/include/bits/wchar.h \ + /usr/include/gconv.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.2/include/stdarg.h \ + /usr/include/bits/stdio_lim.h \ + /usr/include/bits/sys_errlist.h \ + /usr/include/bits/stdio.h \ + /usr/lib/gcc/i386-redhat-linux/3.4.2/include/stdbool.h \ + /usr/include/libintl.h \ + /usr/include/locale.h \ + /usr/include/bits/locale.h \ + scripts/kconfig/lkc_proto.h \ + +scripts/kconfig/kxgettext.o: $(deps_scripts/kconfig/kxgettext.o) + +$(deps_scripts/kconfig/kxgettext.o): diff --git a/scripts/kconfig/POTFILES.in b/scripts/kconfig/POTFILES.in new file mode 100644 index 000000000..cc94e46a7 --- /dev/null +++ b/scripts/kconfig/POTFILES.in @@ -0,0 +1,5 @@ +scripts/kconfig/mconf.c +scripts/kconfig/conf.c +scripts/kconfig/confdata.c +scripts/kconfig/gconf.c +scripts/kconfig/qconf.cc diff --git a/scripts/kconfig/kxgettext.c b/scripts/kconfig/kxgettext.c new file mode 100644 index 000000000..1c88d7c6d --- /dev/null +++ b/scripts/kconfig/kxgettext.c @@ -0,0 +1,221 @@ +/* + * Arnaldo Carvalho de Melo , 2005 + * + * Released under the terms of the GNU GPL v2.0 + */ + +#include +#include + +#define LKC_DIRECT_LINK +#include "lkc.h" + +static char *escape(const char* text, char *bf, int len) +{ + char *bfp = bf; + int multiline = strchr(text, '\n') != NULL; + + *bfp++ = '"'; + --len; + + if (multiline) { + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 3; + } + + while (*text != '\0' && len > 1) { + if (*text == '"') + *bfp++ = '\\'; + else if (*text == '\n') { + *bfp++ = '\\'; + *bfp++ = 'n'; + *bfp++ = '"'; + *bfp++ = '\n'; + *bfp++ = '"'; + len -= 5; + ++text; + goto next; + } + *bfp++ = *text++; +next: + --len; + } + + if (multiline) + bfp -= 3; + + *bfp++ = '"'; + *bfp = '\0'; + + return bf; +} + +struct file_line { + struct file_line *next; + char* file; + int lineno; +}; + +static struct file_line *file_line__new(char *file, int lineno) +{ + struct file_line *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->file = file; + self->lineno = lineno; + self->next = NULL; +out: + return self; +} + +struct message { + const char *msg; + const char *option; + struct message *next; + struct file_line *files; +}; + +static struct message *message__list; + +static struct message *message__new(const char *msg, char *option, char *file, int lineno) +{ + struct message *self = malloc(sizeof(*self)); + + if (self == NULL) + goto out; + + self->files = file_line__new(file, lineno); + if (self->files == NULL) + goto out_fail; + + self->msg = strdup(msg); + if (self->msg == NULL) + goto out_fail_msg; + + self->option = option; + self->next = NULL; +out: + return self; +out_fail_msg: + free(self->files); +out_fail: + free(self); + self = NULL; + goto out; +} + +static struct message *mesage__find(const char *msg) +{ + struct message *m = message__list; + + while (m != NULL) { + if (strcmp(m->msg, msg) == 0) + break; + m = m->next; + } + + return m; +} + +static int message__add_file_line(struct message *self, char *file, int lineno) +{ + int rc = -1; + struct file_line *fl = file_line__new(file, lineno); + + if (fl == NULL) + goto out; + + fl->next = self->files; + self->files = fl; + rc = 0; +out: + return rc; +} + +static int message__add(const char *msg, char *option, char *file, int lineno) +{ + int rc = 0; + char bf[16384]; + char *escaped = escape(msg, bf, sizeof(bf)); + struct message *m = mesage__find(escaped); + + if (m != NULL) + rc = message__add_file_line(m, file, lineno); + else { + m = message__new(escaped, option, file, lineno); + + if (m != NULL) { + m->next = message__list; + message__list = m; + } else + rc = -1; + } + return rc; +} + +void menu_build_message_list(struct menu *menu) +{ + struct menu *child; + + message__add(menu_get_prompt(menu), NULL, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + if (menu->sym != NULL && menu->sym->help != NULL) + message__add(menu->sym->help, menu->sym->name, + menu->file == NULL ? "Root Menu" : menu->file->name, + menu->lineno); + + for (child = menu->list; child != NULL; child = child->next) + if (child->prompt != NULL) + menu_build_message_list(child); +} + +static void message__print_file_lineno(struct message *self) +{ + struct file_line *fl = self->files; + + printf("\n#: %s:%d", fl->file, fl->lineno); + fl = fl->next; + + while (fl != NULL) { + printf(", %s:%d", fl->file, fl->lineno); + fl = fl->next; + } + + if (self->option != NULL) + printf(", %s:00000", self->option); + + putchar('\n'); +} + +static void message__print_gettext_msgid_msgstr(struct message *self) +{ + message__print_file_lineno(self); + + printf("msgid %s\n" + "msgstr \"\"\n", self->msg); +} + +void menu__xgettext(void) +{ + struct message *m = message__list; + + while (m != NULL) { + message__print_gettext_msgid_msgstr(m); + m = m->next; + } +} + +int main(int ac, char **av) +{ + conf_parse(av[1]); + + menu_build_message_list(menu_get_root_menu(NULL)); + menu__xgettext(); + return 0; +} diff --git a/scripts/kconfig/kxgettext.o b/scripts/kconfig/kxgettext.o new file mode 100644 index 000000000..e92d2605c Binary files /dev/null and b/scripts/kconfig/kxgettext.o differ diff --git a/scripts/show_delta b/scripts/show_delta new file mode 100644 index 000000000..48a706ab3 --- /dev/null +++ b/scripts/show_delta @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# +# show_deltas: Read list of printk messages instrumented with +# time data, and format with time deltas. +# +# Also, you can show the times relative to a fixed point. +# +# Copyright 2003 Sony Corporation +# +# GPL 2.0 applies. + +import sys +import string + +def usage(): + print """usage: show_delta [] + +This program parses the output from a set of printk message lines which +have time data prefixed because the CONFIG_PRINTK_TIME option is set, or +the kernel command line option "time" is specified. When run with no +options, the time information is converted to show the time delta between +each printk line and the next. When run with the '-b' option, all times +are relative to a single (base) point in time. + +Options: + -h Show this usage help. + -b Specify a base for time references. + can be a number or a string. + If it is a string, the first message line + which matches (at the beginning of the + line) is used as the time reference. + +ex: $ dmesg >timefile + $ show_delta -b NET4 timefile + +will show times relative to the line in the kernel output +starting with "NET4". +""" + sys.exit(1) + +# returns a tuple containing the seconds and text for each message line +# seconds is returned as a float +# raise an exception if no timing data was found +def get_time(line): + if line[0]!="[": + raise ValueError + + # split on closing bracket + (time_str, rest) = string.split(line[1:],']',1) + time = string.atof(time_str) + + #print "time=", time + return (time, rest) + + +# average line looks like: +# [ 0.084282] VFS: Mounted root (romfs filesystem) readonly +# time data is expressed in seconds.useconds, +# convert_line adds a delta for each line +last_time = 0.0 +def convert_line(line, base_time): + global last_time + + try: + (time, rest) = get_time(line) + except: + # if any problem parsing time, don't convert anything + return line + + if base_time: + # show time from base + delta = time - base_time + else: + # just show time from last line + delta = time - last_time + last_time = time + + return ("[%5.6f < %5.6f >]" % (time, delta)) + rest + +def main(): + base_str = "" + filein = "" + for arg in sys.argv[1:]: + if arg=="-b": + base_str = sys.argv[sys.argv.index("-b")+1] + elif arg=="-h": + usage() + else: + filein = arg + + if not filein: + usage() + + try: + lines = open(filein,"r").readlines() + except: + print "Problem opening file: %s" % filein + sys.exit(1) + + if base_str: + print 'base= "%s"' % base_str + # assume a numeric base. If that fails, try searching + # for a matching line. + try: + base_time = float(base_str) + except: + # search for line matching string + found = 0 + for line in lines: + try: + (time, rest) = get_time(line) + except: + continue + if string.find(rest, base_str)==1: + base_time = time + found = 1 + # stop at first match + break + if not found: + print 'Couldn\'t find line matching base pattern "%s"' % base_str + sys.exit(1) + else: + base_time = 0.0 + + for line in lines: + print convert_line(line, base_time), + +main() + diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c new file mode 100644 index 000000000..d97631c3f --- /dev/null +++ b/sound/core/rawmidi_compat.c @@ -0,0 +1,120 @@ +/* + * 32bit -> 64bit ioctl wrapper for raw MIDI API + * Copyright (c) by Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file included from rawmidi.c */ + +#include + +struct sndrv_rawmidi_params32 { + s32 stream; + u32 buffer_size; + u32 avail_min; + unsigned int no_active_sensing; /* avoid bit-field */ + unsigned char reserved[16]; +} __attribute__((packed)); + +static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile, + struct sndrv_rawmidi_params32 __user *src) +{ + snd_rawmidi_params_t params; + unsigned int val; + + if (rfile->output == NULL) + return -EINVAL; + if (get_user(params.stream, &src->stream) || + get_user(params.buffer_size, &src->buffer_size) || + get_user(params.avail_min, &src->avail_min) || + get_user(val, &src->no_active_sensing)) + return -EFAULT; + params.no_active_sensing = val; + switch (params.stream) { + case SNDRV_RAWMIDI_STREAM_OUTPUT: + return snd_rawmidi_output_params(rfile->output, ¶ms); + case SNDRV_RAWMIDI_STREAM_INPUT: + return snd_rawmidi_input_params(rfile->input, ¶ms); + } + return -EINVAL; +} + +struct sndrv_rawmidi_status32 { + s32 stream; + struct compat_timespec tstamp; + u32 avail; + u32 xruns; + unsigned char reserved[16]; +} __attribute__((packed)); + +static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile, + struct sndrv_rawmidi_status32 __user *src) +{ + int err; + snd_rawmidi_status_t status; + + if (rfile->output == NULL) + return -EINVAL; + if (get_user(status.stream, &src->stream)) + return -EFAULT; + + switch (status.stream) { + case SNDRV_RAWMIDI_STREAM_OUTPUT: + err = snd_rawmidi_output_status(rfile->output, &status); + break; + case SNDRV_RAWMIDI_STREAM_INPUT: + err = snd_rawmidi_input_status(rfile->input, &status); + break; + default: + return -EINVAL; + } + if (err < 0) + return err; + + if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) || + put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) || + put_user(status.avail, &src->avail) || + put_user(status.xruns, &src->xruns)) + return -EFAULT; + + return 0; +} + +enum { + SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32), + SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32), +}; + +static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +{ + snd_rawmidi_file_t *rfile; + void __user *argp = compat_ptr(arg); + + rfile = file->private_data; + switch (cmd) { + case SNDRV_RAWMIDI_IOCTL_PVERSION: + case SNDRV_RAWMIDI_IOCTL_INFO: + case SNDRV_RAWMIDI_IOCTL_DROP: + case SNDRV_RAWMIDI_IOCTL_DRAIN: + return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp); + case SNDRV_RAWMIDI_IOCTL_PARAMS32: + return snd_rawmidi_ioctl_params_compat(rfile, argp); + case SNDRV_RAWMIDI_IOCTL_STATUS32: + return snd_rawmidi_ioctl_status_compat(rfile, argp); + } + return -ENOIOCTLCMD; +} diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c new file mode 100644 index 000000000..902ad8b0c --- /dev/null +++ b/sound/core/seq/seq_compat.c @@ -0,0 +1,137 @@ +/* + * 32bit -> 64bit ioctl wrapper for sequencer API + * Copyright (c) by Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file included from seq.c */ + +#include + +struct sndrv_seq_port_info32 { + struct sndrv_seq_addr addr; /* client/port numbers */ + char name[64]; /* port name */ + + u32 capability; /* port capability bits */ + u32 type; /* port type bits */ + s32 midi_channels; /* channels per MIDI port */ + s32 midi_voices; /* voices per MIDI port */ + s32 synth_voices; /* voices per SYNTH port */ + + s32 read_use; /* R/O: subscribers for output (from this port) */ + s32 write_use; /* R/O: subscribers for input (to this port) */ + + u32 kernel; /* reserved for kernel use (must be NULL) */ + u32 flags; /* misc. conditioning */ + unsigned char time_queue; /* queue # for timestamping */ + char reserved[59]; /* for future use */ +}; + +static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd, + struct sndrv_seq_port_info32 __user *data32) +{ + int err = -EFAULT; + snd_seq_port_info_t *data; + mm_segment_t fs; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (! data) + return -ENOMEM; + + if (copy_from_user(data, data32, sizeof(*data32)) || + get_user(data->flags, &data32->flags) || + get_user(data->time_queue, &data32->time_queue)) + goto error; + data->kernel = NULL; + + fs = snd_enter_user(); + err = snd_seq_do_ioctl(client, cmd, data); + snd_leave_user(fs); + if (err < 0) + goto error; + + if (copy_to_user(data32, data, sizeof(*data32)) || + put_user(data->flags, &data32->flags) || + put_user(data->time_queue, &data32->time_queue)) + err = -EFAULT; + + error: + kfree(data); + return err; +} + + + +/* + */ + +enum { + SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32), + SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32), + SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32), + SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32), + SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32), +}; + +static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +{ + client_t *client = (client_t *) file->private_data; + void __user *argp = compat_ptr(arg); + + snd_assert(client != NULL, return -ENXIO); + + switch (cmd) { + case SNDRV_SEQ_IOCTL_PVERSION: + case SNDRV_SEQ_IOCTL_CLIENT_ID: + case SNDRV_SEQ_IOCTL_SYSTEM_INFO: + case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO: + case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO: + case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT: + case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT: + case SNDRV_SEQ_IOCTL_CREATE_QUEUE: + case SNDRV_SEQ_IOCTL_DELETE_QUEUE: + case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO: + case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO: + case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE: + case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS: + case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO: + case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO: + case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER: + case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER: + case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT: + case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT: + case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL: + case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL: + case SNDRV_SEQ_IOCTL_REMOVE_EVENTS: + case SNDRV_SEQ_IOCTL_QUERY_SUBS: + case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION: + case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT: + case SNDRV_SEQ_IOCTL_RUNNING_MODE: + return snd_seq_do_ioctl(client, cmd, argp); + case SNDRV_SEQ_IOCTL_CREATE_PORT32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp); + case SNDRV_SEQ_IOCTL_DELETE_PORT32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp); + case SNDRV_SEQ_IOCTL_GET_PORT_INFO32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp); + case SNDRV_SEQ_IOCTL_SET_PORT_INFO32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp); + case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32: + return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp); + } + return -ENOIOCTLCMD; +} diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c new file mode 100644 index 000000000..9fbc3957a --- /dev/null +++ b/sound/core/timer_compat.c @@ -0,0 +1,119 @@ +/* + * 32bit -> 64bit ioctl wrapper for timer API + * Copyright (c) by Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* This file included from timer.c */ + +#include + +struct sndrv_timer_info32 { + u32 flags; + s32 card; + unsigned char id[64]; + unsigned char name[80]; + u32 reserved0; + u32 resolution; + unsigned char reserved[64]; +}; + +static int snd_timer_user_info_compat(struct file *file, + struct sndrv_timer_info32 __user *_info) +{ + snd_timer_user_t *tu; + struct sndrv_timer_info32 info; + snd_timer_t *t; + + tu = file->private_data; + snd_assert(tu->timeri != NULL, return -ENXIO); + t = tu->timeri->timer; + snd_assert(t != NULL, return -ENXIO); + memset(&info, 0, sizeof(info)); + info.card = t->card ? t->card->number : -1; + if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) + info.flags |= SNDRV_TIMER_FLG_SLAVE; + strlcpy(info.id, t->id, sizeof(info.id)); + strlcpy(info.name, t->name, sizeof(info.name)); + info.resolution = t->hw.resolution; + if (copy_to_user(_info, &info, sizeof(*_info))) + return -EFAULT; + return 0; +} + +struct sndrv_timer_status32 { + struct compat_timespec tstamp; + u32 resolution; + u32 lost; + u32 overrun; + u32 queue; + unsigned char reserved[64]; +}; + +static int snd_timer_user_status_compat(struct file *file, + struct sndrv_timer_status32 __user *_status) +{ + snd_timer_user_t *tu; + snd_timer_status_t status; + + tu = file->private_data; + snd_assert(tu->timeri != NULL, return -ENXIO); + memset(&status, 0, sizeof(status)); + status.tstamp = tu->tstamp; + status.resolution = snd_timer_resolution(tu->timeri); + status.lost = tu->timeri->lost; + status.overrun = tu->overrun; + spin_lock_irq(&tu->qlock); + status.queue = tu->qused; + spin_unlock_irq(&tu->qlock); + if (copy_to_user(_status, &status, sizeof(status))) + return -EFAULT; + return 0; +} + +/* + */ + +enum { + SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32), + SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32), +}; + +static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = compat_ptr(arg); + + switch (cmd) { + case SNDRV_TIMER_IOCTL_PVERSION: + case SNDRV_TIMER_IOCTL_TREAD: + case SNDRV_TIMER_IOCTL_GINFO: + case SNDRV_TIMER_IOCTL_GPARAMS: + case SNDRV_TIMER_IOCTL_GSTATUS: + case SNDRV_TIMER_IOCTL_SELECT: + case SNDRV_TIMER_IOCTL_PARAMS: + case SNDRV_TIMER_IOCTL_START: + case SNDRV_TIMER_IOCTL_STOP: + case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_NEXT_DEVICE: + return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); + case SNDRV_TIMER_IOCTL_INFO32: + return snd_timer_user_info_compat(file, argp); + case SNDRV_TIMER_IOCTL_STATUS32: + return snd_timer_user_status_compat(file, argp); + } + return -ENOIOCTLCMD; +} diff --git a/sound/parisc/harmony.h b/sound/parisc/harmony.h new file mode 100644 index 000000000..ef77f9a57 --- /dev/null +++ b/sound/parisc/harmony.h @@ -0,0 +1,151 @@ +/* Hewlett-Packard Harmony audio driver + * Copyright (C) 2004, Kyle McMartin + */ + +#ifndef __HARMONY_H__ +#define __HARMONY_H__ + +struct harmony_buffer { + unsigned long addr; + int buf; + int count; + int size; + int coherent; +}; + +typedef struct snd_card_harmony { + int irq; + + unsigned long hpa; /* hard physical address */ + void __iomem *iobase; /* remapped io address */ + + struct parisc_device *dev; + + struct { + u32 gain; + u32 rate; + u32 format; + u32 stereo; + int playing; + int capturing; + } st; + + struct snd_dma_device dma; /* playback/capture */ + struct harmony_buffer pbuf; + struct harmony_buffer cbuf; + + struct snd_dma_buffer gdma; /* graveyard */ + struct snd_dma_buffer sdma; /* silence */ + + struct { + unsigned long play_intr; + unsigned long rec_intr; + unsigned long graveyard_intr; + unsigned long silence_intr; + } stats; + + snd_pcm_t *pcm; + snd_card_t *card; + snd_pcm_substream_t *psubs; + snd_pcm_substream_t *csubs; + snd_info_entry_t *proc; + + spinlock_t lock; + spinlock_t mixer_lock; +} harmony_t; + +#define MAX_PCM_DEVICES 1 +#define MAX_PCM_SUBSTREAMS 4 +#define MAX_MIDI_DEVICES 0 + +#define HARMONY_SIZE 64 + +#define BUF_SIZE PAGE_SIZE +#define MAX_BUFS 10 +#define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE) + +#define PLAYBACK_BUFS MAX_BUFS +#define RECORD_BUFS MAX_BUFS +#define GRAVEYARD_BUFS 1 +#define GRAVEYARD_BUFSZ (GRAVEYARD_BUFS*BUF_SIZE) +#define SILENCE_BUFS 1 +#define SILENCE_BUFSZ (SILENCE_BUFS*BUF_SIZE) + +#define HARMONY_ID 0x000 +#define HARMONY_RESET 0x004 +#define HARMONY_CNTL 0x008 +#define HARMONY_GAINCTL 0x00c +#define HARMONY_PNXTADD 0x010 +#define HARMONY_PCURADD 0x014 +#define HARMONY_RNXTADD 0x018 +#define HARMONY_RCURADD 0x01c +#define HARMONY_DSTATUS 0x020 +#define HARMONY_OV 0x024 +#define HARMONY_PIO 0x028 +#define HARMONY_DIAG 0x03c + +#define HARMONY_CNTL_C 0x80000000 +#define HARMONY_CNTL_ST 0x00000020 +#define HARMONY_CNTL_44100 0x00000015 /* HARMONY_SR_44KHZ */ +#define HARMONY_CNTL_8000 0x00000008 /* HARMONY_SR_8KHZ */ + +#define HARMONY_DSTATUS_ID 0x00000000 /* interrupts off */ +#define HARMONY_DSTATUS_PN 0x00000200 /* playback fill */ +#define HARMONY_DSTATUS_RN 0x00000002 /* record fill */ +#define HARMONY_DSTATUS_IE 0x80000000 /* interrupts on */ + +#define HARMONY_DF_16BIT_LINEAR 0x00000000 +#define HARMONY_DF_8BIT_ULAW 0x00000001 +#define HARMONY_DF_8BIT_ALAW 0x00000002 + +#define HARMONY_SS_MONO 0x00000000 +#define HARMONY_SS_STEREO 0x00000001 + +#define HARMONY_GAIN_SILENCE 0x00F00FFF +#define HARMONY_GAIN_DEFAULT 0x0FF00000 + +#define HARMONY_GAIN_HE_SHIFT 27 +#define HARMONY_GAIN_HE_MASK (1 << HARMONY_GAIN_HE_SHIFT) +#define HARMONY_GAIN_LE_SHIFT 26 +#define HARMONY_GAIN_LE_MASK (1 << HARMONY_GAIN_LE_SHIFT) +#define HARMONY_GAIN_SE_SHIFT 25 +#define HARMONY_GAIN_SE_MASK (1 << HARMONY_GAIN_SE_SHIFT) +#define HARMONY_GAIN_IS_SHIFT 24 +#define HARMONY_GAIN_IS_MASK (1 << HARMONY_GAIN_IS_SHIFT) + +#define HARMONY_GAIN_MA 0x0f +#define HARMONY_GAIN_MA_SHIFT 20 +#define HARMONY_GAIN_MA_MASK (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT) + +#define HARMONY_GAIN_IN 0x0f +#define HARMONY_GAIN_LI_SHIFT 16 +#define HARMONY_GAIN_LI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT) +#define HARMONY_GAIN_RI_SHIFT 12 +#define HARMONY_GAIN_RI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT) + +#define HARMONY_GAIN_OUT 0x3f +#define HARMONY_GAIN_LO_SHIFT 6 +#define HARMONY_GAIN_LO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_LO_SHIFT) +#define HARMONY_GAIN_RO_SHIFT 0 +#define HARMONY_GAIN_RO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_RO_SHIFT) + +#define HARMONY_MAX_OUT (HARMONY_GAIN_RO_MASK >> HARMONY_GAIN_RO_SHIFT) +#define HARMONY_MAX_IN (HARMONY_GAIN_RI_MASK >> HARMONY_GAIN_RI_SHIFT) +#define HARMONY_MAX_MON (HARMONY_GAIN_MA_MASK >> HARMONY_GAIN_MA_SHIFT) + +#define HARMONY_SR_8KHZ 0x08 +#define HARMONY_SR_16KHZ 0x09 +#define HARMONY_SR_27KHZ 0x0A +#define HARMONY_SR_32KHZ 0x0B +#define HARMONY_SR_48KHZ 0x0E +#define HARMONY_SR_9KHZ 0x0F +#define HARMONY_SR_5KHZ 0x10 +#define HARMONY_SR_11KHZ 0x11 +#define HARMONY_SR_18KHZ 0x12 +#define HARMONY_SR_22KHZ 0x13 +#define HARMONY_SR_37KHZ 0x14 +#define HARMONY_SR_44KHZ 0x15 +#define HARMONY_SR_33KHZ 0x16 +#define HARMONY_SR_6KHZ 0x17 + +#endif /* __HARMONY_H__ */ diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h new file mode 100644 index 000000000..153214940 --- /dev/null +++ b/sound/pci/emu10k1/p16v.h @@ -0,0 +1,299 @@ +/* + * Copyright (c) by James Courtier-Dutton + * Driver p16v chips + * Version: 0.21 + * + * FEATURES currently supported: + * Output fixed at S32_LE, 2 channel to hw:0,0 + * Rates: 44.1, 48, 96, 192. + * + * Changelog: + * 0.8 + * Use separate card based buffer for periods table. + * 0.9 + * Use 2 channel output streams instead of 8 channel. + * (8 channel output streams might be good for ASIO type output) + * Corrected speaker output, so Front -> Front etc. + * 0.10 + * Fixed missed interrupts. + * 0.11 + * Add Sound card model number and names. + * Add Analog volume controls. + * 0.12 + * Corrected playback interrupts. Now interrupt per period, instead of half period. + * 0.13 + * Use single trigger for multichannel. + * 0.14 + * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo. + * 0.15 + * Force buffer_size / period_size == INTEGER. + * 0.16 + * Update p16v.c to work with changed alsa api. + * 0.17 + * Update p16v.c to work with changed alsa api. Removed boot_devs. + * 0.18 + * Merging with snd-emu10k1 driver. + * 0.19 + * One stereo channel at 24bit now works. + * 0.20 + * Added better register defines. + * 0.21 + * Split from p16v.c + * + * + * BUGS: + * Some stability problems when unloading the snd-p16v kernel module. + * -- + * + * TODO: + * SPDIF out. + * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz. + * Currently capture fixed at 48000Hz. + * + * -- + * GENERAL INFO: + * Model: SB0240 + * P16V Chip: CA0151-DBS + * Audigy 2 Chip: CA0102-IAT + * AC97 Codec: STAC 9721 + * ADC: Philips 1361T (Stereo 24bit) + * DAC: CS4382-K (8-channel, 24bit, 192Khz) + * + * This code was initally based on code from ALSA's emu10k1x.c which is: + * Copyright (c) by Francisco Moraes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/********************************************************************************************************/ +/* Audigy2 P16V pointer-offset register set, accessed through the PTR2 and DATA2 registers */ +/********************************************************************************************************/ + +/* The sample rate of the SPDIF outputs is set by modifying a register in the EMU10K2 PTR register A_SPDIF_SAMPLERATE. + * The sample rate is also controlled by the same registers that control the rate of the EMU10K2 sample rate converters. + */ + +/* Initally all registers from 0x00 to 0x3f have zero contents. */ +#define PLAYBACK_LIST_ADDR 0x00 /* Base DMA address of a list of pointers to each period/size */ + /* One list entry: 4 bytes for DMA address, + * 4 bytes for period_size << 16. + * One list entry is 8 bytes long. + * One list entry for each period in the buffer. + */ +#define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */ +#define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */ +#define PLAYBACK_UNKNOWN3 0x03 /* Not used */ +#define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */ +#define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size. win2000 uses 0x04000000 */ +#define PLAYBACK_POINTER 0x06 /* Playback period pointer. Used with PLAYBACK_LIST_PTR to determine buffer position currently in DAC */ +#define PLAYBACK_FIFO_END_ADDRESS 0x07 /* Playback FIFO end address */ +#define PLAYBACK_FIFO_POINTER 0x08 /* Playback FIFO pointer and number of valid sound samples in cache */ +#define PLAYBACK_UNKNOWN9 0x09 /* Not used */ +#define CAPTURE_DMA_ADDR 0x10 /* Capture DMA address */ +#define CAPTURE_BUFFER_SIZE 0x11 /* Capture buffer size */ +#define CAPTURE_POINTER 0x12 /* Capture buffer pointer. Sample currently in ADC */ +#define CAPTURE_FIFO_POINTER 0x13 /* Capture FIFO pointer and number of valid sound samples in cache */ +#define CAPTURE_P16V_VOLUME1 0x14 /* Low: Capture volume 0xXXXX3030 */ +#define CAPTURE_P16V_VOLUME2 0x15 /* High:Has no effect on capture volume */ +#define CAPTURE_P16V_SOURCE 0x16 /* P16V source select. Set to 0x0700E4E5 for AC97 CAPTURE */ + /* [0:1] Capture input 0 channel select. 0 = Capture output 0. + * 1 = Capture output 1. + * 2 = Capture output 2. + * 3 = Capture output 3. + * [3:2] Capture input 1 channel select. 0 = Capture output 0. + * 1 = Capture output 1. + * 2 = Capture output 2. + * 3 = Capture output 3. + * [5:4] Capture input 2 channel select. 0 = Capture output 0. + * 1 = Capture output 1. + * 2 = Capture output 2. + * 3 = Capture output 3. + * [7:6] Capture input 3 channel select. 0 = Capture output 0. + * 1 = Capture output 1. + * 2 = Capture output 2. + * 3 = Capture output 3. + * [9:8] Playback input 0 channel select. 0 = Play output 0. + * 1 = Play output 1. + * 2 = Play output 2. + * 3 = Play output 3. + * [11:10] Playback input 1 channel select. 0 = Play output 0. + * 1 = Play output 1. + * 2 = Play output 2. + * 3 = Play output 3. + * [13:12] Playback input 2 channel select. 0 = Play output 0. + * 1 = Play output 1. + * 2 = Play output 2. + * 3 = Play output 3. + * [15:14] Playback input 3 channel select. 0 = Play output 0. + * 1 = Play output 1. + * 2 = Play output 2. + * 3 = Play output 3. + * [19:16] Playback mixer output enable. 1 bit per channel. + * [23:20] Capture mixer output enable. 1 bit per channel. + * [26:24] FX engine channel capture 0 = 0x60-0x67. + * 1 = 0x68-0x6f. + * 2 = 0x70-0x77. + * 3 = 0x78-0x7f. + * 4 = 0x80-0x87. + * 5 = 0x88-0x8f. + * 6 = 0x90-0x97. + * 7 = 0x98-0x9f. + * [31:27] Not used. + */ + + /* 0x1 = capture on. + * 0x100 = capture off. + * 0x200 = capture off. + * 0x1000 = capture off. + */ +#define CAPTURE_RATE_STATUS 0x17 /* Capture sample rate. Read only */ + /* [15:0] Not used. + * [18:16] Channel 0 Detected sample rate. 0 - 44.1khz + * 1 - 48 khz + * 2 - 96 khz + * 3 - 192 khz + * 7 - undefined rate. + * [19] Channel 0. 1 - Valid, 0 - Not Valid. + * [22:20] Channel 1 Detected sample rate. + * [23] Channel 1. 1 - Valid, 0 - Not Valid. + * [26:24] Channel 2 Detected sample rate. + * [27] Channel 2. 1 - Valid, 0 - Not Valid. + * [30:28] Channel 3 Detected sample rate. + * [31] Channel 3. 1 - Valid, 0 - Not Valid. + */ +/* 0x18 - 0x1f unused */ +#define PLAYBACK_LAST_SAMPLE 0x20 /* The sample currently being played. Read only */ +/* 0x21 - 0x3f unused */ +#define BASIC_INTERRUPT 0x40 /* Used by both playback and capture interrupt handler */ + /* Playback (0x1< 77770000 so it must be some sort of route. + * bit 0x1 starts DMA playback on channel_id 0 + */ +/* 0x41,42 take values from 0 - 0xffffffff, but have no effect on playback */ +/* 0x43,0x48 do not remember settings */ +/* 0x41-45 unused */ +#define WATERMARK 0x46 /* Test bit to indicate cache level usage */ + /* Values it can have while playing on channel 0. + * 0000f000, 0000f004, 0000f008, 0000f00c. + * Readonly. + */ +/* 0x47-0x4f unused */ +/* 0x50-0x5f Capture cache data */ +#define SRCSel 0x60 /* SRCSel. Default 0x4. Bypass P16V 0x14 */ + /* [0] 0 = 10K2 audio, 1 = SRC48 mixer output. + * [2] 0 = 10K2 audio, 1 = SRCMulti SPDIF mixer output. + * [4] 0 = 10K2 audio, 1 = SRCMulti I2S mixer output. + */ + /* SRC48 converts samples rates 44.1, 48, 96, 192 to 48 khz. */ + /* SRCMulti converts 48khz samples rates to 44.1, 48, 96, 192 to 48. */ + /* SRC48 and SRCMULTI sample rate select and output select. */ + /* 0xffffffff -> 0xC0000015 + * 0xXXXXXXX4 = Enable Front Left/Right + * Enable PCMs + */ + +/* 0x61 -> 0x6c are Volume controls */ +#define PLAYBACK_VOLUME_MIXER1 0x61 /* SRC48 Low to mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER2 0x62 /* SRC48 High to mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER3 0x63 /* SRCMULTI SPDIF Low to mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER4 0x64 /* SRCMULTI SPDIF High to mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER5 0x65 /* SRCMULTI I2S Low to mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER6 0x66 /* SRCMULTI I2S High to mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER7 0x67 /* P16V Low to SRCMULTI SPDIF mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER8 0x68 /* P16V High to SRCMULTI SPDIF mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER9 0x69 /* P16V Low to SRCMULTI I2S mixer input volume control. */ + /* 0xXXXX3030 = PCM0 Volume (Front). + * 0x3030XXXX = PCM1 Volume (Center) + */ +#define PLAYBACK_VOLUME_MIXER10 0x6a /* P16V High to SRCMULTI I2S mixer input volume control. */ + /* 0x3030XXXX = PCM3 Volume (Rear). */ +#define PLAYBACK_VOLUME_MIXER11 0x6b /* E10K2 Low to SRC48 mixer input volume control. */ +#define PLAYBACK_VOLUME_MIXER12 0x6c /* E10K2 High to SRC48 mixer input volume control. */ + +#define SRC48_ENABLE 0x6d /* SRC48 input audio enable */ + /* SRC48 converts samples rates 44.1, 48, 96, 192 to 48 khz. */ + /* [23:16] The corresponding P16V channel to SRC48 enabled if == 1. + * [31:24] The corresponding E10K2 channel to SRC48 enabled. + */ +#define SRCMULTI_ENABLE 0x6e /* SRCMulti input audio enable. Default 0xffffffff */ + /* SRCMulti converts 48khz samples rates to 44.1, 48, 96, 192 to 48. */ + /* [7:0] The corresponding P16V channel to SRCMulti_I2S enabled if == 1. + * [15:8] The corresponding E10K2 channel to SRCMulti I2S enabled. + * [23:16] The corresponding P16V channel to SRCMulti SPDIF enabled. + * [31:24] The corresponding E10K2 channel to SRCMulti SPDIF enabled. + */ + /* Bypass P16V 0xff00ff00 + * Bitmap. 0 = Off, 1 = On. + * P16V playback outputs: + * 0xXXXXXXX1 = PCM0 Left. (Front) + * 0xXXXXXXX2 = PCM0 Right. + * 0xXXXXXXX4 = PCM1 Left. (Center/LFE) + * 0xXXXXXXX8 = PCM1 Right. + * 0xXXXXXX1X = PCM2 Left. (Unknown) + * 0xXXXXXX2X = PCM2 Right. + * 0xXXXXXX4X = PCM3 Left. (Rear) + * 0xXXXXXX8X = PCM3 Right. + */ +#define AUDIO_OUT_ENABLE 0x6f /* Default: 000100FF */ + /* [3:0] Does something, but not documented. Probably capture enable. + * [7:4] Playback channels enable. not documented. + * [16] AC97 output enable if == 1 + * [30] 0 = SRCMulti_I2S input from fxengine 0x68-0x6f. + * 1 = SRCMulti_I2S input from SRC48 output. + * [31] 0 = SRCMulti_SPDIF input from fxengine 0x60-0x67. + * 1 = SRCMulti_SPDIF input from SRC48 output. + */ + /* 0xffffffff -> C00100FF */ + /* 0 -> Not playback sound, irq still running */ + /* 0xXXXXXX10 = PCM0 Left/Right On. (Front) + * 0xXXXXXX20 = PCM1 Left/Right On. (Center/LFE) + * 0xXXXXXX40 = PCM2 Left/Right On. (Unknown) + * 0xXXXXXX80 = PCM3 Left/Right On. (Rear) + */ +#define PLAYBACK_SPDIF_SELECT 0x70 /* Default: 12030F00 */ + /* 0xffffffff -> 3FF30FFF */ + /* 0x00000001 pauses stream/irq fail. */ + /* All other bits do not effect playback */ +#define PLAYBACK_SPDIF_SRC_SELECT 0x71 /* Default: 0000E4E4 */ + /* 0xffffffff -> F33FFFFF */ + /* All bits do not effect playback */ +#define PLAYBACK_SPDIF_USER_DATA0 0x72 /* SPDIF out user data 0 */ +#define PLAYBACK_SPDIF_USER_DATA1 0x73 /* SPDIF out user data 1 */ +/* 0x74-0x75 unknown */ +#define CAPTURE_SPDIF_CONTROL 0x76 /* SPDIF in control setting */ +#define CAPTURE_SPDIF_STATUS 0x77 /* SPDIF in status */ +#define CAPURE_SPDIF_USER_DATA0 0x78 /* SPDIF in user data 0 */ +#define CAPURE_SPDIF_USER_DATA1 0x79 /* SPDIF in user data 1 */ +#define CAPURE_SPDIF_USER_DATA2 0x7a /* SPDIF in user data 2 */ + diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c new file mode 100644 index 000000000..b7cc8e4bf --- /dev/null +++ b/sound/pci/hda/patch_cmedia.c @@ -0,0 +1,621 @@ +/* + * Universal Interface for Intel High Definition Audio Codec + * + * HD audio interface patch for C-Media CMI9880 + * + * Copyright (c) 2004 Takashi Iwai + * + * + * This driver 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 driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "hda_codec.h" +#include "hda_local.h" + + +/* board config type */ +enum { + CMI_MINIMAL, /* back 3-jack */ + CMI_MIN_FP, /* back 3-jack + front-panel 2-jack */ + CMI_FULL, /* back 6-jack + front-panel 2-jack */ + CMI_FULL_DIG, /* back 6-jack + front-panel 2-jack + digital I/O */ + CMI_ALLOUT, /* back 5-jack + front-panel 2-jack + digital out */ +}; + +struct cmi_spec { + int board_config; + unsigned int surr_switch: 1; /* switchable line,mic */ + unsigned int no_line_in: 1; /* no line-in (5-jack) */ + unsigned int front_panel: 1; /* has front-panel 2-jack */ + + /* playback */ + struct hda_multi_out multiout; + + /* capture */ + hda_nid_t *adc_nids; + hda_nid_t dig_in_nid; + + /* capture source */ + const struct hda_input_mux *input_mux; + unsigned int cur_mux[2]; + + /* channel mode */ + unsigned int num_ch_modes; + unsigned int cur_ch_mode; + const struct cmi_channel_mode *channel_modes; + + struct hda_pcm pcm_rec[2]; /* PCM information */ +}; + +/* + * input MUX + */ +static int cmi_mux_enum_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cmi_spec *spec = codec->spec; + return snd_hda_input_mux_info(spec->input_mux, uinfo); +} + +static int cmi_mux_enum_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cmi_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; + return 0; +} + +static int cmi_mux_enum_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cmi_spec *spec = codec->spec; + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, + spec->adc_nids[adc_idx], &spec->cur_mux[adc_idx]); +} + +/* + * shared line-in, mic for surrounds + */ + +/* 3-stack / 2 channel */ +static struct hda_verb cmi9880_ch2_init[] = { + /* set line-in PIN for input */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* set mic PIN for input, also enable vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* route front PCM (DAC1) to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + {} +}; + +/* 3-stack / 6 channel */ +static struct hda_verb cmi9880_ch6_init[] = { + /* set line-in PIN for output */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* set mic PIN for output */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* route front PCM (DAC1) to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + {} +}; + +/* 3-stack+front / 8 channel */ +static struct hda_verb cmi9880_ch8_init[] = { + /* set line-in PIN for output */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* set mic PIN for output */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, + /* route rear-surround PCM (DAC4) to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x03 }, + {} +}; + +struct cmi_channel_mode { + unsigned int channels; + const struct hda_verb *sequence; +}; + +static struct cmi_channel_mode cmi9880_channel_modes[3] = { + { 2, cmi9880_ch2_init }, + { 6, cmi9880_ch6_init }, + { 8, cmi9880_ch8_init }, +}; + +static int cmi_ch_mode_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cmi_spec *spec = codec->spec; + + snd_assert(spec->channel_modes, return -EINVAL); + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = spec->num_ch_modes; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + sprintf(uinfo->value.enumerated.name, "%dch", + spec->channel_modes[uinfo->value.enumerated.item].channels); + return 0; +} + +static int cmi_ch_mode_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cmi_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->cur_ch_mode; + return 0; +} + +static int cmi_ch_mode_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cmi_spec *spec = codec->spec; + + snd_assert(spec->channel_modes, return -EINVAL); + if (ucontrol->value.enumerated.item[0] >= spec->num_ch_modes) + ucontrol->value.enumerated.item[0] = spec->num_ch_modes; + if (ucontrol->value.enumerated.item[0] == spec->cur_ch_mode && + ! codec->in_resume) + return 0; + + spec->cur_ch_mode = ucontrol->value.enumerated.item[0]; + snd_hda_sequence_write(codec, spec->channel_modes[spec->cur_ch_mode].sequence); + spec->multiout.max_channels = spec->channel_modes[spec->cur_ch_mode].channels; + return 1; +} + +/* + */ +static snd_kcontrol_new_t cmi9880_basic_mixer[] = { + /* CMI9880 has no playback volumes! */ + HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), /* front */ + HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x05, 1, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x05, 2, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Side Playback Switch", 0x06, 0x0, HDA_OUTPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + * FIXME: the controls appear in the "playback" view! + */ + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 2, + .info = cmi_mux_enum_info, + .get = cmi_mux_enum_get, + .put = cmi_mux_enum_put, + }, + HDA_CODEC_VOLUME("Capture Volume", 0x08, 0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT), + HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT), + { } /* end */ +}; + +/* + * shared I/O pins + */ +static snd_kcontrol_new_t cmi9880_ch_mode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = cmi_ch_mode_info, + .get = cmi_ch_mode_get, + .put = cmi_ch_mode_put, + }, + { } /* end */ +}; + +/* AUD-in selections: + * 0x0b 0x0c 0x0d 0x0e 0x0f 0x10 0x11 0x1f 0x20 + */ +static struct hda_input_mux cmi9880_basic_mux = { + .num_items = 4, + .items = { + { "Front Mic", 0x5 }, + { "Rear Mic", 0x2 }, + { "Line", 0x1 }, + { "CD", 0x7 }, + } +}; + +static struct hda_input_mux cmi9880_no_line_mux = { + .num_items = 3, + .items = { + { "Front Mic", 0x5 }, + { "Rear Mic", 0x2 }, + { "CD", 0x7 }, + } +}; + +/* front, rear, clfe, rear_surr */ +static hda_nid_t cmi9880_dac_nids[4] = { + 0x03, 0x04, 0x05, 0x06 +}; +/* ADC0, ADC1 */ +static hda_nid_t cmi9880_adc_nids[2] = { + 0x08, 0x09 +}; + +#define CMI_DIG_OUT_NID 0x07 +#define CMI_DIG_IN_NID 0x0a + +/* + */ +static struct hda_verb cmi9880_basic_init[] = { + /* port-D for line out (rear panel) */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-A for surround (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* port-H for side (rear panel) */ + { 0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* port-C for line-in (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1/2 */ + { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, + { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, + {} /* terminator */ +}; + +static struct hda_verb cmi9880_allout_init[] = { + /* port-D for line out (rear panel) */ + { 0x0b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* port-E for HP out (front panel) */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* route front PCM to HP */ + { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x00 }, + /* port-A for side (rear panel) */ + { 0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* port-G for CLFE (rear panel) */ + { 0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* port-C for surround (rear panel) */ + { 0x0c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, + /* port-B for mic-in (rear panel) with vref */ + { 0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* port-F for mic-in (front panel) with vref */ + { 0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, + /* CD-in */ + { 0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, + /* route front mic to ADC1/2 */ + { 0x08, AC_VERB_SET_CONNECT_SEL, 0x05 }, + { 0x09, AC_VERB_SET_CONNECT_SEL, 0x05 }, + {} /* terminator */ +}; + +/* + */ +static int cmi9880_build_controls(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + int err; + + err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); + if (err < 0) + return err; + if (spec->surr_switch) { + err = snd_hda_add_new_ctls(codec, cmi9880_ch_mode_mixer); + if (err < 0) + return err; + } + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + if (err < 0) + return err; + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; + } + return 0; +} + +static int cmi9880_init(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + if (spec->board_config == CMI_ALLOUT) + snd_hda_sequence_write(codec, cmi9880_allout_init); + else + snd_hda_sequence_write(codec, cmi9880_basic_init); + return 0; +} + +#ifdef CONFIG_PM +/* + * resume + */ +static int cmi9880_resume(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + + cmi9880_init(codec); + snd_hda_resume_ctls(codec, cmi9880_basic_mixer); + if (spec->surr_switch) + snd_hda_resume_ctls(codec, cmi9880_ch_mode_mixer); + if (spec->multiout.dig_out_nid) + snd_hda_resume_spdif_out(codec); + if (spec->dig_in_nid) + snd_hda_resume_spdif_in(codec); + + return 0; +} +#endif + +/* + * Analog playback callbacks + */ +static int cmi9880_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct cmi_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); +} + +static int cmi9880_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct cmi_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, + format, substream); +} + +static int cmi9880_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct cmi_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + +/* + * Digital out + */ +static int cmi9880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct cmi_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct cmi_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +static int cmi9880_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + snd_pcm_substream_t *substream) +{ + struct cmi_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], + stream_tag, 0, format); + return 0; +} + +static int cmi9880_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + snd_pcm_substream_t *substream) +{ + struct cmi_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 0, 0, 0); + return 0; +} + + +/* + */ +static struct hda_pcm_stream cmi9880_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + .nid = 0x03, /* NID to query formats and rates */ + .ops = { + .open = cmi9880_playback_pcm_open, + .prepare = cmi9880_playback_pcm_prepare, + .cleanup = cmi9880_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream cmi9880_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x08, /* NID to query formats and rates */ + .ops = { + .prepare = cmi9880_capture_pcm_prepare, + .cleanup = cmi9880_capture_pcm_cleanup + }, +}; + +static struct hda_pcm_stream cmi9880_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in cmi9880_build_pcms */ + .ops = { + .open = cmi9880_dig_playback_pcm_open, + .close = cmi9880_dig_playback_pcm_close + }, +}; + +static struct hda_pcm_stream cmi9880_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in cmi9880_build_pcms */ +}; + +static int cmi9880_build_pcms(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->num_pcms = 1; + codec->pcm_info = info; + + info->name = "CMI9880"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_analog_capture; + + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + codec->num_pcms++; + info++; + info->name = "CMI9880 Digital"; + if (spec->multiout.dig_out_nid) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cmi9880_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + if (spec->dig_in_nid) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = cmi9880_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } + } + + return 0; +} + +static void cmi9880_free(struct hda_codec *codec) +{ + kfree(codec->spec); +} + +/* + */ + +static struct hda_board_config cmi9880_cfg_tbl[] = { + { .modelname = "minimal", .config = CMI_MINIMAL }, + { .modelname = "min_fp", .config = CMI_MIN_FP }, + { .modelname = "full", .config = CMI_FULL }, + { .modelname = "full_dig", .config = CMI_FULL_DIG }, + { .modelname = "allout", .config = CMI_ALLOUT }, + {} /* terminator */ +}; + +static struct hda_codec_ops cmi9880_patch_ops = { + .build_controls = cmi9880_build_controls, + .build_pcms = cmi9880_build_pcms, + .init = cmi9880_init, + .free = cmi9880_free, +#ifdef CONFIG_PM + .resume = cmi9880_resume, +#endif +}; + +static int patch_cmi9880(struct hda_codec *codec) +{ + struct cmi_spec *spec; + + spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + spec->board_config = snd_hda_check_board_config(codec, cmi9880_cfg_tbl); + if (spec->board_config < 0) { + snd_printd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); + spec->board_config = CMI_FULL_DIG; /* try everything */ + } + + switch (spec->board_config) { + case CMI_MINIMAL: + case CMI_MIN_FP: + spec->surr_switch = 1; + if (spec->board_config == CMI_MINIMAL) + spec->num_ch_modes = 2; + else { + spec->front_panel = 1; + spec->num_ch_modes = 3; + } + spec->channel_modes = cmi9880_channel_modes; + spec->multiout.max_channels = cmi9880_channel_modes[0].channels; + spec->input_mux = &cmi9880_basic_mux; + break; + case CMI_FULL: + case CMI_FULL_DIG: + spec->front_panel = 1; + spec->multiout.max_channels = 8; + spec->input_mux = &cmi9880_basic_mux; + if (spec->board_config == CMI_FULL_DIG) { + spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; + spec->dig_in_nid = CMI_DIG_IN_NID; + } + break; + case CMI_ALLOUT: + spec->front_panel = 1; + spec->multiout.max_channels = 8; + spec->no_line_in = 1; + spec->input_mux = &cmi9880_no_line_mux; + spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; + break; + } + + spec->multiout.num_dacs = 4; + spec->multiout.dac_nids = cmi9880_dac_nids; + + spec->adc_nids = cmi9880_adc_nids; + + codec->patch_ops = cmi9880_patch_ops; + + return 0; +} + +/* + * patch entries + */ +struct hda_codec_preset snd_hda_preset_cmedia[] = { + { .id = 0x13f69880, .name = "CMI9880", .patch = patch_cmi9880 }, + { .id = 0x434d4980, .name = "CMI9880", .patch = patch_cmi9880 }, + {} /* terminator */ +}; diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c new file mode 100644 index 000000000..3fb297b96 --- /dev/null +++ b/sound/pci/ice1712/juli.c @@ -0,0 +1,230 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for ESI Juli@ cards + * + * Copyright (c) 2004 Jaroslav Kysela + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ice1712.h" +#include "envy24ht.h" +#include "juli.h" + +/* + * chip addresses on I2C bus + */ +#define AK4114_ADDR 0x20 /* S/PDIF receiver */ +#define AK4358_ADDR 0x22 /* DAC */ + +/* + * GPIO pins + */ +#define GPIO_FREQ_MASK (3<<0) +#define GPIO_FREQ_32KHZ (0<<0) +#define GPIO_FREQ_44KHZ (1<<0) +#define GPIO_FREQ_48KHZ (2<<0) +#define GPIO_MULTI_MASK (3<<2) +#define GPIO_MULTI_4X (0<<2) +#define GPIO_MULTI_2X (1<<2) +#define GPIO_MULTI_1X (2<<2) /* also external */ +#define GPIO_MULTI_HALF (3<<2) +#define GPIO_INTERNAL_CLOCK (1<<4) +#define GPIO_ANALOG_PRESENT (1<<5) /* RO only: 0 = present */ +#define GPIO_RXMCLK_SEL (1<<7) /* must be 0 */ +#define GPIO_AK5385A_CKS0 (1<<8) +#define GPIO_AK5385A_DFS0 (1<<9) /* swapped with DFS1 according doc? */ +#define GPIO_AK5385A_DFS1 (1<<10) +#define GPIO_DIGOUT_MONITOR (1<<11) /* 1 = active */ +#define GPIO_DIGIN_MONITOR (1<<12) /* 1 = active */ +#define GPIO_ANAIN_MONITOR (1<<13) /* 1 = active */ +#define GPIO_AK5385A_MCLK (1<<14) /* must be 0 */ +#define GPIO_MUTE_CONTROL (1<<15) /* 0 = off, 1 = on */ + +static void juli_ak4114_write(void *private_data, unsigned char reg, unsigned char val) +{ + snd_vt1724_write_i2c((ice1712_t *)private_data, AK4114_ADDR, reg, val); +} + +static unsigned char juli_ak4114_read(void *private_data, unsigned char reg) +{ + return snd_vt1724_read_i2c((ice1712_t *)private_data, AK4114_ADDR, reg); +} + +/* + * AK4358 section + */ + +static void juli_akm_lock(akm4xxx_t *ak, int chip) +{ +} + +static void juli_akm_unlock(akm4xxx_t *ak, int chip) +{ +} + +static void juli_akm_write(akm4xxx_t *ak, int chip, + unsigned char addr, unsigned char data) +{ + ice1712_t *ice = ak->private_data[0]; + + snd_assert(chip == 0, return); + snd_vt1724_write_i2c(ice, AK4358_ADDR, addr, data); +} + +/* + * change the rate of envy24HT, AK4358 + */ +static void juli_akm_set_rate_val(akm4xxx_t *ak, unsigned int rate) +{ + unsigned char old, tmp, dfs; + + if (rate == 0) /* no hint - S/PDIF input is master, simply return */ + return; + + /* adjust DFS on codecs */ + if (rate > 96000) + dfs = 2; + else if (rate > 48000) + dfs = 1; + else + dfs = 0; + + tmp = snd_akm4xxx_get(ak, 0, 2); + old = (tmp >> 4) & 0x03; + if (old == dfs) + return; + /* reset DFS */ + snd_akm4xxx_reset(ak, 1); + tmp = snd_akm4xxx_get(ak, 0, 2); + tmp &= ~(0x03 << 4); + tmp |= dfs << 4; + snd_akm4xxx_set(ak, 0, 2, tmp); + snd_akm4xxx_reset(ak, 0); +} + +static akm4xxx_t akm_juli_dac __devinitdata = { + .type = SND_AK4358, + .num_dacs = 2, + .ops = { + .lock = juli_akm_lock, + .unlock = juli_akm_unlock, + .write = juli_akm_write, + .set_rate_val = juli_akm_set_rate_val + } +}; + +static int __devinit juli_add_controls(ice1712_t *ice) +{ + return snd_ice1712_akm4xxx_build_controls(ice); +} + +/* + * initialize the chip + */ +static int __devinit juli_init(ice1712_t *ice) +{ + static unsigned char ak4114_init_vals[] = { + /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, + /* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S, + /* AK4114_REG_IO0 */ AK4114_TX1E, + /* AK4114_REG_IO1 */ AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1), + /* AK4114_REG_INT0_MASK */ 0, + /* AK4114_REG_INT1_MASK */ 0 + }; + static unsigned char ak4114_init_txcsb[] = { + 0x41, 0x02, 0x2c, 0x00, 0x00 + }; + int err; + akm4xxx_t *ak; + +#if 0 + for (err = 0; err < 0x20; err++) + juli_ak4114_read(ice, err); + juli_ak4114_write(ice, 0, 0x0f); + juli_ak4114_read(ice, 0); + juli_ak4114_read(ice, 1); +#endif + err = snd_ak4114_create(ice->card, + juli_ak4114_read, + juli_ak4114_write, + ak4114_init_vals, ak4114_init_txcsb, + ice, &ice->spec.juli.ak4114); + if (err < 0) + return err; + + ice->spec.juli.analog = ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT; + + if (ice->spec.juli.analog) { + printk(KERN_INFO "juli@: analog I/O detected\n"); + ice->num_total_dacs = 2; + ice->num_total_adcs = 2; + + ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + if (! ak) + return -ENOMEM; + ice->akm_codecs = 1; + if ((err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice)) < 0) + return err; + } + + return 0; +} + + +/* + * Juli@ boards don't provide the EEPROM data except for the vendor IDs. + * hence the driver needs to sets up it properly. + */ + +static unsigned char juli_eeprom[] __devinitdata = { + 0x20, /* SYSCONF: clock 512, mpu401, 1xADC, 1xDACs */ + 0x80, /* ACLINK: I2S */ + 0xf8, /* I2S: vol, 96k, 24bit, 192k */ + 0xc3, /* SPDIF: out-en, out-int, spdif-in */ + 0x9f, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0x7f, /* GPIO_DIR2 */ + 0x9f, /* GPIO_MASK */ + 0xff, /* GPIO_MASK1 */ + 0x7f, /* GPIO_MASK2 */ + 0x16, /* GPIO_STATE: internal clock, multiple 1x, 48kHz */ + 0x80, /* GPIO_STATE1: mute */ + 0x00, /* GPIO_STATE2 */ +}; + +/* entry point */ +struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_JULI, + .name = "ESI Juli@", + .model = "juli", + .chip_init = juli_init, + .build_controls = juli_add_controls, + .eeprom_size = sizeof(juli_eeprom), + .eeprom_data = juli_eeprom, + }, + { } /* terminator */ +}; diff --git a/sound/pci/ice1712/juli.h b/sound/pci/ice1712/juli.h new file mode 100644 index 000000000..d9f8534fd --- /dev/null +++ b/sound/pci/ice1712/juli.h @@ -0,0 +1,10 @@ +#ifndef __SOUND_JULI_H +#define __SOUND_JULI_H + +#define JULI_DEVICE_DESC "{ESI,Juli@}," + +#define VT1724_SUBDEVICE_JULI 0x31305345 /* Juli@ */ + +extern struct snd_ice1712_card_info snd_vt1724_juli_cards[]; + +#endif /* __SOUND_JULI_H */ diff --git a/sound/pci/ice1712/phase.h b/sound/pci/ice1712/phase.h new file mode 100644 index 000000000..6230cf169 --- /dev/null +++ b/sound/pci/ice1712/phase.h @@ -0,0 +1,34 @@ +#ifndef __SOUND_PHASE_H +#define __SOUND_PHASE_H + +/* + * ALSA driver for ICEnsemble ICE1712 (Envy24) + * + * Lowlevel functions for Terratec PHASE 22 + * + * Copyright (c) 2005 Misha Zhilin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define PHASE_DEVICE_DESC "{Terratec,Phase 22}," + +#define VT1724_SUBDEVICE_PHASE22 0x3b155011 + +/* entry point */ +extern struct snd_ice1712_card_info snd_vt1724_phase_cards[]; + +#endif /* __SOUND_PHASE */