summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/powerpc/mpc52xx.txt12
-rw-r--r--MAINTAINERS2
-rw-r--r--arch/powerpc/boot/dts/a4m072.dts168
-rw-r--r--arch/powerpc/boot/dts/bluestone.dts127
-rw-r--r--arch/powerpc/configs/mpc5200_defconfig27
-rw-r--r--arch/powerpc/kernel/cputable.c2
-rw-r--r--arch/powerpc/kernel/idle_power4.S2
-rw-r--r--arch/powerpc/platforms/44x/Kconfig1
-rw-r--r--arch/powerpc/platforms/44x/ppc44x_simple.c2
-rw-r--r--arch/powerpc/platforms/52xx/mpc5200_simple.c1
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c10
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c70
-rw-r--r--drivers/block/viodasd.c809
-rw-r--r--drivers/cdrom/viocd.c739
-rw-r--r--drivers/char/viotape.c1041
-rw-r--r--drivers/tty/hvc/Kconfig4
-rw-r--r--drivers/tty/hvc/hvc_udbg.c8
17 files changed, 403 insertions, 2622 deletions
diff --git a/Documentation/powerpc/mpc52xx.txt b/Documentation/powerpc/mpc52xx.txt
index 10dd4ab93b85..0d540a31ea1a 100644
--- a/Documentation/powerpc/mpc52xx.txt
+++ b/Documentation/powerpc/mpc52xx.txt
@@ -2,7 +2,7 @@ Linux 2.6.x on MPC52xx family
-----------------------------
For the latest info, go to http://www.246tNt.com/mpc52xx/
-
+
To compile/use :
- U-Boot:
@@ -10,23 +10,23 @@ To compile/use :
if you wish to ).
# make lite5200_defconfig
# make uImage
-
+
then, on U-boot:
=> tftpboot 200000 uImage
=> tftpboot 400000 pRamdisk
=> bootm 200000 400000
-
+
- DBug:
# <edit Makefile to set ARCH=ppc & CROSS_COMPILE=... ( also EXTRAVERSION
if you wish to ).
# make lite5200_defconfig
# cp your_initrd.gz arch/ppc/boot/images/ramdisk.image.gz
- # make zImage.initrd
- # make
+ # make zImage.initrd
+ # make
then in DBug:
DBug> dn -i zImage.initrd.lite5200
-
+
Some remarks :
- The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100
diff --git a/MAINTAINERS b/MAINTAINERS
index 75a9a5fc230a..93de670593e9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4034,7 +4034,7 @@ M: Josh Boyer <jwboyer@gmail.com>
M: Matt Porter <mporter@kernel.crashing.org>
W: http://www.penguinppc.org/
L: linuxppc-dev@lists.ozlabs.org
-T: git git://git.infradead.org/users/jwboyer/powerpc-4xx.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git
S: Maintained
F: arch/powerpc/platforms/40x/
F: arch/powerpc/platforms/44x/
diff --git a/arch/powerpc/boot/dts/a4m072.dts b/arch/powerpc/boot/dts/a4m072.dts
new file mode 100644
index 000000000000..fabe7b7d5f13
--- /dev/null
+++ b/arch/powerpc/boot/dts/a4m072.dts
@@ -0,0 +1,168 @@
+/*
+ * a4m072 board Device Tree Source
+ *
+ * Copyright (C) 2011 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * Copyright (C) 2007 Semihalf
+ * Marian Balakowicz <m8@semihalf.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.
+ */
+
+/include/ "mpc5200b.dtsi"
+
+/ {
+ model = "anonymous,a4m072";
+ compatible = "anonymous,a4m072";
+
+ soc5200@f0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc5200b-immr";
+ ranges = <0 0xf0000000 0x0000c000>;
+ reg = <0xf0000000 0x00000100>;
+ bus-frequency = <0>; /* From boot loader */
+ system-frequency = <0>; /* From boot loader */
+
+ cdm@200 {
+ fsl,init-ext-48mhz-en = <0x0>;
+ fsl,init-fd-enable = <0x01>;
+ fsl,init-fd-counters = <0x3333>;
+ };
+
+ timer@600 {
+ fsl,has-wdt;
+ };
+
+ gpt3: timer@630 { /* General Purpose Timer in GPIO mode */
+ compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt4: timer@640 { /* General Purpose Timer in GPIO mode */
+ compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpt5: timer@650 { /* General Purpose Timer in GPIO mode */
+ compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ spi@f00 {
+ status = "disabled";
+ };
+
+ psc@2000 {
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2000 0x100>;
+ interrupts = <2 1 0>;
+ };
+
+ psc@2200 {
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2200 0x100>;
+ interrupts = <2 2 0>;
+ };
+
+ psc@2400 {
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2400 0x100>;
+ interrupts = <2 3 0>;
+ };
+
+ psc@2600 {
+ status = "disabled";
+ };
+
+ psc@2800 {
+ status = "disabled";
+ };
+
+ psc@2c00 {
+ compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart";
+ reg = <0x2c00 0x100>;
+ interrupts = <2 4 0>;
+ };
+
+ ethernet@3000 {
+ phy-handle = <&phy0>;
+ };
+
+ mdio@3000 {
+ phy0: ethernet-phy@1f {
+ reg = <0x1f>;
+ interrupts = <1 2 0>; /* IRQ 2 active low */
+ };
+ };
+
+ i2c@3d00 {
+ status = "disabled";
+ };
+
+ i2c@3d40 {
+ hwmon@2e {
+ compatible = "nsc,lm87";
+ reg = <0x2e>;
+ };
+ rtc@51 {
+ compatible = "nxp,rtc8564";
+ reg = <0x51>;
+ };
+ };
+ };
+
+ localbus {
+ compatible = "fsl,mpc5200b-lpb","simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0 0 0xfe000000 0x02000000
+ 1 0 0x62000000 0x00400000
+ 2 0 0x64000000 0x00200000
+ 3 0 0x66000000 0x01000000
+ 6 0 0x68000000 0x01000000
+ 7 0 0x6a000000 0x00000004>;
+
+ flash@0,0 {
+ compatible = "cfi-flash";
+ reg = <0 0 0x02000000>;
+ bank-width = <2>;
+ #size-cells = <1>;
+ #address-cells = <1>;
+ };
+ sram0@1,0 {
+ compatible = "mtd-ram";
+ reg = <1 0x00000 0x00400000>;
+ bank-width = <2>;
+ };
+ };
+
+ pci@f0000d00 {
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ compatible = "fsl,mpc5200-pci";
+ reg = <0xf0000d00 0x100>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x16 */
+ 0xc000 0 0 1 &mpc5200_pic 1 3 3
+ 0xc000 0 0 2 &mpc5200_pic 1 3 3
+ 0xc000 0 0 3 &mpc5200_pic 1 3 3
+ 0xc000 0 0 4 &mpc5200_pic 1 3 3>;
+ clock-frequency = <0>; /* From boot loader */
+ interrupts = <2 8 0 2 9 0 2 10 0>;
+ bus-range = <0 0>;
+ ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000
+ 0x02000000 0 0x90000000 0x90000000 0 0x10000000
+ 0x01000000 0 0x00000000 0xa0000000 0 0x01000000>;
+ };
+};
diff --git a/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts
index 2a56a0dbd1f7..cfa23bf7564f 100644
--- a/arch/powerpc/boot/dts/bluestone.dts
+++ b/arch/powerpc/boot/dts/bluestone.dts
@@ -33,7 +33,7 @@
aliases {
ethernet0 = &EMAC0;
serial0 = &UART0;
- //serial1 = &UART1; --gcl missing UART1 label
+ serial1 = &UART1;
};
cpus {
@@ -52,7 +52,7 @@
d-cache-size = <32768>;
dcr-controller;
dcr-access-method = "native";
- //next-level-cache = <&L2C0>; --gcl missing L2C0 label
+ next-level-cache = <&L2C0>;
};
};
@@ -117,6 +117,16 @@
dcr-reg = <0x00c 0x002>;
};
+ L2C0: l2c {
+ compatible = "ibm,l2-cache-apm82181", "ibm,l2-cache";
+ dcr-reg = <0x020 0x008
+ 0x030 0x008>;
+ cache-line-size = <32>;
+ cache-size = <262144>;
+ interrupt-parent = <&UIC1>;
+ interrupts = <11 1>;
+ };
+
plb {
compatible = "ibm,plb4";
#address-cells = <2>;
@@ -182,6 +192,53 @@
reg = <0x001a0000 0x00060000>;
};
};
+
+ ndfc@1,0 {
+ compatible = "ibm,ndfc";
+ reg = <0x00000003 0x00000000 0x00002000>;
+ ccr = <0x00001000>;
+ bank-settings = <0x80002222>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* 2Gb Nand Flash */
+ nand {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "firmware";
+ reg = <0x00000000 0x00C00000>;
+ };
+ partition@c00000 {
+ label = "environment";
+ reg = <0x00C00000 0x00B00000>;
+ };
+ partition@1700000 {
+ label = "kernel";
+ reg = <0x01700000 0x00E00000>;
+ };
+ partition@2500000 {
+ label = "root";
+ reg = <0x02500000 0x08200000>;
+ };
+ partition@a700000 {
+ label = "device-tree";
+ reg = <0x0A700000 0x00B00000>;
+ };
+ partition@b200000 {
+ label = "config";
+ reg = <0x0B200000 0x00D00000>;
+ };
+ partition@bf00000 {
+ label = "diag";
+ reg = <0x0BF00000 0x00C00000>;
+ };
+ partition@cb00000 {
+ label = "vendor";
+ reg = <0x0CB00000 0x3500000>;
+ };
+ };
+ };
};
UART0: serial@ef600300 {
@@ -195,11 +252,36 @@
interrupts = <0x1 0x4>;
};
+ UART1: serial@ef600400 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xef600400 0x00000008>;
+ virtual-reg = <0xef600400>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>; /* Filled in by U-Boot */
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x1 0x4>;
+ };
+
IIC0: i2c@ef600700 {
compatible = "ibm,iic";
reg = <0xef600700 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x2 0x4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ rtc@68 {
+ compatible = "stm,m41t80";
+ reg = <0x68>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x9 0x8>;
+ };
+ sttm@4C {
+ compatible = "adm,adm1032";
+ reg = <0x4C>;
+ interrupt-parent = <&UIC1>;
+ interrupts = <0x1E 0x8>; /* CPU_THERNAL_L */
+ };
};
IIC1: i2c@ef600800 {
@@ -250,5 +332,46 @@
};
};
+ PCIE0: pciex@d00000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-apm821xx", "ibm,plb-pciex";
+ primary;
+ port = <0x0>; /* port number */
+ reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */
+ 0x0000000c 0x08010000 0x00001000>; /* Registers */
+ dcr-reg = <0x100 0x020>;
+ sdr-base = <0x300>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
+ 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000
+ 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+
+ /* This drives busses 40 to 0x7f */
+ bus-range = <0x40 0x7f>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */
+ 0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */
+ 0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
+ 0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
+ };
};
};
diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig
index 2a1320fb2723..6640a35bebb7 100644
--- a/arch/powerpc/configs/mpc5200_defconfig
+++ b/arch/powerpc/configs/mpc5200_defconfig
@@ -1,8 +1,8 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
+CONFIG_SPARSE_IRQ=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
@@ -13,15 +13,12 @@ CONFIG_PPC_EFIKA=y
CONFIG_PPC_LITE5200=y
CONFIG_PPC_MEDIA5200=y
CONFIG_PPC_MPC5200_BUGFIX=y
-CONFIG_PPC_MPC5200_GPIO=y
CONFIG_PPC_MPC5200_LPBFIFO=m
# CONFIG_PPC_PMAC is not set
CONFIG_PPC_BESTCOMM=y
CONFIG_SIMPLE_GPIO=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
-CONFIG_SPARSE_IRQ=y
-CONFIG_PM=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -36,23 +33,20 @@ CONFIG_SYN_COOKIES=y
# CONFIG_IPV6 is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_OF_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_RAM=y
CONFIG_MTD_ROM=y
CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_PLATRAM=y
CONFIG_MTD_UBI=m
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=32768
-CONFIG_MISC_DEVICES=y
CONFIG_EEPROM_AT24=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -61,11 +55,10 @@ CONFIG_ATA=y
CONFIG_PATA_MPC52xx=y
CONFIG_PATA_PLATFORM=y
CONFIG_NETDEVICES=y
-CONFIG_LXT_PHY=y
-CONFIG_NET_ETHERNET=y
CONFIG_FEC_MPC52xx=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_AMD_PHY=y
+CONFIG_LXT_PHY=y
+CONFIG_FIXED_PHY=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
@@ -80,11 +73,17 @@ CONFIG_SPI_GPIO=m
CONFIG_SPI_MPC52xx=m
CONFIG_SPI_MPC52xx_PSC=m
CONFIG_SPI_SPIDEV=m
+CONFIG_GPIO_SYSFS=y
+CONFIG_SENSORS_LM80=y
+CONFIG_SENSORS_LM87=m
CONFIG_WATCHDOG=y
+CONFIG_MFD_SM501=m
CONFIG_DRM=y
CONFIG_VIDEO_OUTPUT_CONTROL=y
CONFIG_FB=y
+CONFIG_FB_FOREIGN_ENDIAN=y
CONFIG_FB_RADEON=y
+CONFIG_FB_SM501=m
# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
@@ -124,10 +123,11 @@ CONFIG_USB_STORAGE=y
CONFIG_NEW_LEDS=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_DS1374=y
+CONFIG_RTC_DRV_PCF8563=m
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_PROC_KCORE=y
@@ -145,5 +145,4 @@ CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 4dccf51064ea..138ae183c440 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1816,7 +1816,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.platform = "ppc440",
},
{ /* 464 in APM821xx */
- .pvr_mask = 0xffffff00,
+ .pvr_mask = 0xfffffff0,
.pvr_value = 0x12C41C80,
.cpu_name = "APM821XX",
.cpu_features = CPU_FTRS_44X,
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index d8cdba4c28b2..2c71b0fc9f91 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -50,9 +50,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
addi r1,r1,128
ld r0,16(r1)
mtlr r0
+ mfmsr r7
#endif /* CONFIG_TRACE_IRQFLAGS */
- TRACE_ENABLE_INTS
li r0,1
stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */
BEGIN_FTR_SECTION
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index fcf6bf2ceee9..2e4e64abfab4 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -23,6 +23,7 @@ config BLUESTONE
default n
select PPC44x_SIMPLE
select APM821xx
+ select PPC4xx_PCI_EXPRESS
select IBM_EMAC_RGMII
help
This option enables support for the APM APM821xx Evaluation board.
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c
index 8d2202763415..3ffb915446e3 100644
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
@@ -52,7 +52,7 @@ machine_device_initcall(ppc44x_simple, ppc44x_device_probe);
static char *board[] __initdata = {
"amcc,arches",
"amcc,bamboo",
- "amcc,bluestone",
+ "apm,bluestone",
"amcc,glacier",
"ibm,ebony",
"amcc,eiger",
diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c
index 846b789fb195..c0aa04068d69 100644
--- a/arch/powerpc/platforms/52xx/mpc5200_simple.c
+++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c
@@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void)
/* list of the supported boards */
static const char *board[] __initdata = {
+ "anonymous,a4m072",
"anon,charon",
"intercontrol,digsy-mtc",
"manroland,mucmc52",
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index 369fd5457a3f..d7e94f49532a 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -98,13 +98,11 @@ struct mpc52xx_gpio_wkup __iomem *wkup_gpio;
* of the localplus bus to the of_platform
* bus.
*/
-void __init
-mpc52xx_declare_of_platform_devices(void)
+void __init mpc52xx_declare_of_platform_devices(void)
{
- /* Find every child of the SOC node and add it to of_platform */
- if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL))
- printk(KERN_ERR __FILE__ ": "
- "Error while probing of_platform bus\n");
+ /* Find all the 'platform' devices and register them. */
+ if (of_platform_populate(NULL, mpc52xx_bus_ids, NULL, NULL))
+ pr_err(__FILE__ ": Error while populating devices from DT\n");
}
/*
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index 4f05f7542346..56e8b3c3c890 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -1050,6 +1050,74 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata =
.check_link = ppc4xx_pciex_check_link_sdr,
};
+static int __init apm821xx_pciex_core_init(struct device_node *np)
+{
+ /* Return the number of pcie port */
+ return 1;
+}
+
+static int apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
+{
+ u32 val;
+
+ /*
+ * Do a software reset on PCIe ports.
+ * This code is to fix the issue that pci drivers doesn't re-assign
+ * bus number for PCIE devices after Uboot
+ * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000
+ * PT quad port, SAS LSI 1064E)
+ */
+
+ mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0);
+ mdelay(10);
+
+ if (port->endpoint)
+ val = PTYPE_LEGACY_ENDPOINT << 20;
+ else
+ val = PTYPE_ROOT_PORT << 20;
+
+ val |= LNKW_X1 << 12;
+
+ mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
+ mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000);
+ mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000);
+
+ mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
+ mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
+ mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
+
+ mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000);
+ mdelay(50);
+ mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000);
+
+ mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
+ mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) |
+ (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN));
+
+ /* Poll for PHY reset */
+ val = PESDR0_460EX_RSTSTA - port->sdr_base;
+ if (ppc4xx_pciex_wait_on_sdr(port, val, 0x1, 1, 100)) {
+ printk(KERN_WARNING "%s: PCIE: Can't reset PHY\n", __func__);
+ return -EBUSY;
+ } else {
+ mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
+ (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) &
+ ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) |
+ PESDRx_RCSSET_RSTPYN);
+
+ port->has_ibpre = 1;
+ return 0;
+ }
+}
+
+static struct ppc4xx_pciex_hwops apm821xx_pcie_hwops __initdata = {
+ .want_sdr = true,
+ .core_init = apm821xx_pciex_core_init,
+ .port_init_hw = apm821xx_pciex_init_port_hw,
+ .setup_utl = ppc460ex_pciex_init_utl,
+ .check_link = ppc4xx_pciex_check_link_sdr,
+};
+
static int __init ppc460sx_pciex_core_init(struct device_node *np)
{
/* HSS drive amplitude */
@@ -1362,6 +1430,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops;
if (of_device_is_compatible(np, "ibm,plb-pciex-460sx"))
ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops;
+ if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx"))
+ ppc4xx_pciex_hwops = &apm821xx_pcie_hwops;
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
deleted file mode 100644
index 9a5b2a2d616d..000000000000
--- a/drivers/block/viodasd.c
+++ /dev/null
@@ -1,809 +0,0 @@
-/* -*- linux-c -*-
- * viodasd.c
- * Authors: Dave Boutcher <boutcher@us.ibm.com>
- * Ryan Arnold <ryanarn@us.ibm.com>
- * Colin Devilbiss <devilbis@us.ibm.com>
- * Stephen Rothwell
- *
- * (C) Copyright 2000-2004 IBM Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * This routine provides access to disk space (termed "DASD" in historical
- * IBM terms) owned and managed by an OS/400 partition running on the
- * same box as this Linux partition.
- *
- * All disk operations are performed by sending messages back and forth to
- * the OS/400 partition.
- */
-
-#define pr_fmt(fmt) "viod: " fmt
-
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/mutex.h>
-#include <linux/dma-mapping.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <linux/scatterlist.h>
-
-#include <asm/uaccess.h>
-#include <asm/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_lp_config.h>
-#include <asm/iseries/vio.h>
-#include <asm/firmware.h>
-
-MODULE_DESCRIPTION("iSeries Virtual DASD");
-MODULE_AUTHOR("Dave Boutcher");
-MODULE_LICENSE("GPL");
-
-/*
- * We only support 7 partitions per physical disk....so with minor
- * numbers 0-255 we get a maximum of 32 disks.
- */
-#define VIOD_GENHD_NAME "iseries/vd"
-
-#define VIOD_VERS "1.64"
-
-enum {
- PARTITION_SHIFT = 3,
- MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS,
- MAX_DISK_NAME = FIELD_SIZEOF(struct gendisk, disk_name)
-};
-
-static DEFINE_MUTEX(viodasd_mutex);
-static DEFINE_SPINLOCK(viodasd_spinlock);
-
-#define VIOMAXREQ 16
-
-#define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0])
-
-struct viodasd_waitevent {
- struct completion com;
- int rc;
- u16 sub_result;
- int max_disk; /* open */
-};
-
-static const struct vio_error_entry viodasd_err_table[] = {
- { 0x0201, EINVAL, "Invalid Range" },
- { 0x0202, EINVAL, "Invalid Token" },
- { 0x0203, EIO, "DMA Error" },
- { 0x0204, EIO, "Use Error" },
- { 0x0205, EIO, "Release Error" },
- { 0x0206, EINVAL, "Invalid Disk" },
- { 0x0207, EBUSY, "Can't Lock" },
- { 0x0208, EIO, "Already Locked" },
- { 0x0209, EIO, "Already Unlocked" },
- { 0x020A, EIO, "Invalid Arg" },
- { 0x020B, EIO, "Bad IFS File" },
- { 0x020C, EROFS, "Read Only Device" },
- { 0x02FF, EIO, "Internal Error" },
- { 0x0000, 0, NULL },
-};
-
-/*
- * Figure out the biggest I/O request (in sectors) we can accept
- */
-#define VIODASD_MAXSECTORS (4096 / 512 * VIOMAXBLOCKDMA)
-
-/*
- * Number of disk I/O requests we've sent to OS/400
- */
-static int num_req_outstanding;
-
-/*
- * This is our internal structure for keeping track of disk devices
- */
-struct viodasd_device {
- u16 cylinders;
- u16 tracks;
- u16 sectors;
- u16 bytes_per_sector;
- u64 size;
- int read_only;
- spinlock_t q_lock;
- struct gendisk *disk;
- struct device *dev;
-} viodasd_devices[MAX_DISKNO];
-
-/*
- * External open entry point.
- */
-static int viodasd_open(struct block_device *bdev, fmode_t mode)
-{
- struct viodasd_device *d = bdev->bd_disk->private_data;
- HvLpEvent_Rc hvrc;
- struct viodasd_waitevent we;
- u16 flags = 0;
-
- if (d->read_only) {
- if (mode & FMODE_WRITE)
- return -EROFS;
- flags = vioblockflags_ro;
- }
-
- init_completion(&we.com);
-
- /* Send the open event to OS/400 */
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_blockio | vioblockopen,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)&we, VIOVERSION << 16,
- ((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32),
- 0, 0, 0);
- if (hvrc != 0) {
- pr_warning("HV open failed %d\n", (int)hvrc);
- return -EIO;
- }
-
- wait_for_completion(&we.com);
-
- /* Check the return code */
- if (we.rc != 0) {
- const struct vio_error_entry *err =
- vio_lookup_rc(viodasd_err_table, we.sub_result);
-
- pr_warning("bad rc opening disk: %d:0x%04x (%s)\n",
- (int)we.rc, we.sub_result, err->msg);
- return -EIO;
- }
-
- return 0;
-}
-
-static int viodasd_unlocked_open(struct block_device *bdev, fmode_t mode)
-{
- int ret;
-
- mutex_lock(&viodasd_mutex);
- ret = viodasd_open(bdev, mode);
- mutex_unlock(&viodasd_mutex);
-
- return ret;
-}
-
-
-/*
- * External release entry point.
- */
-static int viodasd_release(struct gendisk *disk, fmode_t mode)
-{
- struct viodasd_device *d = disk->private_data;
- HvLpEvent_Rc hvrc;
-
- mutex_lock(&viodasd_mutex);
- /* Send the event to OS/400. We DON'T expect a response */
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_blockio | vioblockclose,
- HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- 0, VIOVERSION << 16,
- ((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */,
- 0, 0, 0);
- if (hvrc != 0)
- pr_warning("HV close call failed %d\n", (int)hvrc);
-
- mutex_unlock(&viodasd_mutex);
-
- return 0;
-}
-
-
-/* External ioctl entry point.
- */
-static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- struct gendisk *disk = bdev->bd_disk;
- struct viodasd_device *d = disk->private_data;
-
- geo->sectors = d->sectors ? d->sectors : 32;
- geo->heads = d->tracks ? d->tracks : 64;
- geo->cylinders = d->cylinders ? d->cylinders :
- get_capacity(disk) / (geo->sectors * geo->heads);
-
- return 0;
-}
-
-/*
- * Our file operations table
- */
-static const struct block_device_operations viodasd_fops = {
- .owner = THIS_MODULE,
- .open = viodasd_unlocked_open,
- .release = viodasd_release,
- .getgeo = viodasd_getgeo,
-};
-
-/*
- * End a request
- */
-static void viodasd_end_request(struct request *req, int error,
- int num_sectors)
-{
- __blk_end_request(req, error, num_sectors << 9);
-}
-
-/*
- * Send an actual I/O request to OS/400
- */
-static int send_request(struct request *req)
-{
- u64 start;
- int direction;
- int nsg;
- u16 viocmd;
- HvLpEvent_Rc hvrc;
- struct vioblocklpevent *bevent;
- struct HvLpEvent *hev;
- struct scatterlist sg[VIOMAXBLOCKDMA];
- int sgindex;
- struct viodasd_device *d;
- unsigned long flags;
-
- start = (u64)blk_rq_pos(req) << 9;
-
- if (rq_data_dir(req) == READ) {
- direction = DMA_FROM_DEVICE;
- viocmd = viomajorsubtype_blockio | vioblockread;
- } else {
- direction = DMA_TO_DEVICE;
- viocmd = viomajorsubtype_blockio | vioblockwrite;
- }
-
- d = req->rq_disk->private_data;
-
- /* Now build the scatter-gather list */
- sg_init_table(sg, VIOMAXBLOCKDMA);
- nsg = blk_rq_map_sg(req->q, req, sg);
- nsg = dma_map_sg(d->dev, sg, nsg, direction);
-
- spin_lock_irqsave(&viodasd_spinlock, flags);
- num_req_outstanding++;
-
- /* This optimization handles a single DMA block */
- if (nsg == 1)
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo, viocmd,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)req, VIOVERSION << 16,
- ((u64)DEVICE_NO(d) << 48), start,
- ((u64)sg_dma_address(&sg[0])) << 32,
- sg_dma_len(&sg[0]));
- else {
- bevent = (struct vioblocklpevent *)
- vio_get_event_buffer(viomajorsubtype_blockio);
- if (bevent == NULL) {
- pr_warning("error allocating disk event buffer\n");
- goto error_ret;
- }
-
- /*
- * Now build up the actual request. Note that we store
- * the pointer to the request in the correlation
- * token so we can match the response up later
- */
- memset(bevent, 0, sizeof(struct vioblocklpevent));
- hev = &bevent->event;
- hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK |
- HV_LP_EVENT_INT;
- hev->xType = HvLpEvent_Type_VirtualIo;
- hev->xSubtype = viocmd;
- hev->xSourceLp = HvLpConfig_getLpIndex();
- hev->xTargetLp = viopath_hostLp;
- hev->xSizeMinus1 =
- offsetof(struct vioblocklpevent, u.rw_data.dma_info) +
- (sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1;
- hev->xSourceInstanceId = viopath_sourceinst(viopath_hostLp);
- hev->xTargetInstanceId = viopath_targetinst(viopath_hostLp);
- hev->xCorrelationToken = (u64)req;
- bevent->version = VIOVERSION;
- bevent->disk = DEVICE_NO(d);
- bevent->u.rw_data.offset = start;
-
- /*
- * Copy just the dma information from the sg list
- * into the request
- */
- for (sgindex = 0; sgindex < nsg; sgindex++) {
- bevent->u.rw_data.dma_info[sgindex].token =
- sg_dma_address(&sg[sgindex]);
- bevent->u.rw_data.dma_info[sgindex].len =
- sg_dma_len(&sg[sgindex]);
- }
-
- /* Send the request */
- hvrc = HvCallEvent_signalLpEvent(&bevent->event);
- vio_free_event_buffer(viomajorsubtype_blockio, bevent);
- }
-
- if (hvrc != HvLpEvent_Rc_Good) {
- pr_warning("error sending disk event to OS/400 (rc %d)\n",
- (int)hvrc);
- goto error_ret;
- }
- spin_unlock_irqrestore(&viodasd_spinlock, flags);
- return 0;
-
-error_ret:
- num_req_outstanding--;
- spin_unlock_irqrestore(&viodasd_spinlock, flags);
- dma_unmap_sg(d->dev, sg, nsg, direction);
- return -1;
-}
-
-/*
- * This is the external request processing routine
- */
-static void do_viodasd_request(struct request_queue *q)
-{
- struct request *req;
-
- /*
- * If we already have the maximum number of requests
- * outstanding to OS/400 just bail out. We'll come
- * back later.
- */
- while (num_req_outstanding < VIOMAXREQ) {
- req = blk_fetch_request(q);
- if (req == NULL)
- return;
- /* check that request contains a valid command */
- if (req->cmd_type != REQ_TYPE_FS) {
- viodasd_end_request(req, -EIO, blk_rq_sectors(req));
- continue;
- }
- /* Try sending the request */
- if (send_request(req) != 0)
- viodasd_end_request(req, -EIO, blk_rq_sectors(req));
- }
-}
-
-/*
- * Probe a single disk and fill in the viodasd_device structure
- * for it.
- */
-static int probe_disk(struct viodasd_device *d)
-{
- HvLpEvent_Rc hvrc;
- struct viodasd_waitevent we;
- int dev_no = DEVICE_NO(d);
- struct gendisk *g;
- struct request_queue *q;
- u16 flags = 0;
-
-retry:
- init_completion(&we.com);
-
- /* Send the open event to OS/400 */
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_blockio | vioblockopen,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)&we, VIOVERSION << 16,
- ((u64)dev_no << 48) | ((u64)flags<< 32),
- 0, 0, 0);
- if (hvrc != 0) {
- pr_warning("bad rc on HV open %d\n", (int)hvrc);
- return 0;
- }
-
- wait_for_completion(&we.com);
-
- if (we.rc != 0) {
- if (flags != 0)
- return 0;
- /* try again with read only flag set */
- flags = vioblockflags_ro;
- goto retry;
- }
- if (we.max_disk > (MAX_DISKNO - 1)) {
- printk_once(KERN_INFO pr_fmt("Only examining the first %d of %d disks connected\n"),
- MAX_DISKNO, we.max_disk + 1);
- }
-
- /* Send the close event to OS/400. We DON'T expect a response */
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_blockio | vioblockclose,
- HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- 0, VIOVERSION << 16,
- ((u64)dev_no << 48) | ((u64)flags << 32),
- 0, 0, 0);
- if (hvrc != 0) {
- pr_warning("bad rc sending event to OS/400 %d\n", (int)hvrc);
- return 0;
- }
-
- if (d->dev == NULL) {
- /* this is when we reprobe for new disks */
- if (vio_create_viodasd(dev_no) == NULL) {
- pr_warning("cannot allocate virtual device for disk %d\n",
- dev_no);
- return 0;
- }
- /*
- * The vio_create_viodasd will have recursed into this
- * routine with d->dev set to the new vio device and
- * will finish the setup of the disk below.
- */
- return 1;
- }
-
- /* create the request queue for the disk */
- spin_lock_init(&d->q_lock);
- q = blk_init_queue(do_viodasd_request, &d->q_lock);
- if (q == NULL) {
- pr_warning("cannot allocate queue for disk %d\n", dev_no);
- return 0;
- }
- g = alloc_disk(1 << PARTITION_SHIFT);
- if (g == NULL) {
- pr_warning("cannot allocate disk structure for disk %d\n",
- dev_no);
- blk_cleanup_queue(q);
- return 0;
- }
-
- d->disk = g;
- blk_queue_max_segments(q, VIOMAXBLOCKDMA);
- blk_queue_max_hw_sectors(q, VIODASD_MAXSECTORS);
- g->major = VIODASD_MAJOR;
- g->first_minor = dev_no << PARTITION_SHIFT;
- if (dev_no >= 26)
- snprintf(g->disk_name, sizeof(g->disk_name),
- VIOD_GENHD_NAME "%c%c",
- 'a' + (dev_no / 26) - 1, 'a' + (dev_no % 26));
- else
- snprintf(g->disk_name, sizeof(g->disk_name),
- VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26));
- g->fops = &viodasd_fops;
- g->queue = q;
- g->private_data = d;
- g->driverfs_dev = d->dev;
- set_capacity(g, d->size >> 9);
-
- pr_info("disk %d: %lu sectors (%lu MB) CHS=%d/%d/%d sector size %d%s\n",
- dev_no, (unsigned long)(d->size >> 9),
- (unsigned long)(d->size >> 20),
- (int)d->cylinders, (int)d->tracks,
- (int)d->sectors, (int)d->bytes_per_sector,
- d->read_only ? " (RO)" : "");
-
- /* register us in the global list */
- add_disk(g);
- return 1;
-}
-
-/* returns the total number of scatterlist elements converted */
-static int block_event_to_scatterlist(const struct vioblocklpevent *bevent,
- struct scatterlist *sg, int *total_len)
-{
- int i, numsg;
- const struct rw_data *rw_data = &bevent->u.rw_data;
- static const int offset =
- offsetof(struct vioblocklpevent, u.rw_data.dma_info);
- static const int element_size = sizeof(rw_data->dma_info[0]);
-
- numsg = ((bevent->event.xSizeMinus1 + 1) - offset) / element_size;
- if (numsg > VIOMAXBLOCKDMA)
- numsg = VIOMAXBLOCKDMA;
-
- *total_len = 0;
- sg_init_table(sg, VIOMAXBLOCKDMA);
- for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) {
- sg_dma_address(&sg[i]) = rw_data->dma_info[i].token;
- sg_dma_len(&sg[i]) = rw_data->dma_info[i].len;
- *total_len += rw_data->dma_info[i].len;
- }
- return i;
-}
-
-/*
- * Restart all queues, starting with the one _after_ the disk given,
- * thus reducing the chance of starvation of higher numbered disks.
- */
-static void viodasd_restart_all_queues_starting_from(int first_index)
-{
- int i;
-
- for (i = first_index + 1; i < MAX_DISKNO; ++i)
- if (viodasd_devices[i].disk)
- blk_run_queue(viodasd_devices[i].disk->queue);
- for (i = 0; i <= first_index; ++i)
- if (viodasd_devices[i].disk)
- blk_run_queue(viodasd_devices[i].disk->queue);
-}
-
-/*
- * For read and write requests, decrement the number of outstanding requests,
- * Free the DMA buffers we allocated.
- */
-static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
-{
- int num_sg, num_sect, pci_direction, total_len;
- struct request *req;
- struct scatterlist sg[VIOMAXBLOCKDMA];
- struct HvLpEvent *event = &bevent->event;
- unsigned long irq_flags;
- struct viodasd_device *d;
- int error;
- spinlock_t *qlock;
-
- num_sg = block_event_to_scatterlist(bevent, sg, &total_len);
- num_sect = total_len >> 9;
- if (event->xSubtype == (viomajorsubtype_blockio | vioblockread))
- pci_direction = DMA_FROM_DEVICE;
- else
- pci_direction = DMA_TO_DEVICE;
- req = (struct request *)bevent->event.xCorrelationToken;
- d = req->rq_disk->private_data;
-
- dma_unmap_sg(d->dev, sg, num_sg, pci_direction);
-
- /*
- * Since this is running in interrupt mode, we need to make sure
- * we're not stepping on any global I/O operations
- */
- spin_lock_irqsave(&viodasd_spinlock, irq_flags);
- num_req_outstanding--;
- spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
-
- error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO;
- if (error) {
- const struct vio_error_entry *err;
- err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
- pr_warning("read/write error %d:0x%04x (%s)\n",
- event->xRc, bevent->sub_result, err->msg);
- num_sect = blk_rq_sectors(req);
- }
- qlock = req->q->queue_lock;
- spin_lock_irqsave(qlock, irq_flags);
- viodasd_end_request(req, error, num_sect);
- spin_unlock_irqrestore(qlock, irq_flags);
-
- /* Finally, try to get more requests off of this device's queue */
- viodasd_restart_all_queues_starting_from(DEVICE_NO(d));
-
- return 0;
-}
-
-/* This routine handles incoming block LP events */
-static void handle_block_event(struct HvLpEvent *event)
-{
- struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
- struct viodasd_waitevent *pwe;
-
- if (event == NULL)
- /* Notification that a partition went away! */
- return;
- /* First, we should NEVER get an int here...only acks */
- if (hvlpevent_is_int(event)) {
- pr_warning("Yikes! got an int in viodasd event handler!\n");
- if (hvlpevent_need_ack(event)) {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
-
- switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
- case vioblockopen:
- /*
- * Handle a response to an open request. We get all the
- * disk information in the response, so update it. The
- * correlation token contains a pointer to a waitevent
- * structure that has a completion in it. update the
- * return code in the waitevent structure and post the
- * completion to wake up the guy who sent the request
- */
- pwe = (struct viodasd_waitevent *)event->xCorrelationToken;
- pwe->rc = event->xRc;
- pwe->sub_result = bevent->sub_result;
- if (event->xRc == HvLpEvent_Rc_Good) {
- const struct open_data *data = &bevent->u.open_data;
- struct viodasd_device *device =
- &viodasd_devices[bevent->disk];
- device->read_only =
- bevent->flags & vioblockflags_ro;
- device->size = data->disk_size;
- device->cylinders = data->cylinders;
- device->tracks = data->tracks;
- device->sectors = data->sectors;
- device->bytes_per_sector = data->bytes_per_sector;
- pwe->max_disk = data->max_disk;
- }
- complete(&pwe->com);
- break;
- case vioblockclose:
- break;
- case vioblockread:
- case vioblockwrite:
- viodasd_handle_read_write(bevent);
- break;
-
- default:
- pr_warning("invalid subtype!");
- if (hvlpevent_need_ack(event)) {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
-}
-
-/*
- * Get the driver to reprobe for more disks.
- */
-static ssize_t probe_disks(struct device_driver *drv, const char *buf,
- size_t count)
-{
- struct viodasd_device *d;
-
- for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) {
- if (d->disk == NULL)
- probe_disk(d);
- }
- return count;
-}
-static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks);
-
-static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
- struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
-
- d->dev = &vdev->dev;
- if (!probe_disk(d))
- return -ENODEV;
- return 0;
-}
-
-static int viodasd_remove(struct vio_dev *vdev)
-{
- struct viodasd_device *d;
-
- d = &viodasd_devices[vdev->unit_address];
- if (d->disk) {
- del_gendisk(d->disk);
- blk_cleanup_queue(d->disk->queue);
- put_disk(d->disk);
- d->disk = NULL;
- }
- d->dev = NULL;
- return 0;
-}
-
-/**
- * viodasd_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viodasd_device_table[] __devinitdata = {
- { "block", "IBM,iSeries-viodasd" },
- { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viodasd_device_table);
-
-static struct vio_driver viodasd_driver = {
- .id_table = viodasd_device_table,
- .probe = viodasd_probe,
- .remove = viodasd_remove,
- .driver = {
- .name = "viodasd",
- .owner = THIS_MODULE,
- }
-};
-
-static int need_delete_probe;
-
-/*
- * Initialize the whole device driver. Handle module and non-module
- * versions
- */
-static int __init viodasd_init(void)
-{
- int rc;
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES)) {
- rc = -ENODEV;
- goto early_fail;
- }
-
- /* Try to open to our host lp */
- if (viopath_hostLp == HvLpIndexInvalid)
- vio_set_hostlp();
-
- if (viopath_hostLp == HvLpIndexInvalid) {
- pr_warning("invalid hosting partition\n");
- rc = -EIO;
- goto early_fail;
- }
-
- pr_info("vers " VIOD_VERS ", hosting partition %d\n", viopath_hostLp);
-
- /* register the block device */
- rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
- if (rc) {
- pr_warning("Unable to get major number %d for %s\n",
- VIODASD_MAJOR, VIOD_GENHD_NAME);
- goto early_fail;
- }
- /* Actually open the path to the hosting partition */
- rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio,
- VIOMAXREQ + 2);
- if (rc) {
- pr_warning("error opening path to host partition %d\n",
- viopath_hostLp);
- goto unregister_blk;
- }
-
- /* Initialize our request handler */
- vio_setHandler(viomajorsubtype_blockio, handle_block_event);
-
- rc = vio_register_driver(&viodasd_driver);
- if (rc) {
- pr_warning("vio_register_driver failed\n");
- goto unset_handler;
- }
-
- /*
- * If this call fails, it just means that we cannot dynamically
- * add virtual disks, but the driver will still work fine for
- * all existing disk, so ignore the failure.
- */
- if (!driver_create_file(&viodasd_driver.driver, &driver_attr_probe))
- need_delete_probe = 1;
-
- return 0;
-
-unset_handler:
- vio_clearHandler(viomajorsubtype_blockio);
- viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
-unregister_blk:
- unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
-early_fail:
- return rc;
-}
-module_init(viodasd_init);
-
-void __exit viodasd_exit(void)
-{
- if (need_delete_probe)
- driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
- vio_unregister_driver(&viodasd_driver);
- vio_clearHandler(viomajorsubtype_blockio);
- viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
- unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
-}
-module_exit(viodasd_exit);
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
deleted file mode 100644
index 7878da89d29e..000000000000
--- a/drivers/cdrom/viocd.c
+++ /dev/null
@@ -1,739 +0,0 @@
-/* -*- linux-c -*-
- * drivers/cdrom/viocd.c
- *
- * iSeries Virtual CD Rom
- *
- * Authors: Dave Boutcher <boutcher@us.ibm.com>
- * Ryan Arnold <ryanarn@us.ibm.com>
- * Colin Devilbiss <devilbis@us.ibm.com>
- * Stephen Rothwell
- *
- * (C) Copyright 2000-2004 IBM Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) anyu 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 routine provides access to CD ROM drives owned and managed by an
- * OS/400 partition running on the same box as this Linux partition.
- *
- * All operations are performed by sending messages back and forth to
- * the OS/400 partition.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/major.h>
-#include <linux/blkdev.h>
-#include <linux/cdrom.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/mutex.h>
-#include <linux/seq_file.h>
-#include <linux/scatterlist.h>
-
-#include <asm/vio.h>
-#include <asm/iseries/hv_types.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/vio.h>
-#include <asm/firmware.h>
-
-#define VIOCD_DEVICE "iseries/vcd"
-
-#define VIOCD_VERS "1.06"
-
-/*
- * Should probably make this a module parameter....sigh
- */
-#define VIOCD_MAX_CD HVMAXARCHITECTEDVIRTUALCDROMS
-
-static DEFINE_MUTEX(viocd_mutex);
-static const struct vio_error_entry viocd_err_table[] = {
- {0x0201, EINVAL, "Invalid Range"},
- {0x0202, EINVAL, "Invalid Token"},
- {0x0203, EIO, "DMA Error"},
- {0x0204, EIO, "Use Error"},
- {0x0205, EIO, "Release Error"},
- {0x0206, EINVAL, "Invalid CD"},
- {0x020C, EROFS, "Read Only Device"},
- {0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"},
- {0x020E, EIO, "Optical System Error (Varied Off?)"},
- {0x02FF, EIO, "Internal Error"},
- {0x3010, EIO, "Changed Volume"},
- {0xC100, EIO, "Optical System Error"},
- {0x0000, 0, NULL},
-};
-
-/*
- * This is the structure we use to exchange info between driver and interrupt
- * handler
- */
-struct viocd_waitevent {
- struct completion com;
- int rc;
- u16 sub_result;
- int changed;
-};
-
-/* this is a lookup table for the true capabilities of a device */
-struct capability_entry {
- char *type;
- int capability;
-};
-
-static struct capability_entry capability_table[] __initdata = {
- { "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
- { "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
- { "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
- { "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM },
- { "6321", CDC_LOCK },
- { "632B", 0 },
- { NULL , CDC_LOCK },
-};
-
-/* These are our internal structures for keeping track of devices */
-static int viocd_numdev;
-
-struct disk_info {
- struct gendisk *viocd_disk;
- struct cdrom_device_info viocd_info;
- struct device *dev;
- const char *rsrcname;
- const char *type;
- const char *model;
-};
-static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
-
-#define DEVICE_NR(di) ((di) - &viocd_diskinfo[0])
-
-static spinlock_t viocd_reqlock;
-
-#define MAX_CD_REQ 1
-
-/* procfs support */
-static int proc_viocd_show(struct seq_file *m, void *v)
-{
- int i;
-
- for (i = 0; i < viocd_numdev; i++) {
- seq_printf(m, "viocd device %d is iSeries resource %10.10s"
- "type %4.4s, model %3.3s\n",
- i, viocd_diskinfo[i].rsrcname,
- viocd_diskinfo[i].type,
- viocd_diskinfo[i].model);
- }
- return 0;
-}
-
-static int proc_viocd_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_viocd_show, NULL);
-}
-
-static const struct file_operations proc_viocd_operations = {
- .owner = THIS_MODULE,
- .open = proc_viocd_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int viocd_blk_open(struct block_device *bdev, fmode_t mode)
-{
- struct disk_info *di = bdev->bd_disk->private_data;
- int ret;
-
- mutex_lock(&viocd_mutex);
- ret = cdrom_open(&di->viocd_info, bdev, mode);
- mutex_unlock(&viocd_mutex);
-
- return ret;
-}
-
-static int viocd_blk_release(struct gendisk *disk, fmode_t mode)
-{
- struct disk_info *di = disk->private_data;
- mutex_lock(&viocd_mutex);
- cdrom_release(&di->viocd_info, mode);
- mutex_unlock(&viocd_mutex);
- return 0;
-}
-
-static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned cmd, unsigned long arg)
-{
- struct disk_info *di = bdev->bd_disk->private_data;
- int ret;
-
- mutex_lock(&viocd_mutex);
- ret = cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg);
- mutex_unlock(&viocd_mutex);
-
- return ret;
-}
-
-static unsigned int viocd_blk_check_events(struct gendisk *disk,
- unsigned int clearing)
-{
- struct disk_info *di = disk->private_data;
- return cdrom_check_events(&di->viocd_info, clearing);
-}
-
-static const struct block_device_operations viocd_fops = {
- .owner = THIS_MODULE,
- .open = viocd_blk_open,
- .release = viocd_blk_release,
- .ioctl = viocd_blk_ioctl,
- .check_events = viocd_blk_check_events,
-};
-
-static int viocd_open(struct cdrom_device_info *cdi, int purpose)
-{
- struct disk_info *diskinfo = cdi->handle;
- int device_no = DEVICE_NR(diskinfo);
- HvLpEvent_Rc hvrc;
- struct viocd_waitevent we;
-
- init_completion(&we.com);
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_cdio | viocdopen,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)&we, VIOVERSION << 16, ((u64)device_no << 48),
- 0, 0, 0);
- if (hvrc != 0) {
- pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
- (int)hvrc);
- return -EIO;
- }
-
- wait_for_completion(&we.com);
-
- if (we.rc) {
- const struct vio_error_entry *err =
- vio_lookup_rc(viocd_err_table, we.sub_result);
- pr_warning("bad rc %d:0x%04X on open: %s\n",
- we.rc, we.sub_result, err->msg);
- return -err->errno;
- }
-
- return 0;
-}
-
-static void viocd_release(struct cdrom_device_info *cdi)
-{
- int device_no = DEVICE_NR((struct disk_info *)cdi->handle);
- HvLpEvent_Rc hvrc;
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_cdio | viocdclose,
- HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp), 0,
- VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0);
- if (hvrc != 0)
- pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
- (int)hvrc);
-}
-
-/* Send a read or write request to OS/400 */
-static int send_request(struct request *req)
-{
- HvLpEvent_Rc hvrc;
- struct disk_info *diskinfo = req->rq_disk->private_data;
- u64 len;
- dma_addr_t dmaaddr;
- int direction;
- u16 cmd;
- struct scatterlist sg;
-
- BUG_ON(req->nr_phys_segments > 1);
-
- if (rq_data_dir(req) == READ) {
- direction = DMA_FROM_DEVICE;
- cmd = viomajorsubtype_cdio | viocdread;
- } else {
- direction = DMA_TO_DEVICE;
- cmd = viomajorsubtype_cdio | viocdwrite;
- }
-
- sg_init_table(&sg, 1);
- if (blk_rq_map_sg(req->q, req, &sg) == 0) {
- pr_warning("error setting up scatter/gather list\n");
- return -1;
- }
-
- if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) {
- pr_warning("error allocating sg tce\n");
- return -1;
- }
- dmaaddr = sg_dma_address(&sg);
- len = sg_dma_len(&sg);
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo, cmd,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)req, VIOVERSION << 16,
- ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr,
- (u64)blk_rq_pos(req) * 512, len, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- pr_warning("hv error on op %d\n", (int)hvrc);
- return -1;
- }
-
- return 0;
-}
-
-static int rwreq;
-
-static void do_viocd_request(struct request_queue *q)
-{
- struct request *req;
-
- while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) {
- if (req->cmd_type != REQ_TYPE_FS)
- __blk_end_request_all(req, -EIO);
- else if (send_request(req) < 0) {
- pr_warning("unable to send message to OS/400!\n");
- __blk_end_request_all(req, -EIO);
- } else
- rwreq++;
- }
-}
-
-static unsigned int viocd_check_events(struct cdrom_device_info *cdi,
- unsigned int clearing, int disc_nr)
-{
- struct viocd_waitevent we;
- HvLpEvent_Rc hvrc;
- int device_no = DEVICE_NR((struct disk_info *)cdi->handle);
-
- init_completion(&we.com);
-
- /* Send the open event to OS/400 */
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_cdio | viocdcheck,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)&we, VIOVERSION << 16, ((u64)device_no << 48),
- 0, 0, 0);
- if (hvrc != 0) {
- pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
- (int)hvrc);
- return 0;
- }
-
- wait_for_completion(&we.com);
-
- /* Check the return code. If bad, assume no change */
- if (we.rc) {
- const struct vio_error_entry *err =
- vio_lookup_rc(viocd_err_table, we.sub_result);
- pr_warning("bad rc %d:0x%04X on check_change: %s; Assuming no change\n",
- we.rc, we.sub_result, err->msg);
- return 0;
- }
-
- return we.changed ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-static int viocd_lock_door(struct cdrom_device_info *cdi, int locking)
-{
- HvLpEvent_Rc hvrc;
- u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle);
- /* NOTE: flags is 1 or 0 so it won't overwrite the device_no */
- u64 flags = !!locking;
- struct viocd_waitevent we;
-
- init_completion(&we.com);
-
- /* Send the lockdoor event to OS/400 */
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_cdio | viocdlockdoor,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)&we, VIOVERSION << 16,
- (device_no << 48) | (flags << 32), 0, 0, 0);
- if (hvrc != 0) {
- pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n",
- (int)hvrc);
- return -EIO;
- }
-
- wait_for_completion(&we.com);
-
- if (we.rc != 0)
- return -EIO;
- return 0;
-}
-
-static int viocd_packet(struct cdrom_device_info *cdi,
- struct packet_command *cgc)
-{
- unsigned int buflen = cgc->buflen;
- int ret = -EIO;
-
- switch (cgc->cmd[0]) {
- case GPCMD_READ_DISC_INFO:
- {
- disc_information *di = (disc_information *)cgc->buffer;
-
- if (buflen >= 2) {
- di->disc_information_length = cpu_to_be16(1);
- ret = 0;
- }
- if (buflen >= 3)
- di->erasable =
- (cdi->ops->capability & ~cdi->mask
- & (CDC_DVD_RAM | CDC_RAM)) != 0;
- }
- break;
- case GPCMD_GET_CONFIGURATION:
- if (cgc->cmd[3] == CDF_RWRT) {
- struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header));
-
- if ((buflen >=
- (sizeof(struct feature_header) + sizeof(*rfd))) &&
- (cdi->ops->capability & ~cdi->mask
- & (CDC_DVD_RAM | CDC_RAM))) {
- rfd->feature_code = cpu_to_be16(CDF_RWRT);
- rfd->curr = 1;
- ret = 0;
- }
- }
- break;
- default:
- if (cgc->sense) {
- /* indicate Unknown code */
- cgc->sense->sense_key = 0x05;
- cgc->sense->asc = 0x20;
- cgc->sense->ascq = 0x00;
- }
- break;
- }
-
- cgc->stat = ret;
- return ret;
-}
-
-static void restart_all_queues(int first_index)
-{
- int i;
-
- for (i = first_index + 1; i < viocd_numdev; i++)
- if (viocd_diskinfo[i].viocd_disk)
- blk_run_queue(viocd_diskinfo[i].viocd_disk->queue);
- for (i = 0; i <= first_index; i++)
- if (viocd_diskinfo[i].viocd_disk)
- blk_run_queue(viocd_diskinfo[i].viocd_disk->queue);
-}
-
-/* This routine handles incoming CD LP events */
-static void vio_handle_cd_event(struct HvLpEvent *event)
-{
- struct viocdlpevent *bevent;
- struct viocd_waitevent *pwe;
- struct disk_info *di;
- unsigned long flags;
- struct request *req;
-
-
- if (event == NULL)
- /* Notification that a partition went away! */
- return;
- /* First, we should NEVER get an int here...only acks */
- if (hvlpevent_is_int(event)) {
- pr_warning("Yikes! got an int in viocd event handler!\n");
- if (hvlpevent_need_ack(event)) {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
-
- bevent = (struct viocdlpevent *)event;
-
- switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
- case viocdopen:
- if (event->xRc == 0) {
- di = &viocd_diskinfo[bevent->disk];
- blk_queue_logical_block_size(di->viocd_disk->queue,
- bevent->block_size);
- set_capacity(di->viocd_disk,
- bevent->media_size *
- bevent->block_size / 512);
- }
- /* FALLTHROUGH !! */
- case viocdlockdoor:
- pwe = (struct viocd_waitevent *)event->xCorrelationToken;
-return_complete:
- pwe->rc = event->xRc;
- pwe->sub_result = bevent->sub_result;
- complete(&pwe->com);
- break;
-
- case viocdcheck:
- pwe = (struct viocd_waitevent *)event->xCorrelationToken;
- pwe->changed = bevent->flags;
- goto return_complete;
-
- case viocdclose:
- break;
-
- case viocdwrite:
- case viocdread:
- /*
- * Since this is running in interrupt mode, we need to
- * make sure we're not stepping on any global I/O operations
- */
- di = &viocd_diskinfo[bevent->disk];
- spin_lock_irqsave(&viocd_reqlock, flags);
- dma_unmap_single(di->dev, bevent->token, bevent->len,
- ((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread)
- ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- req = (struct request *)bevent->event.xCorrelationToken;
- rwreq--;
-
- if (event->xRc != HvLpEvent_Rc_Good) {
- const struct vio_error_entry *err =
- vio_lookup_rc(viocd_err_table,
- bevent->sub_result);
- pr_warning("request %p failed with rc %d:0x%04X: %s\n",
- req, event->xRc,
- bevent->sub_result, err->msg);
- __blk_end_request_all(req, -EIO);
- } else
- __blk_end_request_all(req, 0);
-
- /* restart handling of incoming requests */
- spin_unlock_irqrestore(&viocd_reqlock, flags);
- restart_all_queues(bevent->disk);
- break;
-
- default:
- pr_warning("message with invalid subtype %0x04X!\n",
- event->xSubtype & VIOMINOR_SUBTYPE_MASK);
- if (hvlpevent_need_ack(event)) {
- event->xRc = HvLpEvent_Rc_InvalidSubtype;
- HvCallEvent_ackLpEvent(event);
- }
- }
-}
-
-static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
- void *arg)
-{
- return -EINVAL;
-}
-
-static struct cdrom_device_ops viocd_dops = {
- .open = viocd_open,
- .release = viocd_release,
- .check_events = viocd_check_events,
- .lock_door = viocd_lock_door,
- .generic_packet = viocd_packet,
- .audio_ioctl = viocd_audio_ioctl,
- .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
-};
-
-static int find_capability(const char *type)
-{
- struct capability_entry *entry;
-
- for(entry = capability_table; entry->type; ++entry)
- if(!strncmp(entry->type, type, 4))
- break;
- return entry->capability;
-}
-
-static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
- struct gendisk *gendisk;
- int deviceno;
- struct disk_info *d;
- struct cdrom_device_info *c;
- struct request_queue *q;
- struct device_node *node = vdev->dev.of_node;
-
- deviceno = vdev->unit_address;
- if (deviceno >= VIOCD_MAX_CD)
- return -ENODEV;
- if (!node)
- return -ENODEV;
-
- if (deviceno >= viocd_numdev)
- viocd_numdev = deviceno + 1;
-
- d = &viocd_diskinfo[deviceno];
- d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);
- d->type = of_get_property(node, "linux,vio_type", NULL);
- d->model = of_get_property(node, "linux,vio_model", NULL);
-
- c = &d->viocd_info;
-
- c->ops = &viocd_dops;
- c->speed = 4;
- c->capacity = 1;
- c->handle = d;
- c->mask = ~find_capability(d->type);
- sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
-
- if (register_cdrom(c) != 0) {
- pr_warning("Cannot register viocd CD-ROM %s!\n", c->name);
- goto out;
- }
- pr_info("cd %s is iSeries resource %10.10s type %4.4s, model %3.3s\n",
- c->name, d->rsrcname, d->type, d->model);
- q = blk_init_queue(do_viocd_request, &viocd_reqlock);
- if (q == NULL) {
- pr_warning("Cannot allocate queue for %s!\n", c->name);
- goto out_unregister_cdrom;
- }
- gendisk = alloc_disk(1);
- if (gendisk == NULL) {
- pr_warning("Cannot create gendisk for %s!\n", c->name);
- goto out_cleanup_queue;
- }
- gendisk->major = VIOCD_MAJOR;
- gendisk->first_minor = deviceno;
- strncpy(gendisk->disk_name, c->name,
- sizeof(gendisk->disk_name));
- blk_queue_max_segments(q, 1);
- blk_queue_max_hw_sectors(q, 4096 / 512);
- gendisk->queue = q;
- gendisk->fops = &viocd_fops;
- gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
- GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
- set_capacity(gendisk, 0);
- gendisk->private_data = d;
- d->viocd_disk = gendisk;
- d->dev = &vdev->dev;
- gendisk->driverfs_dev = d->dev;
- add_disk(gendisk);
- return 0;
-
-out_cleanup_queue:
- blk_cleanup_queue(q);
-out_unregister_cdrom:
- unregister_cdrom(c);
-out:
- return -ENODEV;
-}
-
-static int viocd_remove(struct vio_dev *vdev)
-{
- struct disk_info *d = &viocd_diskinfo[vdev->unit_address];
-
- unregister_cdrom(&d->viocd_info);
- del_gendisk(d->viocd_disk);
- blk_cleanup_queue(d->viocd_disk->queue);
- put_disk(d->viocd_disk);
- return 0;
-}
-
-/**
- * viocd_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viocd_device_table[] __devinitdata = {
- { "block", "IBM,iSeries-viocd" },
- { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viocd_device_table);
-
-static struct vio_driver viocd_driver = {
- .id_table = viocd_device_table,
- .probe = viocd_probe,
- .remove = viocd_remove,
- .driver = {
- .name = "viocd",
- .owner = THIS_MODULE,
- }
-};
-
-static int __init viocd_init(void)
-{
- int ret = 0;
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- return -ENODEV;
-
- if (viopath_hostLp == HvLpIndexInvalid) {
- vio_set_hostlp();
- /* If we don't have a host, bail out */
- if (viopath_hostLp == HvLpIndexInvalid)
- return -ENODEV;
- }
-
- pr_info("vers " VIOCD_VERS ", hosting partition %d\n", viopath_hostLp);
-
- if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) {
- pr_warning("Unable to get major %d for %s\n",
- VIOCD_MAJOR, VIOCD_DEVICE);
- return -EIO;
- }
-
- ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio,
- MAX_CD_REQ + 2);
- if (ret) {
- pr_warning("error opening path to host partition %d\n",
- viopath_hostLp);
- goto out_unregister;
- }
-
- /* Initialize our request handler */
- vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
-
- spin_lock_init(&viocd_reqlock);
-
- ret = vio_register_driver(&viocd_driver);
- if (ret)
- goto out_free_info;
-
- proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL,
- &proc_viocd_operations);
- return 0;
-
-out_free_info:
- vio_clearHandler(viomajorsubtype_cdio);
- viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
-out_unregister:
- unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
- return ret;
-}
-
-static void __exit viocd_exit(void)
-{
- remove_proc_entry("iSeries/viocd", NULL);
- vio_unregister_driver(&viocd_driver);
- viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
- vio_clearHandler(viomajorsubtype_cdio);
- unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
-}
-
-module_init(viocd_init);
-module_exit(viocd_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
deleted file mode 100644
index ad6e64a2912d..000000000000
--- a/drivers/char/viotape.c
+++ /dev/null
@@ -1,1041 +0,0 @@
-/* -*- linux-c -*-
- * drivers/char/viotape.c
- *
- * iSeries Virtual Tape
- *
- * Authors: Dave Boutcher <boutcher@us.ibm.com>
- * Ryan Arnold <ryanarn@us.ibm.com>
- * Colin Devilbiss <devilbis@us.ibm.com>
- * Stephen Rothwell
- *
- * (C) Copyright 2000-2004 IBM Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) anyu 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 routine provides access to tape drives owned and managed by an OS/400
- * partition running on the same box as this Linux partition.
- *
- * All tape operations are performed by sending messages back and forth to
- * the OS/400 partition. The format of the messages is defined in
- * iseries/vio.h
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/spinlock.h>
-#include <linux/mtio.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/major.h>
-#include <linux/completion.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <asm/uaccess.h>
-#include <asm/ioctls.h>
-#include <asm/firmware.h>
-#include <asm/vio.h>
-#include <asm/iseries/vio.h>
-#include <asm/iseries/hv_lp_event.h>
-#include <asm/iseries/hv_call_event.h>
-#include <asm/iseries/hv_lp_config.h>
-
-#define VIOTAPE_VERSION "1.2"
-#define VIOTAPE_MAXREQ 1
-
-#define VIOTAPE_KERN_WARN KERN_WARNING "viotape: "
-#define VIOTAPE_KERN_INFO KERN_INFO "viotape: "
-
-static DEFINE_MUTEX(proc_viotape_mutex);
-static int viotape_numdev;
-
-/*
- * The minor number follows the conventions of the SCSI tape drives. The
- * rewind and mode are encoded in the minor #. We use this struct to break
- * them out
- */
-struct viot_devinfo_struct {
- int devno;
- int mode;
- int rewind;
-};
-
-#define VIOTAPOP_RESET 0
-#define VIOTAPOP_FSF 1
-#define VIOTAPOP_BSF 2
-#define VIOTAPOP_FSR 3
-#define VIOTAPOP_BSR 4
-#define VIOTAPOP_WEOF 5
-#define VIOTAPOP_REW 6
-#define VIOTAPOP_NOP 7
-#define VIOTAPOP_EOM 8
-#define VIOTAPOP_ERASE 9
-#define VIOTAPOP_SETBLK 10
-#define VIOTAPOP_SETDENSITY 11
-#define VIOTAPOP_SETPOS 12
-#define VIOTAPOP_GETPOS 13
-#define VIOTAPOP_SETPART 14
-#define VIOTAPOP_UNLOAD 15
-
-enum viotaperc {
- viotape_InvalidRange = 0x0601,
- viotape_InvalidToken = 0x0602,
- viotape_DMAError = 0x0603,
- viotape_UseError = 0x0604,
- viotape_ReleaseError = 0x0605,
- viotape_InvalidTape = 0x0606,
- viotape_InvalidOp = 0x0607,
- viotape_TapeErr = 0x0608,
-
- viotape_AllocTimedOut = 0x0640,
- viotape_BOTEnc = 0x0641,
- viotape_BlankTape = 0x0642,
- viotape_BufferEmpty = 0x0643,
- viotape_CleanCartFound = 0x0644,
- viotape_CmdNotAllowed = 0x0645,
- viotape_CmdNotSupported = 0x0646,
- viotape_DataCheck = 0x0647,
- viotape_DecompressErr = 0x0648,
- viotape_DeviceTimeout = 0x0649,
- viotape_DeviceUnavail = 0x064a,
- viotape_DeviceBusy = 0x064b,
- viotape_EndOfMedia = 0x064c,
- viotape_EndOfTape = 0x064d,
- viotape_EquipCheck = 0x064e,
- viotape_InsufficientRs = 0x064f,
- viotape_InvalidLogBlk = 0x0650,
- viotape_LengthError = 0x0651,
- viotape_LibDoorOpen = 0x0652,
- viotape_LoadFailure = 0x0653,
- viotape_NotCapable = 0x0654,
- viotape_NotOperational = 0x0655,
- viotape_NotReady = 0x0656,
- viotape_OpCancelled = 0x0657,
- viotape_PhyLinkErr = 0x0658,
- viotape_RdyNotBOT = 0x0659,
- viotape_TapeMark = 0x065a,
- viotape_WriteProt = 0x065b
-};
-
-static const struct vio_error_entry viotape_err_table[] = {
- { viotape_InvalidRange, EIO, "Internal error" },
- { viotape_InvalidToken, EIO, "Internal error" },
- { viotape_DMAError, EIO, "DMA error" },
- { viotape_UseError, EIO, "Internal error" },
- { viotape_ReleaseError, EIO, "Internal error" },
- { viotape_InvalidTape, EIO, "Invalid tape device" },
- { viotape_InvalidOp, EIO, "Invalid operation" },
- { viotape_TapeErr, EIO, "Tape error" },
- { viotape_AllocTimedOut, EBUSY, "Allocate timed out" },
- { viotape_BOTEnc, EIO, "Beginning of tape encountered" },
- { viotape_BlankTape, EIO, "Blank tape" },
- { viotape_BufferEmpty, EIO, "Buffer empty" },
- { viotape_CleanCartFound, ENOMEDIUM, "Cleaning cartridge found" },
- { viotape_CmdNotAllowed, EIO, "Command not allowed" },
- { viotape_CmdNotSupported, EIO, "Command not supported" },
- { viotape_DataCheck, EIO, "Data check" },
- { viotape_DecompressErr, EIO, "Decompression error" },
- { viotape_DeviceTimeout, EBUSY, "Device timeout" },
- { viotape_DeviceUnavail, EIO, "Device unavailable" },
- { viotape_DeviceBusy, EBUSY, "Device busy" },
- { viotape_EndOfMedia, ENOSPC, "End of media" },
- { viotape_EndOfTape, ENOSPC, "End of tape" },
- { viotape_EquipCheck, EIO, "Equipment check" },
- { viotape_InsufficientRs, EOVERFLOW, "Insufficient tape resources" },
- { viotape_InvalidLogBlk, EIO, "Invalid logical block location" },
- { viotape_LengthError, EOVERFLOW, "Length error" },
- { viotape_LibDoorOpen, EBUSY, "Door open" },
- { viotape_LoadFailure, ENOMEDIUM, "Load failure" },
- { viotape_NotCapable, EIO, "Not capable" },
- { viotape_NotOperational, EIO, "Not operational" },
- { viotape_NotReady, EIO, "Not ready" },
- { viotape_OpCancelled, EIO, "Operation cancelled" },
- { viotape_PhyLinkErr, EIO, "Physical link error" },
- { viotape_RdyNotBOT, EIO, "Ready but not beginning of tape" },
- { viotape_TapeMark, EIO, "Tape mark" },
- { viotape_WriteProt, EROFS, "Write protection error" },
- { 0, 0, NULL },
-};
-
-/* Maximum number of tapes we support */
-#define VIOTAPE_MAX_TAPE HVMAXARCHITECTEDVIRTUALTAPES
-#define MAX_PARTITIONS 4
-
-/* defines for current tape state */
-#define VIOT_IDLE 0
-#define VIOT_READING 1
-#define VIOT_WRITING 2
-
-/* Our info on the tapes */
-static struct {
- const char *rsrcname;
- const char *type;
- const char *model;
-} viotape_unitinfo[VIOTAPE_MAX_TAPE];
-
-static struct mtget viomtget[VIOTAPE_MAX_TAPE];
-
-static struct class *tape_class;
-
-static struct device *tape_device[VIOTAPE_MAX_TAPE];
-
-/*
- * maintain the current state of each tape (and partition)
- * so that we know when to write EOF marks.
- */
-static struct {
- unsigned char cur_part;
- unsigned char part_stat_rwi[MAX_PARTITIONS];
-} state[VIOTAPE_MAX_TAPE];
-
-/* We single-thread */
-static struct semaphore reqSem;
-
-/*
- * When we send a request, we use this struct to get the response back
- * from the interrupt handler
- */
-struct op_struct {
- void *buffer;
- dma_addr_t dmaaddr;
- size_t count;
- int rc;
- int non_blocking;
- struct completion com;
- struct device *dev;
- struct op_struct *next;
-};
-
-static spinlock_t op_struct_list_lock;
-static struct op_struct *op_struct_list;
-
-/* forward declaration to resolve interdependence */
-static int chg_state(int index, unsigned char new_state, struct file *file);
-
-/* procfs support */
-static int proc_viotape_show(struct seq_file *m, void *v)
-{
- int i;
-
- seq_printf(m, "viotape driver version " VIOTAPE_VERSION "\n");
- for (i = 0; i < viotape_numdev; i++) {
- seq_printf(m, "viotape device %d is iSeries resource %10.10s"
- "type %4.4s, model %3.3s\n",
- i, viotape_unitinfo[i].rsrcname,
- viotape_unitinfo[i].type,
- viotape_unitinfo[i].model);
- }
- return 0;
-}
-
-static int proc_viotape_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_viotape_show, NULL);
-}
-
-static const struct file_operations proc_viotape_operations = {
- .owner = THIS_MODULE,
- .open = proc_viotape_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/* Decode the device minor number into its parts */
-void get_dev_info(struct inode *ino, struct viot_devinfo_struct *devi)
-{
- devi->devno = iminor(ino) & 0x1F;
- devi->mode = (iminor(ino) & 0x60) >> 5;
- /* if bit is set in the minor, do _not_ rewind automatically */
- devi->rewind = (iminor(ino) & 0x80) == 0;
-}
-
-/* This is called only from the exit and init paths, so no need for locking */
-static void clear_op_struct_pool(void)
-{
- while (op_struct_list) {
- struct op_struct *toFree = op_struct_list;
- op_struct_list = op_struct_list->next;
- kfree(toFree);
- }
-}
-
-/* Likewise, this is only called from the init path */
-static int add_op_structs(int structs)
-{
- int i;
-
- for (i = 0; i < structs; ++i) {
- struct op_struct *new_struct =
- kmalloc(sizeof(*new_struct), GFP_KERNEL);
- if (!new_struct) {
- clear_op_struct_pool();
- return -ENOMEM;
- }
- new_struct->next = op_struct_list;
- op_struct_list = new_struct;
- }
- return 0;
-}
-
-/* Allocate an op structure from our pool */
-static struct op_struct *get_op_struct(void)
-{
- struct op_struct *retval;
- unsigned long flags;
-
- spin_lock_irqsave(&op_struct_list_lock, flags);
- retval = op_struct_list;
- if (retval)
- op_struct_list = retval->next;
- spin_unlock_irqrestore(&op_struct_list_lock, flags);
- if (retval) {
- memset(retval, 0, sizeof(*retval));
- init_completion(&retval->com);
- }
-
- return retval;
-}
-
-/* Return an op structure to our pool */
-static void free_op_struct(struct op_struct *op_struct)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&op_struct_list_lock, flags);
- op_struct->next = op_struct_list;
- op_struct_list = op_struct;
- spin_unlock_irqrestore(&op_struct_list_lock, flags);
-}
-
-/* Map our tape return codes to errno values */
-int tape_rc_to_errno(int tape_rc, char *operation, int tapeno)
-{
- const struct vio_error_entry *err;
-
- if (tape_rc == 0)
- return 0;
-
- err = vio_lookup_rc(viotape_err_table, tape_rc);
- printk(VIOTAPE_KERN_WARN "error(%s) 0x%04x on Device %d (%-10s): %s\n",
- operation, tape_rc, tapeno,
- viotape_unitinfo[tapeno].rsrcname, err->msg);
- return -err->errno;
-}
-
-/* Write */
-static ssize_t viotap_write(struct file *file, const char *buf,
- size_t count, loff_t * ppos)
-{
- HvLpEvent_Rc hvrc;
- unsigned short flags = file->f_flags;
- int noblock = ((flags & O_NONBLOCK) != 0);
- ssize_t ret;
- struct viot_devinfo_struct devi;
- struct op_struct *op = get_op_struct();
-
- if (op == NULL)
- return -ENOMEM;
-
- get_dev_info(file->f_path.dentry->d_inode, &devi);
-
- /*
- * We need to make sure we can send a request. We use
- * a semaphore to keep track of # requests in use. If
- * we are non-blocking, make sure we don't block on the
- * semaphore
- */
- if (noblock) {
- if (down_trylock(&reqSem)) {
- ret = -EWOULDBLOCK;
- goto free_op;
- }
- } else
- down(&reqSem);
-
- /* Allocate a DMA buffer */
- op->dev = tape_device[devi.devno];
- op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr,
- GFP_ATOMIC);
-
- if (op->buffer == NULL) {
- printk(VIOTAPE_KERN_WARN
- "error allocating dma buffer for len %ld\n",
- count);
- ret = -EFAULT;
- goto up_sem;
- }
-
- /* Copy the data into the buffer */
- if (copy_from_user(op->buffer, buf, count)) {
- printk(VIOTAPE_KERN_WARN "tape: error on copy from user\n");
- ret = -EFAULT;
- goto free_dma;
- }
-
- op->non_blocking = noblock;
- init_completion(&op->com);
- op->count = count;
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotapewrite,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)op, VIOVERSION << 16,
- ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
- (int)hvrc);
- ret = -EIO;
- goto free_dma;
- }
-
- if (noblock)
- return count;
-
- wait_for_completion(&op->com);
-
- if (op->rc)
- ret = tape_rc_to_errno(op->rc, "write", devi.devno);
- else {
- chg_state(devi.devno, VIOT_WRITING, file);
- ret = op->count;
- }
-
-free_dma:
- dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);
-up_sem:
- up(&reqSem);
-free_op:
- free_op_struct(op);
- return ret;
-}
-
-/* read */
-static ssize_t viotap_read(struct file *file, char *buf, size_t count,
- loff_t *ptr)
-{
- HvLpEvent_Rc hvrc;
- unsigned short flags = file->f_flags;
- struct op_struct *op = get_op_struct();
- int noblock = ((flags & O_NONBLOCK) != 0);
- ssize_t ret;
- struct viot_devinfo_struct devi;
-
- if (op == NULL)
- return -ENOMEM;
-
- get_dev_info(file->f_path.dentry->d_inode, &devi);
-
- /*
- * We need to make sure we can send a request. We use
- * a semaphore to keep track of # requests in use. If
- * we are non-blocking, make sure we don't block on the
- * semaphore
- */
- if (noblock) {
- if (down_trylock(&reqSem)) {
- ret = -EWOULDBLOCK;
- goto free_op;
- }
- } else
- down(&reqSem);
-
- chg_state(devi.devno, VIOT_READING, file);
-
- /* Allocate a DMA buffer */
- op->dev = tape_device[devi.devno];
- op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr,
- GFP_ATOMIC);
- if (op->buffer == NULL) {
- ret = -EFAULT;
- goto up_sem;
- }
-
- op->count = count;
- init_completion(&op->com);
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotaperead,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)op, VIOVERSION << 16,
- ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOTAPE_KERN_WARN "tape hv error on op %d\n",
- (int)hvrc);
- ret = -EIO;
- goto free_dma;
- }
-
- wait_for_completion(&op->com);
-
- if (op->rc)
- ret = tape_rc_to_errno(op->rc, "read", devi.devno);
- else {
- ret = op->count;
- if (ret && copy_to_user(buf, op->buffer, ret)) {
- printk(VIOTAPE_KERN_WARN "error on copy_to_user\n");
- ret = -EFAULT;
- }
- }
-
-free_dma:
- dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr);
-up_sem:
- up(&reqSem);
-free_op:
- free_op_struct(op);
- return ret;
-}
-
-/* ioctl */
-static int viotap_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- HvLpEvent_Rc hvrc;
- int ret;
- struct viot_devinfo_struct devi;
- struct mtop mtc;
- u32 myOp;
- struct op_struct *op = get_op_struct();
-
- if (op == NULL)
- return -ENOMEM;
-
- get_dev_info(file->f_path.dentry->d_inode, &devi);
-
- down(&reqSem);
-
- ret = -EINVAL;
-
- switch (cmd) {
- case MTIOCTOP:
- ret = -EFAULT;
- /*
- * inode is null if and only if we (the kernel)
- * made the request
- */
- if (inode == NULL)
- memcpy(&mtc, (void *) arg, sizeof(struct mtop));
- else if (copy_from_user((char *)&mtc, (char *)arg,
- sizeof(struct mtop)))
- goto free_op;
-
- ret = -EIO;
- switch (mtc.mt_op) {
- case MTRESET:
- myOp = VIOTAPOP_RESET;
- break;
- case MTFSF:
- myOp = VIOTAPOP_FSF;
- break;
- case MTBSF:
- myOp = VIOTAPOP_BSF;
- break;
- case MTFSR:
- myOp = VIOTAPOP_FSR;
- break;
- case MTBSR:
- myOp = VIOTAPOP_BSR;
- break;
- case MTWEOF:
- myOp = VIOTAPOP_WEOF;
- break;
- case MTREW:
- myOp = VIOTAPOP_REW;
- break;
- case MTNOP:
- myOp = VIOTAPOP_NOP;
- break;
- case MTEOM:
- myOp = VIOTAPOP_EOM;
- break;
- case MTERASE:
- myOp = VIOTAPOP_ERASE;
- break;
- case MTSETBLK:
- myOp = VIOTAPOP_SETBLK;
- break;
- case MTSETDENSITY:
- myOp = VIOTAPOP_SETDENSITY;
- break;
- case MTTELL:
- myOp = VIOTAPOP_GETPOS;
- break;
- case MTSEEK:
- myOp = VIOTAPOP_SETPOS;
- break;
- case MTSETPART:
- myOp = VIOTAPOP_SETPART;
- break;
- case MTOFFL:
- myOp = VIOTAPOP_UNLOAD;
- break;
- default:
- printk(VIOTAPE_KERN_WARN "MTIOCTOP called "
- "with invalid op 0x%x\n", mtc.mt_op);
- goto free_op;
- }
-
- /*
- * if we moved the head, we are no longer
- * reading or writing
- */
- switch (mtc.mt_op) {
- case MTFSF:
- case MTBSF:
- case MTFSR:
- case MTBSR:
- case MTTELL:
- case MTSEEK:
- case MTREW:
- chg_state(devi.devno, VIOT_IDLE, file);
- }
-
- init_completion(&op->com);
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotapeop,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)op,
- VIOVERSION << 16,
- ((u64)devi.devno << 48), 0,
- (((u64)myOp) << 32) | mtc.mt_count, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
- (int)hvrc);
- goto free_op;
- }
- wait_for_completion(&op->com);
- ret = tape_rc_to_errno(op->rc, "tape operation", devi.devno);
- goto free_op;
-
- case MTIOCGET:
- ret = -EIO;
- init_completion(&op->com);
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotapegetstatus,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)op, VIOVERSION << 16,
- ((u64)devi.devno << 48), 0, 0, 0);
- if (hvrc != HvLpEvent_Rc_Good) {
- printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
- (int)hvrc);
- goto free_op;
- }
- wait_for_completion(&op->com);
-
- /* Operation is complete - grab the error code */
- ret = tape_rc_to_errno(op->rc, "get status", devi.devno);
- free_op_struct(op);
- up(&reqSem);
-
- if ((ret == 0) && copy_to_user((void *)arg,
- &viomtget[devi.devno],
- sizeof(viomtget[0])))
- ret = -EFAULT;
- return ret;
- case MTIOCPOS:
- printk(VIOTAPE_KERN_WARN "Got an (unsupported) MTIOCPOS\n");
- break;
- default:
- printk(VIOTAPE_KERN_WARN "got an unsupported ioctl 0x%0x\n",
- cmd);
- break;
- }
-
-free_op:
- free_op_struct(op);
- up(&reqSem);
- return ret;
-}
-
-static long viotap_unlocked_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- long rc;
-
- mutex_lock(&proc_viotape_mutex);
- rc = viotap_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
- mutex_unlock(&proc_viotape_mutex);
- return rc;
-}
-
-static int viotap_open(struct inode *inode, struct file *file)
-{
- HvLpEvent_Rc hvrc;
- struct viot_devinfo_struct devi;
- int ret;
- struct op_struct *op = get_op_struct();
-
- if (op == NULL)
- return -ENOMEM;
-
- mutex_lock(&proc_viotape_mutex);
- get_dev_info(file->f_path.dentry->d_inode, &devi);
-
- /* Note: We currently only support one mode! */
- if ((devi.devno >= viotape_numdev) || (devi.mode)) {
- ret = -ENODEV;
- goto free_op;
- }
-
- init_completion(&op->com);
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotapeopen,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)op, VIOVERSION << 16,
- ((u64)devi.devno << 48), 0, 0, 0);
- if (hvrc != 0) {
- printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",
- (int) hvrc);
- ret = -EIO;
- goto free_op;
- }
-
- wait_for_completion(&op->com);
- ret = tape_rc_to_errno(op->rc, "open", devi.devno);
-
-free_op:
- free_op_struct(op);
- mutex_unlock(&proc_viotape_mutex);
- return ret;
-}
-
-
-static int viotap_release(struct inode *inode, struct file *file)
-{
- HvLpEvent_Rc hvrc;
- struct viot_devinfo_struct devi;
- int ret = 0;
- struct op_struct *op = get_op_struct();
-
- if (op == NULL)
- return -ENOMEM;
- init_completion(&op->com);
-
- get_dev_info(file->f_path.dentry->d_inode, &devi);
-
- if (devi.devno >= viotape_numdev) {
- ret = -ENODEV;
- goto free_op;
- }
-
- chg_state(devi.devno, VIOT_IDLE, file);
-
- if (devi.rewind) {
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotapeop,
- HvLpEvent_AckInd_DoAck,
- HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)op, VIOVERSION << 16,
- ((u64)devi.devno << 48), 0,
- ((u64)VIOTAPOP_REW) << 32, 0);
- wait_for_completion(&op->com);
-
- tape_rc_to_errno(op->rc, "rewind", devi.devno);
- }
-
- hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
- HvLpEvent_Type_VirtualIo,
- viomajorsubtype_tape | viotapeclose,
- HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
- viopath_sourceinst(viopath_hostLp),
- viopath_targetinst(viopath_hostLp),
- (u64)(unsigned long)op, VIOVERSION << 16,
- ((u64)devi.devno << 48), 0, 0, 0);
- if (hvrc != 0) {
- printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",
- (int) hvrc);
- ret = -EIO;
- goto free_op;
- }
-
- wait_for_completion(&op->com);
-
- if (op->rc)
- printk(VIOTAPE_KERN_WARN "close failed\n");
-
-free_op:
- free_op_struct(op);
- return ret;
-}
-
-const struct file_operations viotap_fops = {
- .owner = THIS_MODULE,
- .read = viotap_read,
- .write = viotap_write,
- .unlocked_ioctl = viotap_unlocked_ioctl,
- .open = viotap_open,
- .release = viotap_release,
- .llseek = noop_llseek,
-};
-
-/* Handle interrupt events for tape */
-static void vioHandleTapeEvent(struct HvLpEvent *event)
-{
- int tapeminor;
- struct op_struct *op;
- struct viotapelpevent *tevent = (struct viotapelpevent *)event;
-
- if (event == NULL) {
- /* Notification that a partition went away! */
- if (!viopath_isactive(viopath_hostLp)) {
- /* TODO! Clean up */
- }
- return;
- }
-
- tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
- op = (struct op_struct *)event->xCorrelationToken;
- switch (tapeminor) {
- case viotapeopen:
- case viotapeclose:
- op->rc = tevent->sub_type_result;
- complete(&op->com);
- break;
- case viotaperead:
- op->rc = tevent->sub_type_result;
- op->count = tevent->len;
- complete(&op->com);
- break;
- case viotapewrite:
- if (op->non_blocking) {
- dma_free_coherent(op->dev, op->count,
- op->buffer, op->dmaaddr);
- free_op_struct(op);
- up(&reqSem);
- } else {
- op->rc = tevent->sub_type_result;
- op->count = tevent->len;
- complete(&op->com);
- }
- break;
- case viotapeop:
- case viotapegetpos:
- case viotapesetpos:
- case viotapegetstatus:
- if (op) {
- op->count = tevent->u.op.count;
- op->rc = tevent->sub_type_result;
- if (!op->non_blocking)
- complete(&op->com);
- }
- break;
- default:
- printk(VIOTAPE_KERN_WARN "weird ack\n");
- }
-}
-
-static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
-{
- int i = vdev->unit_address;
- int j;
- struct device_node *node = vdev->dev.of_node;
-
- if (i >= VIOTAPE_MAX_TAPE)
- return -ENODEV;
- if (!node)
- return -ENODEV;
-
- if (i >= viotape_numdev)
- viotape_numdev = i + 1;
-
- tape_device[i] = &vdev->dev;
- viotape_unitinfo[i].rsrcname = of_get_property(node,
- "linux,vio_rsrcname", NULL);
- viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type",
- NULL);
- viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model",
- NULL);
-
- state[i].cur_part = 0;
- for (j = 0; j < MAX_PARTITIONS; ++j)
- state[i].part_stat_rwi[j] = VIOT_IDLE;
- device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
- "iseries!vt%d", i);
- device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL,
- "iseries!nvt%d", i);
- printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
- "resource %10.10s type %4.4s, model %3.3s\n",
- i, viotape_unitinfo[i].rsrcname,
- viotape_unitinfo[i].type, viotape_unitinfo[i].model);
- return 0;
-}
-
-static int viotape_remove(struct vio_dev *vdev)
-{
- int i = vdev->unit_address;
-
- device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
- device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
- return 0;
-}
-
-/**
- * viotape_device_table: Used by vio.c to match devices that we
- * support.
- */
-static struct vio_device_id viotape_device_table[] __devinitdata = {
- { "byte", "IBM,iSeries-viotape" },
- { "", "" }
-};
-MODULE_DEVICE_TABLE(vio, viotape_device_table);
-
-static struct vio_driver viotape_driver = {
- .id_table = viotape_device_table,
- .probe = viotape_probe,
- .remove = viotape_remove,
- .driver = {
- .name = "viotape",
- .owner = THIS_MODULE,
- }
-};
-
-
-int __init viotap_init(void)
-{
- int ret;
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- return -ENODEV;
-
- op_struct_list = NULL;
- if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) {
- printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n");
- return ret;
- }
- spin_lock_init(&op_struct_list_lock);
-
- sema_init(&reqSem, VIOTAPE_MAXREQ);
-
- if (viopath_hostLp == HvLpIndexInvalid) {
- vio_set_hostlp();
- if (viopath_hostLp == HvLpIndexInvalid) {
- ret = -ENODEV;
- goto clear_op;
- }
- }
-
- ret = viopath_open(viopath_hostLp, viomajorsubtype_tape,
- VIOTAPE_MAXREQ + 2);
- if (ret) {
- printk(VIOTAPE_KERN_WARN
- "error on viopath_open to hostlp %d\n", ret);
- ret = -EIO;
- goto clear_op;
- }
-
- printk(VIOTAPE_KERN_INFO "vers " VIOTAPE_VERSION
- ", hosting partition %d\n", viopath_hostLp);
-
- vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent);
-
- ret = register_chrdev(VIOTAPE_MAJOR, "viotape", &viotap_fops);
- if (ret < 0) {
- printk(VIOTAPE_KERN_WARN "Error registering viotape device\n");
- goto clear_handler;
- }
-
- tape_class = class_create(THIS_MODULE, "tape");
- if (IS_ERR(tape_class)) {
- printk(VIOTAPE_KERN_WARN "Unable to allocat class\n");
- ret = PTR_ERR(tape_class);
- goto unreg_chrdev;
- }
-
- ret = vio_register_driver(&viotape_driver);
- if (ret)
- goto unreg_class;
-
- proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL,
- &proc_viotape_operations);
-
- return 0;
-
-unreg_class:
- class_destroy(tape_class);
-unreg_chrdev:
- unregister_chrdev(VIOTAPE_MAJOR, "viotape");
-clear_handler:
- vio_clearHandler(viomajorsubtype_tape);
- viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
-clear_op:
- clear_op_struct_pool();
- return ret;
-}
-
-/* Give a new state to the tape object */
-static int chg_state(int index, unsigned char new_state, struct file *file)
-{
- unsigned char *cur_state =
- &state[index].part_stat_rwi[state[index].cur_part];
- int rc = 0;
-
- /* if the same state, don't bother */
- if (*cur_state == new_state)
- return 0;
-
- /* write an EOF if changing from writing to some other state */
- if (*cur_state == VIOT_WRITING) {
- struct mtop write_eof = { MTWEOF, 1 };
-
- rc = viotap_ioctl(NULL, file, MTIOCTOP,
- (unsigned long)&write_eof);
- }
- *cur_state = new_state;
- return rc;
-}
-
-/* Cleanup */
-static void __exit viotap_exit(void)
-{
- remove_proc_entry("iSeries/viotape", NULL);
- vio_unregister_driver(&viotape_driver);
- class_destroy(tape_class);
- unregister_chrdev(VIOTAPE_MAJOR, "viotape");
- viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
- vio_clearHandler(viomajorsubtype_tape);
- clear_op_struct_pool();
-}
-
-MODULE_LICENSE("GPL");
-module_init(viotap_init);
-module_exit(viotap_exit);
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig
index 8ea7f078b233..48cb8d3d1758 100644
--- a/drivers/tty/hvc/Kconfig
+++ b/drivers/tty/hvc/Kconfig
@@ -71,6 +71,10 @@ config HVC_UDBG
depends on PPC && EXPERIMENTAL
select HVC_DRIVER
default n
+ help
+ This is meant to be used during HW bring up or debugging when
+ no other console mechanism exist but udbg, to get you a quick
+ console for userspace. Do NOT enable in production kernels.
config HVC_DCC
bool "ARM JTAG DCC console"
diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c
index b0957e61a7be..2259c6e72f06 100644
--- a/drivers/tty/hvc/hvc_udbg.c
+++ b/drivers/tty/hvc/hvc_udbg.c
@@ -36,7 +36,7 @@ static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count)
{
int i;
- for (i = 0; i < count; i++)
+ for (i = 0; i < count && udbg_putc; i++)
udbg_putc(buf[i]);
return i;
@@ -67,6 +67,9 @@ static int __init hvc_udbg_init(void)
{
struct hvc_struct *hp;
+ if (!udbg_putc)
+ return -ENODEV;
+
BUG_ON(hvc_udbg_dev);
hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16);
@@ -88,6 +91,9 @@ module_exit(hvc_udbg_exit);
static int __init hvc_udbg_console_init(void)
{
+ if (!udbg_putc)
+ return -ENODEV;
+
hvc_instantiate(0, 0, &hvc_udbg_ops);
add_preferred_console("hvc", 0, NULL);