Merge branch 'drm-intel-fixes' into drm-intel-next

This commit is contained in:
Keith Packard 2011-07-07 13:39:38 -07:00
commit bc67f799e7
153 changed files with 24389 additions and 502 deletions

View File

@ -518,7 +518,7 @@ N: Zach Brown
E: zab@zabbo.net
D: maestro pci sound
M: David Brownell
N: David Brownell
D: Kernel engineer, mentor, and friend. Maintained USB EHCI and
D: gadget layers, SPI subsystem, GPIO subsystem, and more than a few
D: device drivers. His encouragement also helped many engineers get

View File

@ -22,6 +22,10 @@ Supported chips:
Prefix: 'f71869'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Available from the Fintek website
* Fintek F71869A
Prefix: 'f71869a'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Not public
* Fintek F71882FG and F71883FG
Prefix: 'f71882fg'
Addresses scanned: none, address read from Super I/O config space

View File

@ -9,8 +9,8 @@ Supported chips:
Socket S1G3: Athlon II, Sempron, Turion II
* AMD Family 11h processors:
Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
* AMD Family 12h processors: "Llano"
* AMD Family 14h processors: "Brazos" (C/E/G-Series)
* AMD Family 12h processors: "Llano" (E2/A4/A6/A8-Series)
* AMD Family 14h processors: "Brazos" (C/E/G/Z-Series)
* AMD Family 15h processors: "Bulldozer"
Prefix: 'k10temp'
@ -20,12 +20,16 @@ Supported chips:
http://support.amd.com/us/Processor_TechDocs/31116.pdf
BIOS and Kernel Developer's Guide (BKDG) for AMD Family 11h Processors:
http://support.amd.com/us/Processor_TechDocs/41256.pdf
BIOS and Kernel Developer's Guide (BKDG) for AMD Family 12h Processors:
http://support.amd.com/us/Processor_TechDocs/41131.pdf
BIOS and Kernel Developer's Guide (BKDG) for AMD Family 14h Models 00h-0Fh Processors:
http://support.amd.com/us/Processor_TechDocs/43170.pdf
Revision Guide for AMD Family 10h Processors:
http://support.amd.com/us/Processor_TechDocs/41322.pdf
Revision Guide for AMD Family 11h Processors:
http://support.amd.com/us/Processor_TechDocs/41788.pdf
Revision Guide for AMD Family 12h Processors:
http://support.amd.com/us/Processor_TechDocs/44739.pdf
Revision Guide for AMD Family 14h Models 00h-0Fh Processors:
http://support.amd.com/us/Processor_TechDocs/47534.pdf
AMD Family 11h Processor Power and Thermal Data Sheet for Notebooks:

View File

@ -501,13 +501,29 @@ helper functions described in Section 4. In that case, pm_runtime_resume()
should be used. Of course, for this purpose the device's run-time PM has to be
enabled earlier by calling pm_runtime_enable().
If the device bus type's or driver's ->probe() or ->remove() callback runs
If the device bus type's or driver's ->probe() callback runs
pm_runtime_suspend() or pm_runtime_idle() or their asynchronous counterparts,
they will fail returning -EAGAIN, because the device's usage counter is
incremented by the core before executing ->probe() and ->remove(). Still, it
may be desirable to suspend the device as soon as ->probe() or ->remove() has
finished, so the PM core uses pm_runtime_idle_sync() to invoke the
subsystem-level idle callback for the device at that time.
incremented by the driver core before executing ->probe(). Still, it may be
desirable to suspend the device as soon as ->probe() has finished, so the driver
core uses pm_runtime_put_sync() to invoke the subsystem-level idle callback for
the device at that time.
Moreover, the driver core prevents runtime PM callbacks from racing with the bus
notifier callback in __device_release_driver(), which is necessary, because the
notifier is used by some subsystems to carry out operations affecting the
runtime PM functionality. It does so by calling pm_runtime_get_sync() before
driver_sysfs_remove() and the BUS_NOTIFY_UNBIND_DRIVER notifications. This
resumes the device if it's in the suspended state and prevents it from
being suspended again while those routines are being executed.
To allow bus types and drivers to put devices into the suspended state by
calling pm_runtime_suspend() from their ->remove() routines, the driver core
executes pm_runtime_put_sync() after running the BUS_NOTIFY_UNBIND_DRIVER
notifications in __device_release_driver(). This requires bus types and
drivers to make their ->remove() callbacks avoid races with runtime PM directly,
but also it allows of more flexibility in the handling of devices during the
removal of their drivers.
The user space can effectively disallow the driver of the device to power manage
it at run time by changing the value of its /sys/devices/.../power/control

View File

@ -1345,16 +1345,18 @@ F: drivers/auxdisplay/
F: include/linux/cfag12864b.h
AVR32 ARCHITECTURE
M: Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>
M: Haavard Skinnemoen <hskinnemoen@gmail.com>
M: Hans-Christian Egtvedt <egtvedt@samfundet.no>
W: http://www.atmel.com/products/AVR32/
W: http://avr32linux.org/
W: http://avrfreaks.net/
S: Supported
S: Maintained
F: arch/avr32/
AVR32/AT32AP MACHINE SUPPORT
M: Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>
S: Supported
M: Haavard Skinnemoen <hskinnemoen@gmail.com>
M: Hans-Christian Egtvedt <egtvedt@samfundet.no>
S: Maintained
F: arch/avr32/mach-at32ap/
AX.25 NETWORK LAYER
@ -1390,7 +1392,6 @@ F: include/linux/backlight.h
BATMAN ADVANCED
M: Marek Lindner <lindner_marek@yahoo.de>
M: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
M: Sven Eckelmann <sven@narfation.org>
L: b.a.t.m.a.n@lists.open-mesh.org
W: http://www.open-mesh.org/
S: Maintained
@ -1423,7 +1424,6 @@ S: Supported
F: arch/blackfin/
BLACKFIN EMAC DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
L: uclinux-dist-devel@blackfin.uclinux.org
W: http://blackfin.uclinux.org
S: Supported
@ -1639,7 +1639,7 @@ CAN NETWORK LAYER
M: Oliver Hartkopp <socketcan@hartkopp.net>
M: Oliver Hartkopp <oliver.hartkopp@volkswagen.de>
M: Urs Thuermann <urs.thuermann@volkswagen.de>
L: socketcan-core@lists.berlios.de
L: socketcan-core@lists.berlios.de (subscribers-only)
L: netdev@vger.kernel.org
W: http://developer.berlios.de/projects/socketcan/
S: Maintained
@ -1651,7 +1651,7 @@ F: include/linux/can/raw.h
CAN NETWORK DRIVERS
M: Wolfgang Grandegger <wg@grandegger.com>
L: socketcan-core@lists.berlios.de
L: socketcan-core@lists.berlios.de (subscribers-only)
L: netdev@vger.kernel.org
W: http://developer.berlios.de/projects/socketcan/
S: Maintained
@ -5181,6 +5181,7 @@ S: Supported
F: drivers/net/qlcnic/
QLOGIC QLGE 10Gb ETHERNET DRIVER
M: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
M: Ron Mercer <ron.mercer@qlogic.com>
M: linux-driver@qlogic.com
L: netdev@vger.kernel.org

View File

@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 0
SUBLEVEL = 0
EXTRAVERSION = -rc5
EXTRAVERSION = -rc6
NAME = Sneaky Weasel
# *DOCUMENTATION*

42
README
View File

@ -1,6 +1,6 @@
Linux kernel release 2.6.xx <http://kernel.org/>
Linux kernel release 3.x <http://kernel.org/>
These are the release notes for Linux version 2.6. Read them carefully,
These are the release notes for Linux version 3. Read them carefully,
as they tell you what this is all about, explain how to install the
kernel, and what to do if something goes wrong.
@ -62,10 +62,10 @@ INSTALLING the kernel source:
directory where you have permissions (eg. your home directory) and
unpack it:
gzip -cd linux-2.6.XX.tar.gz | tar xvf -
gzip -cd linux-3.X.tar.gz | tar xvf -
or
bzip2 -dc linux-2.6.XX.tar.bz2 | tar xvf -
bzip2 -dc linux-3.X.tar.bz2 | tar xvf -
Replace "XX" with the version number of the latest kernel.
@ -75,15 +75,15 @@ INSTALLING the kernel source:
files. They should match the library, and not get messed up by
whatever the kernel-du-jour happens to be.
- You can also upgrade between 2.6.xx releases by patching. Patches are
- You can also upgrade between 3.x releases by patching. Patches are
distributed in the traditional gzip and the newer bzip2 format. To
install by patching, get all the newer patch files, enter the
top level directory of the kernel source (linux-2.6.xx) and execute:
top level directory of the kernel source (linux-3.x) and execute:
gzip -cd ../patch-2.6.xx.gz | patch -p1
gzip -cd ../patch-3.x.gz | patch -p1
or
bzip2 -dc ../patch-2.6.xx.bz2 | patch -p1
bzip2 -dc ../patch-3.x.bz2 | patch -p1
(repeat xx for all versions bigger than the version of your current
source tree, _in_order_) and you should be ok. You may want to remove
@ -91,9 +91,9 @@ INSTALLING the kernel source:
failed patches (xxx# or xxx.rej). If there are, either you or me has
made a mistake.
Unlike patches for the 2.6.x kernels, patches for the 2.6.x.y kernels
Unlike patches for the 3.x kernels, patches for the 3.x.y kernels
(also known as the -stable kernels) are not incremental but instead apply
directly to the base 2.6.x kernel. Please read
directly to the base 3.x kernel. Please read
Documentation/applying-patches.txt for more information.
Alternatively, the script patch-kernel can be used to automate this
@ -107,14 +107,14 @@ INSTALLING the kernel source:
an alternative directory can be specified as the second argument.
- If you are upgrading between releases using the stable series patches
(for example, patch-2.6.xx.y), note that these "dot-releases" are
not incremental and must be applied to the 2.6.xx base tree. For
example, if your base kernel is 2.6.12 and you want to apply the
2.6.12.3 patch, you do not and indeed must not first apply the
2.6.12.1 and 2.6.12.2 patches. Similarly, if you are running kernel
version 2.6.12.2 and want to jump to 2.6.12.3, you must first
reverse the 2.6.12.2 patch (that is, patch -R) _before_ applying
the 2.6.12.3 patch.
(for example, patch-3.x.y), note that these "dot-releases" are
not incremental and must be applied to the 3.x base tree. For
example, if your base kernel is 3.0 and you want to apply the
3.0.3 patch, you do not and indeed must not first apply the
3.0.1 and 3.0.2 patches. Similarly, if you are running kernel
version 3.0.2 and want to jump to 3.0.3, you must first
reverse the 3.0.2 patch (that is, patch -R) _before_ applying
the 3.0.3 patch.
You can read more on this in Documentation/applying-patches.txt
- Make sure you have no stale .o files and dependencies lying around:
@ -126,7 +126,7 @@ INSTALLING the kernel source:
SOFTWARE REQUIREMENTS
Compiling and running the 2.6.xx kernels requires up-to-date
Compiling and running the 3.x kernels requires up-to-date
versions of various software packages. Consult
Documentation/Changes for the minimum version numbers required
and how to get updates for these packages. Beware that using
@ -142,11 +142,11 @@ BUILD directory for the kernel:
Using the option "make O=output/dir" allow you to specify an alternate
place for the output files (including .config).
Example:
kernel source code: /usr/src/linux-2.6.N
kernel source code: /usr/src/linux-3.N
build directory: /home/name/build/kernel
To configure and build the kernel use:
cd /usr/src/linux-2.6.N
cd /usr/src/linux-3.N
make O=/home/name/build/kernel menuconfig
make O=/home/name/build/kernel
sudo make O=/home/name/build/kernel modules_install install

View File

@ -223,15 +223,15 @@ static struct clk *periph_clocks[] __initdata = {
};
static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {

View File

@ -1220,7 +1220,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
at91cap9_set_console_clock(portnr);
at91cap9_set_console_clock(at91_uarts[portnr]->id);
}
}

View File

@ -199,9 +199,9 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("ssc", "ssc.2", &ssc2_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {

View File

@ -1135,7 +1135,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
at91rm9200_set_console_clock(portnr);
at91rm9200_set_console_clock(at91_uarts[portnr]->id);
}
}

View File

@ -1173,7 +1173,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
at91sam9260_set_console_clock(portnr);
at91sam9260_set_console_clock(at91_uarts[portnr]->id);
}
}

View File

@ -1013,7 +1013,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
at91sam9261_set_console_clock(portnr);
at91sam9261_set_console_clock(at91_uarts[portnr]->id);
}
}

View File

@ -1395,7 +1395,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
at91sam9263_set_console_clock(portnr);
at91sam9263_set_console_clock(at91_uarts[portnr]->id);
}
}

View File

@ -217,11 +217,11 @@ static struct clk *periph_clocks[] __initdata = {
static struct clk_lookup periph_clocks_lookups[] = {
/* One additional fake clock for ohci */
CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci.0", &uhphs_clk),
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci", &uhphs_clk),
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),

View File

@ -1550,7 +1550,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
at91sam9g45_set_console_clock(portnr);
at91sam9g45_set_console_clock(at91_uarts[portnr]->id);
}
}

View File

@ -191,8 +191,8 @@ static struct clk *periph_clocks[] __initdata = {
};
static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk),
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk),
CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),

View File

@ -1168,7 +1168,7 @@ void __init at91_set_serial_console(unsigned portnr)
{
if (portnr < ATMEL_MAX_UART) {
atmel_default_console_device = at91_uarts[portnr];
at91sam9rl_set_console_clock(portnr);
at91sam9rl_set_console_clock(at91_uarts[portnr]->id);
}
}

View File

@ -215,7 +215,7 @@ static void __init cap9adk_add_device_nand(void)
csa = at91_sys_read(AT91_MATRIX_EBICSA);
at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V);
cap9adk_nand_data.bus_width_16 = !board_have_nand_8bit();
cap9adk_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (cap9adk_nand_data.bus_width_16)
cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16;

View File

@ -214,7 +214,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;

View File

@ -220,7 +220,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;

View File

@ -221,7 +221,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;

View File

@ -198,7 +198,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;

View File

@ -178,7 +178,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = {
static void __init ek_add_device_nand(void)
{
ek_nand_data.bus_width_16 = !board_have_nand_8bit();
ek_nand_data.bus_width_16 = board_have_nand_16bit();
/* setup bus-width (8 or 16) */
if (ek_nand_data.bus_width_16)
ek_nand_smc_config.mode |= AT91_SMC_DBW_16;

View File

@ -13,13 +13,13 @@
* the 16-31 bit are reserved for at91 generic information
*
* bit 31:
* 0 => nand 16 bit
* 1 => nand 8 bit
* 0 => nand 8 bit
* 1 => nand 16 bit
*/
#define BOARD_HAVE_NAND_8BIT (1 << 31)
static int inline board_have_nand_8bit(void)
#define BOARD_HAVE_NAND_16BIT (1 << 31)
static inline int board_have_nand_16bit(void)
{
return system_rev & BOARD_HAVE_NAND_8BIT;
return system_rev & BOARD_HAVE_NAND_16BIT;
}
#endif /* __ARCH_SYSTEM_REV_H__ */

View File

@ -381,7 +381,7 @@ void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
gpio_set_value(GPIO_PORT114, state);
}
static struct sh_mobile_sdhi_info sh_sdhi1_platdata = {
static struct sh_mobile_sdhi_info sh_sdhi1_info = {
.tmio_flags = TMIO_MMC_WRPROTECT_DISABLE,
.tmio_caps = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
.tmio_ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
@ -413,7 +413,7 @@ static struct platform_device sdhi1_device = {
.name = "sh_mobile_sdhi",
.id = 1,
.dev = {
.platform_data = &sh_sdhi1_platdata,
.platform_data = &sh_sdhi1_info,
},
.num_resources = ARRAY_SIZE(sdhi1_resources),
.resource = sdhi1_resources,

View File

@ -913,7 +913,7 @@ static struct i2c_board_info imx074_info = {
I2C_BOARD_INFO("imx074", 0x1a),
};
struct soc_camera_link imx074_link = {
static struct soc_camera_link imx074_link = {
.bus_id = 0,
.board_info = &imx074_info,
.i2c_adapter_id = 0,

View File

@ -1287,9 +1287,9 @@ static struct platform_device *mackerel_devices[] __initdata = {
&nor_flash_device,
&smc911x_device,
&lcdc_device,
&usbhs0_device,
&usb1_host_device,
&usbhs1_device,
&usbhs0_device,
&leds_device,
&fsi_device,
&fsi_ak4643_device,

View File

@ -209,8 +209,10 @@
wm8776:codec@1a {
compatible = "wlf,wm8776";
reg = <0x1a>;
/* MCLK source is a stand-alone oscillator */
clock-frequency = <12288000>;
/*
* clock-frequency will be set by U-Boot if
* the clock is enabled.
*/
};
};
@ -280,7 +282,8 @@
codec-handle = <&wm8776>;
fsl,playback-dma = <&dma00>;
fsl,capture-dma = <&dma01>;
fsl,fifo-depth = <16>;
fsl,fifo-depth = <15>;
fsl,ssi-asynchronous;
};
dma@c300 {

View File

@ -148,7 +148,6 @@ CONFIG_SCSI_SAS_ATTRS=m
CONFIG_SCSI_CXGB3_ISCSI=m
CONFIG_SCSI_CXGB4_ISCSI=m
CONFIG_SCSI_BNX2_ISCSI=m
CONFIG_SCSI_BNX2_ISCSI=m
CONFIG_BE2ISCSI=m
CONFIG_SCSI_IBMVSCSI=y
CONFIG_SCSI_IBMVFC=m

View File

@ -4,6 +4,7 @@
#include <linux/init.h>
#include <linux/rtc.h>
#include <linux/delay.h>
#include <linux/ratelimit.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/time.h>
@ -29,9 +30,10 @@ unsigned long __init rtas_get_boot_time(void)
}
} while (wait_time && (get_tb() < max_wait_tb));
if (error != 0 && printk_ratelimit()) {
printk(KERN_WARNING "error: reading the clock failed (%d)\n",
error);
if (error != 0) {
printk_ratelimited(KERN_WARNING
"error: reading the clock failed (%d)\n",
error);
return 0;
}
@ -55,19 +57,21 @@ void rtas_get_rtc_time(struct rtc_time *rtc_tm)
wait_time = rtas_busy_delay_time(error);
if (wait_time) {
if (in_interrupt() && printk_ratelimit()) {
if (in_interrupt()) {
memset(rtc_tm, 0, sizeof(struct rtc_time));
printk(KERN_WARNING "error: reading clock"
" would delay interrupt\n");
printk_ratelimited(KERN_WARNING
"error: reading clock "
"would delay interrupt\n");
return; /* delay not allowed */
}
msleep(wait_time);
}
} while (wait_time && (get_tb() < max_wait_tb));
if (error != 0 && printk_ratelimit()) {
printk(KERN_WARNING "error: reading the clock failed (%d)\n",
error);
if (error != 0) {
printk_ratelimited(KERN_WARNING
"error: reading the clock failed (%d)\n",
error);
return;
}
@ -99,9 +103,10 @@ int rtas_set_rtc_time(struct rtc_time *tm)
}
} while (wait_time && (get_tb() < max_wait_tb));
if (error != 0 && printk_ratelimit())
printk(KERN_WARNING "error: setting the clock failed (%d)\n",
error);
if (error != 0)
printk_ratelimited(KERN_WARNING
"error: setting the clock failed (%d)\n",
error);
return 0;
}

View File

@ -25,6 +25,7 @@
#include <linux/errno.h>
#include <linux/elf.h>
#include <linux/ptrace.h>
#include <linux/ratelimit.h>
#ifdef CONFIG_PPC64
#include <linux/syscalls.h>
#include <linux/compat.h>
@ -892,11 +893,12 @@ badframe:
printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
if (show_unhandled_signals && printk_ratelimit())
printk(KERN_INFO "%s[%d]: bad frame in handle_rt_signal32: "
"%p nip %08lx lr %08lx\n",
current->comm, current->pid,
addr, regs->nip, regs->link);
if (show_unhandled_signals)
printk_ratelimited(KERN_INFO
"%s[%d]: bad frame in handle_rt_signal32: "
"%p nip %08lx lr %08lx\n",
current->comm, current->pid,
addr, regs->nip, regs->link);
force_sigsegv(sig, current);
return 0;
@ -1058,11 +1060,12 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
return 0;
bad:
if (show_unhandled_signals && printk_ratelimit())
printk(KERN_INFO "%s[%d]: bad frame in sys_rt_sigreturn: "
"%p nip %08lx lr %08lx\n",
current->comm, current->pid,
rt_sf, regs->nip, regs->link);
if (show_unhandled_signals)
printk_ratelimited(KERN_INFO
"%s[%d]: bad frame in sys_rt_sigreturn: "
"%p nip %08lx lr %08lx\n",
current->comm, current->pid,
rt_sf, regs->nip, regs->link);
force_sig(SIGSEGV, current);
return 0;
@ -1149,12 +1152,12 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
* We kill the task with a SIGSEGV in this situation.
*/
if (do_setcontext(ctx, regs, 1)) {
if (show_unhandled_signals && printk_ratelimit())
printk(KERN_INFO "%s[%d]: bad frame in "
"sys_debug_setcontext: %p nip %08lx "
"lr %08lx\n",
current->comm, current->pid,
ctx, regs->nip, regs->link);
if (show_unhandled_signals)
printk_ratelimited(KERN_INFO "%s[%d]: bad frame in "
"sys_debug_setcontext: %p nip %08lx "
"lr %08lx\n",
current->comm, current->pid,
ctx, regs->nip, regs->link);
force_sig(SIGSEGV, current);
goto out;
@ -1236,11 +1239,12 @@ badframe:
printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
if (show_unhandled_signals && printk_ratelimit())
printk(KERN_INFO "%s[%d]: bad frame in handle_signal32: "
"%p nip %08lx lr %08lx\n",
current->comm, current->pid,
frame, regs->nip, regs->link);
if (show_unhandled_signals)
printk_ratelimited(KERN_INFO
"%s[%d]: bad frame in handle_signal32: "
"%p nip %08lx lr %08lx\n",
current->comm, current->pid,
frame, regs->nip, regs->link);
force_sigsegv(sig, current);
return 0;
@ -1288,11 +1292,12 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
return 0;
badframe:
if (show_unhandled_signals && printk_ratelimit())
printk(KERN_INFO "%s[%d]: bad frame in sys_sigreturn: "
"%p nip %08lx lr %08lx\n",
current->comm, current->pid,
addr, regs->nip, regs->link);
if (show_unhandled_signals)
printk_ratelimited(KERN_INFO
"%s[%d]: bad frame in sys_sigreturn: "
"%p nip %08lx lr %08lx\n",
current->comm, current->pid,
addr, regs->nip, regs->link);
force_sig(SIGSEGV, current);
return 0;

View File

@ -24,6 +24,7 @@
#include <linux/elf.h>
#include <linux/ptrace.h>
#include <linux/module.h>
#include <linux/ratelimit.h>
#include <asm/sigcontext.h>
#include <asm/ucontext.h>
@ -380,10 +381,10 @@ badframe:
printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n",
regs, uc, &uc->uc_mcontext);
#endif
if (show_unhandled_signals && printk_ratelimit())
printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, "rt_sigreturn",
(long)uc, regs->nip, regs->link);
if (show_unhandled_signals)
printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, "rt_sigreturn",
(long)uc, regs->nip, regs->link);
force_sig(SIGSEGV, current);
return 0;
@ -468,10 +469,10 @@ badframe:
printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
regs, frame, newsp);
#endif
if (show_unhandled_signals && printk_ratelimit())
printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, "setup_rt_frame",
(long)frame, regs->nip, regs->link);
if (show_unhandled_signals)
printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, "setup_rt_frame",
(long)frame, regs->nip, regs->link);
force_sigsegv(signr, current);
return 0;

View File

@ -34,6 +34,7 @@
#include <linux/bug.h>
#include <linux/kdebug.h>
#include <linux/debugfs.h>
#include <linux/ratelimit.h>
#include <asm/emulated_ops.h>
#include <asm/pgtable.h>
@ -197,12 +198,11 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
if (die("Exception in kernel mode", regs, signr))
return;
} else if (show_unhandled_signals &&
unhandled_signal(current, signr) &&
printk_ratelimit()) {
printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, signr,
addr, regs->nip, regs->link, code);
}
unhandled_signal(current, signr)) {
printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, signr,
addr, regs->nip, regs->link, code);
}
memset(&info, 0, sizeof(info));
info.si_signo = signr;
@ -425,7 +425,7 @@ int machine_check_e500mc(struct pt_regs *regs)
unsigned long reason = mcsr;
int recoverable = 1;
if (reason & MCSR_BUS_RBERR) {
if (reason & MCSR_LD) {
recoverable = fsl_rio_mcheck_exception(regs);
if (recoverable == 1)
goto silent_out;
@ -1342,9 +1342,8 @@ void altivec_assist_exception(struct pt_regs *regs)
} else {
/* didn't recognize the instruction */
/* XXX quick hack for now: set the non-Java bit in the VSCR */
if (printk_ratelimit())
printk(KERN_ERR "Unrecognized altivec instruction "
"in %s at %lx\n", current->comm, regs->nip);
printk_ratelimited(KERN_ERR "Unrecognized altivec instruction "
"in %s at %lx\n", current->comm, regs->nip);
current->thread.vscr.u[3] |= 0x10000;
}
}
@ -1548,9 +1547,8 @@ u32 ppc_warn_emulated;
void ppc_warn_emulated_print(const char *type)
{
if (printk_ratelimit())
pr_warning("%s used emulated %s instruction\n", current->comm,
type);
pr_warn_ratelimited("%s used emulated %s instruction\n", current->comm,
type);
}
static int __init ppc_warn_emulated_init(void)

View File

@ -31,6 +31,7 @@
#include <linux/kdebug.h>
#include <linux/perf_event.h>
#include <linux/magic.h>
#include <linux/ratelimit.h>
#include <asm/firmware.h>
#include <asm/page.h>
@ -346,11 +347,10 @@ bad_area_nosemaphore:
return 0;
}
if (is_exec && (error_code & DSISR_PROTFAULT)
&& printk_ratelimit())
printk(KERN_CRIT "kernel tried to execute NX-protected"
" page (%lx) - exploit attempt? (uid: %d)\n",
address, current_uid());
if (is_exec && (error_code & DSISR_PROTFAULT))
printk_ratelimited(KERN_CRIT "kernel tried to execute NX-protected"
" page (%lx) - exploit attempt? (uid: %d)\n",
address, current_uid());
return SIGSEGV;

View File

@ -283,23 +283,24 @@ static void __iomem *rio_regs_win;
#ifdef CONFIG_E500
int fsl_rio_mcheck_exception(struct pt_regs *regs)
{
const struct exception_table_entry *entry = NULL;
unsigned long reason = mfspr(SPRN_MCSR);
const struct exception_table_entry *entry;
unsigned long reason;
if (reason & MCSR_BUS_RBERR) {
reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR));
if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) {
/* Check if we are prepared to handle this fault */
entry = search_exception_tables(regs->nip);
if (entry) {
pr_debug("RIO: %s - MC Exception handled\n",
__func__);
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
0);
regs->msr |= MSR_RI;
regs->nip = entry->fixup;
return 1;
}
if (!rio_regs_win)
return 0;
reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR));
if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) {
/* Check if we are prepared to handle this fault */
entry = search_exception_tables(regs->nip);
if (entry) {
pr_debug("RIO: %s - MC Exception handled\n",
__func__);
out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR),
0);
regs->msr |= MSR_RI;
regs->nip = entry->fixup;
return 1;
}
}

View File

@ -29,6 +29,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/syscore_ops.h>
#include <linux/ratelimit.h>
#include <asm/ptrace.h>
#include <asm/signal.h>
@ -1648,9 +1649,8 @@ static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg)
return NO_IRQ;
}
if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
if (printk_ratelimit())
printk(KERN_WARNING "%s: Got protected source %d !\n",
mpic->name, (int)src);
printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n",
mpic->name, (int)src);
mpic_eoi(mpic);
return NO_IRQ;
}
@ -1688,9 +1688,8 @@ unsigned int mpic_get_coreint_irq(void)
return NO_IRQ;
}
if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
if (printk_ratelimit())
printk(KERN_WARNING "%s: Got protected source %d !\n",
mpic->name, (int)src);
printk_ratelimited(KERN_WARNING "%s: Got protected source %d !\n",
mpic->name, (int)src);
return NO_IRQ;
}

View File

@ -348,6 +348,7 @@ config CPU_SUBTYPE_SH7720
select SYS_SUPPORTS_CMT
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
help
Select SH7720 if you have a SH3-DSP SH7720 CPU.
@ -357,6 +358,7 @@ config CPU_SUBTYPE_SH7721
select CPU_HAS_DSP
select SYS_SUPPORTS_CMT
select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
help
Select SH7721 if you have a SH3-DSP SH7721 CPU.
@ -440,6 +442,7 @@ config CPU_SUBTYPE_SH7763
bool "Support SH7763 processor"
select CPU_SH4A
select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
help
Select SH7763 if you have a SH4A SH7763(R5S77631) CPU.
@ -467,7 +470,9 @@ config CPU_SUBTYPE_SH7786
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select ARCH_WANT_OPTIONAL_GPIOLIB
select USB_ARCH_HAS_OHCI
select USB_OHCI_SH if USB_OHCI_HCD
select USB_ARCH_HAS_EHCI
select USB_EHCI_SH if USB_EHCI_HCD
config CPU_SUBTYPE_SHX3
bool "Support SH-X3 processor"

View File

@ -9,7 +9,6 @@ CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS_ALL=y
CONFIG_SLAB=y
@ -39,8 +38,6 @@ CONFIG_IPV6=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
CONFIG_MTD_CONCAT=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_M25P80=y
@ -56,18 +53,19 @@ CONFIG_SH_ETH=y
# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_MOUSE_PS2 is not set
# CONFIG_SERIO is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_SH_SCI_NR_UARTS=3
CONFIG_SERIAL_SH_SCI_CONSOLE=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_SPI=y
CONFIG_SPI_SH=y
# CONFIG_HWMON is not set
CONFIG_MFD_SH_MOBILE_SDHI=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_SH=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_SH=y
CONFIG_USB_STORAGE=y
CONFIG_MMC=y
CONFIG_MMC_SDHI=y

View File

@ -183,7 +183,7 @@ static const struct sh_dmae_slave_config sh7757_dmae1_slaves[] = {
{
.slave_id = SHDMA_SLAVE_SCIF2_RX,
.addr = 0x1f4b0014,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x22,
},
@ -197,7 +197,7 @@ static const struct sh_dmae_slave_config sh7757_dmae1_slaves[] = {
{
.slave_id = SHDMA_SLAVE_SCIF3_RX,
.addr = 0x1f4c0014,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x2a,
},
@ -211,7 +211,7 @@ static const struct sh_dmae_slave_config sh7757_dmae1_slaves[] = {
{
.slave_id = SHDMA_SLAVE_SCIF4_RX,
.addr = 0x1f4d0014,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x42,
},
@ -228,7 +228,7 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
{
.slave_id = SHDMA_SLAVE_RIIC0_RX,
.addr = 0x1e500013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x22,
},
@ -242,7 +242,7 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
{
.slave_id = SHDMA_SLAVE_RIIC1_RX,
.addr = 0x1e510013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x2a,
},
@ -256,7 +256,7 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
{
.slave_id = SHDMA_SLAVE_RIIC2_RX,
.addr = 0x1e520013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0xa2,
},
@ -265,12 +265,12 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
.addr = 0x1e530012,
.chcr = SM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0xab,
.mid_rid = 0xa9,
},
{
.slave_id = SHDMA_SLAVE_RIIC3_RX,
.addr = 0x1e530013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0xaf,
},
@ -279,14 +279,14 @@ static const struct sh_dmae_slave_config sh7757_dmae2_slaves[] = {
.addr = 0x1e540012,
.chcr = SM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0xc1,
.mid_rid = 0xc5,
},
{
.slave_id = SHDMA_SLAVE_RIIC4_RX,
.addr = 0x1e540013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0xc2,
.mid_rid = 0xc6,
},
};
@ -301,7 +301,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
{
.slave_id = SHDMA_SLAVE_RIIC5_RX,
.addr = 0x1e550013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x22,
},
@ -315,7 +315,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
{
.slave_id = SHDMA_SLAVE_RIIC6_RX,
.addr = 0x1e560013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x2a,
},
@ -329,7 +329,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
{
.slave_id = SHDMA_SLAVE_RIIC7_RX,
.addr = 0x1e570013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x42,
},
@ -343,7 +343,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
{
.slave_id = SHDMA_SLAVE_RIIC8_RX,
.addr = 0x1e580013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x46,
},
@ -357,7 +357,7 @@ static const struct sh_dmae_slave_config sh7757_dmae3_slaves[] = {
{
.slave_id = SHDMA_SLAVE_RIIC9_RX,
.addr = 0x1e590013,
.chcr = SM_INC | 0x800 | 0x40000000 |
.chcr = DM_INC | 0x800 | 0x40000000 |
TS_INDEX2VAL(XMIT_SZ_8BIT),
.mid_rid = 0x52,
},
@ -659,6 +659,54 @@ static struct platform_device spi0_device = {
.resource = spi0_resources,
};
static struct resource usb_ehci_resources[] = {
[0] = {
.start = 0xfe4f1000,
.end = 0xfe4f10ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 57,
.end = 57,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device usb_ehci_device = {
.name = "sh_ehci",
.id = -1,
.dev = {
.dma_mask = &usb_ehci_device.dev.coherent_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(usb_ehci_resources),
.resource = usb_ehci_resources,
};
static struct resource usb_ohci_resources[] = {
[0] = {
.start = 0xfe4f1800,
.end = 0xfe4f18ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 57,
.end = 57,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device usb_ohci_device = {
.name = "sh_ohci",
.id = -1,
.dev = {
.dma_mask = &usb_ohci_device.dev.coherent_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(usb_ohci_resources),
.resource = usb_ohci_resources,
};
static struct platform_device *sh7757_devices[] __initdata = {
&scif2_device,
&scif3_device,
@ -670,6 +718,8 @@ static struct platform_device *sh7757_devices[] __initdata = {
&dma2_device,
&dma3_device,
&spi0_device,
&usb_ehci_device,
&usb_ohci_device,
};
static int __init sh7757_devices_setup(void)
@ -1039,13 +1089,13 @@ static DECLARE_INTC_DESC(intc_desc, "sh7757", vectors, groups,
/* Support for external interrupt pins in IRQ mode */
static struct intc_vect vectors_irq0123[] __initdata = {
INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
INTC_VECT(IRQ0, 0x200), INTC_VECT(IRQ1, 0x240),
INTC_VECT(IRQ2, 0x280), INTC_VECT(IRQ3, 0x2c0),
};
static struct intc_vect vectors_irq4567[] __initdata = {
INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
INTC_VECT(IRQ4, 0x300), INTC_VECT(IRQ5, 0x340),
INTC_VECT(IRQ6, 0x380), INTC_VECT(IRQ7, 0x3c0),
};
static struct intc_sense_reg sense_registers[] __initdata = {
@ -1079,14 +1129,14 @@ static struct intc_vect vectors_irl0123[] __initdata = {
};
static struct intc_vect vectors_irl4567[] __initdata = {
INTC_VECT(IRL4_LLLL, 0xb00), INTC_VECT(IRL4_LLLH, 0xb20),
INTC_VECT(IRL4_LLHL, 0xb40), INTC_VECT(IRL4_LLHH, 0xb60),
INTC_VECT(IRL4_LHLL, 0xb80), INTC_VECT(IRL4_LHLH, 0xba0),
INTC_VECT(IRL4_LHHL, 0xbc0), INTC_VECT(IRL4_LHHH, 0xbe0),
INTC_VECT(IRL4_HLLL, 0xc00), INTC_VECT(IRL4_HLLH, 0xc20),
INTC_VECT(IRL4_HLHL, 0xc40), INTC_VECT(IRL4_HLHH, 0xc60),
INTC_VECT(IRL4_HHLL, 0xc80), INTC_VECT(IRL4_HHLH, 0xca0),
INTC_VECT(IRL4_HHHL, 0xcc0),
INTC_VECT(IRL4_LLLL, 0x200), INTC_VECT(IRL4_LLLH, 0x220),
INTC_VECT(IRL4_LLHL, 0x240), INTC_VECT(IRL4_LLHH, 0x260),
INTC_VECT(IRL4_LHLL, 0x280), INTC_VECT(IRL4_LHLH, 0x2a0),
INTC_VECT(IRL4_LHHL, 0x2c0), INTC_VECT(IRL4_LHHH, 0x2e0),
INTC_VECT(IRL4_HLLL, 0x300), INTC_VECT(IRL4_HLLH, 0x320),
INTC_VECT(IRL4_HLHL, 0x340), INTC_VECT(IRL4_HLHH, 0x360),
INTC_VECT(IRL4_HHLL, 0x380), INTC_VECT(IRL4_HHLH, 0x3a0),
INTC_VECT(IRL4_HHHL, 0x3c0),
};
static DECLARE_INTC_DESC(intc_desc_irl0123, "sh7757-irl0123", vectors_irl0123,

View File

@ -13,6 +13,7 @@
#include <linux/seq_file.h>
#include <linux/ftrace.h>
#include <linux/delay.h>
#include <linux/ratelimit.h>
#include <asm/processor.h>
#include <asm/machvec.h>
#include <asm/uaccess.h>
@ -268,9 +269,8 @@ void migrate_irqs(void)
unsigned int newcpu = cpumask_any_and(data->affinity,
cpu_online_mask);
if (newcpu >= nr_cpu_ids) {
if (printk_ratelimit())
printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
irq, cpu);
pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n",
irq, cpu);
cpumask_setall(data->affinity);
newcpu = cpumask_any_and(data->affinity,

View File

@ -13,6 +13,7 @@
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/ratelimit.h>
#include <asm/alignment.h>
#include <asm/processor.h>
@ -95,13 +96,13 @@ int set_unalign_ctl(struct task_struct *tsk, unsigned int val)
void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn,
struct pt_regs *regs)
{
if (user_mode(regs) && (se_usermode & UM_WARN) && printk_ratelimit())
pr_notice("Fixing up unaligned userspace access "
if (user_mode(regs) && (se_usermode & UM_WARN))
pr_notice_ratelimited("Fixing up unaligned userspace access "
"in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
tsk->comm, task_pid_nr(tsk),
(void *)instruction_pointer(regs), insn);
else if (se_kernmode_warn && printk_ratelimit())
pr_notice("Fixing up unaligned kernel access "
else if (se_kernmode_warn)
pr_notice_ratelimited("Fixing up unaligned kernel access "
"in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
tsk->comm, task_pid_nr(tsk),
(void *)instruction_pointer(regs), insn);

View File

@ -62,7 +62,7 @@ extern int sfi_mtimer_num;
#else /* CONFIG_APB_TIMER */
static inline unsigned long apbt_quick_calibrate(void) {return 0; }
static inline void apbt_time_init(void) {return 0; }
static inline void apbt_time_init(void) { }
#endif
#endif /* ASM_X86_APBT_H */

View File

@ -3372,7 +3372,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
int def_op_bytes, def_ad_bytes, goffset, simd_prefix;
bool op_prefix = false;
struct opcode opcode;
struct operand memop = { .type = OP_NONE };
struct operand memop = { .type = OP_NONE }, *memopp = NULL;
c->eip = ctxt->eip;
c->fetch.start = c->eip;
@ -3547,9 +3547,6 @@ done_prefixes:
if (memop.type == OP_MEM && c->ad_bytes != 8)
memop.addr.mem.ea = (u32)memop.addr.mem.ea;
if (memop.type == OP_MEM && c->rip_relative)
memop.addr.mem.ea += c->eip;
/*
* Decode and fetch the source operand: register, memory
* or immediate.
@ -3571,6 +3568,7 @@ done_prefixes:
c->op_bytes;
srcmem_common:
c->src = memop;
memopp = &c->src;
break;
case SrcImmU16:
rc = decode_imm(ctxt, &c->src, 2, false);
@ -3667,6 +3665,7 @@ done_prefixes:
case DstMem:
case DstMem64:
c->dst = memop;
memopp = &c->dst;
if ((c->d & DstMask) == DstMem64)
c->dst.bytes = 8;
else
@ -3700,10 +3699,13 @@ done_prefixes:
/* Special instructions do their own operand decoding. */
default:
c->dst.type = OP_NONE; /* Disable writeback. */
return 0;
break;
}
done:
if (memopp && memopp->type == OP_MEM && c->rip_relative)
memopp->addr.mem.ea += c->eip;
return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK;
}

View File

@ -333,6 +333,7 @@ static int xen_register_pirq(u32 gsi, int triggering)
struct physdev_map_pirq map_irq;
int shareable = 0;
char *name;
bool gsi_override = false;
if (!xen_pv_domain())
return -1;
@ -349,11 +350,32 @@ static int xen_register_pirq(u32 gsi, int triggering)
if (pirq < 0)
goto out;
irq = xen_bind_pirq_gsi_to_irq(gsi, pirq, shareable, name);
/* Before we bind the GSI to a Linux IRQ, check whether
* we need to override it with bus_irq (IRQ) value. Usually for
* IRQs below IRQ_LEGACY_IRQ this holds IRQ == GSI, as so:
* ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 low level)
* but there are oddballs where the IRQ != GSI:
* ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 20 low level)
* which ends up being: gsi_to_irq[9] == 20
* (which is what acpi_gsi_to_irq ends up calling when starting the
* the ACPI interpreter and keels over since IRQ 9 has not been
* setup as we had setup IRQ 20 for it).
*/
if (gsi == acpi_sci_override_gsi) {
/* Check whether the GSI != IRQ */
acpi_gsi_to_irq(gsi, &irq);
if (irq != gsi)
/* Bugger, we MUST have that IRQ. */
gsi_override = true;
}
if (gsi_override)
irq = xen_bind_pirq_gsi_to_irq(irq, pirq, shareable, name);
else
irq = xen_bind_pirq_gsi_to_irq(gsi, pirq, shareable, name);
if (irq < 0)
goto out;
printk(KERN_DEBUG "xen: --> pirq=%d -> irq=%d\n", pirq, irq);
printk(KERN_DEBUG "xen: --> pirq=%d -> irq=%d (gsi=%d)\n", pirq, irq, gsi);
map_irq.domid = DOMID_SELF;
map_irq.type = MAP_PIRQ_TYPE_GSI;

View File

@ -1232,7 +1232,11 @@ static void xen_flush_tlb_others(const struct cpumask *cpus,
{
struct {
struct mmuext_op op;
#ifdef CONFIG_SMP
DECLARE_BITMAP(mask, num_processors);
#else
DECLARE_BITMAP(mask, NR_CPUS);
#endif
} *args;
struct multicall_space mcs;

View File

@ -32,7 +32,6 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/net.h>
#include <linux/slab.h>
#define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION
#define DEFLATE_DEF_WINBITS 11
@ -73,7 +72,7 @@ static int deflate_decomp_init(struct deflate_ctx *ctx)
int ret = 0;
struct z_stream_s *stream = &ctx->decomp_stream;
stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
stream->workspace = vzalloc(zlib_inflate_workspacesize());
if (!stream->workspace) {
ret = -ENOMEM;
goto out;
@ -86,7 +85,7 @@ static int deflate_decomp_init(struct deflate_ctx *ctx)
out:
return ret;
out_free:
kfree(stream->workspace);
vfree(stream->workspace);
goto out;
}
@ -99,7 +98,7 @@ static void deflate_comp_exit(struct deflate_ctx *ctx)
static void deflate_decomp_exit(struct deflate_ctx *ctx)
{
zlib_inflateEnd(&ctx->decomp_stream);
kfree(ctx->decomp_stream.workspace);
vfree(ctx->decomp_stream.workspace);
}
static int deflate_init(struct crypto_tfm *tfm)

View File

@ -29,7 +29,6 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/net.h>
#include <linux/slab.h>
#include <crypto/internal/compress.h>
@ -60,7 +59,7 @@ static void zlib_decomp_exit(struct zlib_ctx *ctx)
if (stream->workspace) {
zlib_inflateEnd(stream);
kfree(stream->workspace);
vfree(stream->workspace);
stream->workspace = NULL;
}
}
@ -228,13 +227,13 @@ static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
: DEF_WBITS;
stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
stream->workspace = vzalloc(zlib_inflate_workspacesize());
if (!stream->workspace)
return -ENOMEM;
ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
if (ret != Z_OK) {
kfree(stream->workspace);
vfree(stream->workspace);
stream->workspace = NULL;
return -EINVAL;
}

View File

@ -452,7 +452,7 @@ void ahci_save_initial_config(struct device *dev,
}
if (mask_port_map) {
dev_printk(KERN_ERR, dev, "masking port_map 0x%x -> 0x%x\n",
dev_printk(KERN_WARNING, dev, "masking port_map 0x%x -> 0x%x\n",
port_map,
port_map & mask_port_map);
port_map &= mask_port_map;

View File

@ -238,9 +238,9 @@ static int build_sh_desc_ipsec(struct caam_ctx *ctx)
/* build shared descriptor for this session */
sh_desc = kmalloc(CAAM_CMD_SZ * DESC_AEAD_SHARED_TEXT_LEN +
keys_fit_inline ?
ctx->split_key_pad_len + ctx->enckeylen :
CAAM_PTR_SZ * 2, GFP_DMA | GFP_KERNEL);
(keys_fit_inline ?
ctx->split_key_pad_len + ctx->enckeylen :
CAAM_PTR_SZ * 2), GFP_DMA | GFP_KERNEL);
if (!sh_desc) {
dev_err(jrdev, "could not allocate shared descriptor\n");
return -ENOMEM;

View File

@ -50,7 +50,6 @@ struct intel_dp {
bool has_audio;
int force_audio;
uint32_t color_range;
int dpms_mode;
uint8_t link_bw;
uint8_t lane_count;
uint8_t dpcd[4];
@ -138,8 +137,8 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp)
{
int max_lane_count = 4;
if (intel_dp->dpcd[0] >= 0x11) {
max_lane_count = intel_dp->dpcd[2] & 0x1f;
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) {
max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f;
switch (max_lane_count) {
case 1: case 2: case 4:
break;
@ -153,7 +152,7 @@ intel_dp_max_lane_count(struct intel_dp *intel_dp)
static int
intel_dp_max_link_bw(struct intel_dp *intel_dp)
{
int max_link_bw = intel_dp->dpcd[1];
int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
switch (max_link_bw) {
case DP_LINK_BW_1_62:
@ -775,7 +774,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
/*
* Check for DPCD version > 1.1 and enhanced framing support
*/
if (intel_dp->dpcd[0] >= 0x11 && (intel_dp->dpcd[2] & DP_ENHANCED_FRAME_CAP)) {
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
(intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) {
intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
intel_dp->DP |= DP_ENHANCED_FRAMING;
}
@ -943,11 +943,44 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
udelay(200);
}
/* If the sink supports it, try to set the power state appropriately */
static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
{
int ret, i;
/* Should have a valid DPCD by this point */
if (intel_dp->dpcd[DP_DPCD_REV] < 0x11)
return;
if (mode != DRM_MODE_DPMS_ON) {
ret = intel_dp_aux_native_write_1(intel_dp, DP_SET_POWER,
DP_SET_POWER_D3);
if (ret != 1)
DRM_DEBUG_DRIVER("failed to write sink power state\n");
} else {
/*
* When turning on, we need to retry for 1ms to give the sink
* time to wake up.
*/
for (i = 0; i < 3; i++) {
ret = intel_dp_aux_native_write_1(intel_dp,
DP_SET_POWER,
DP_SET_POWER_D0);
if (ret == 1)
break;
msleep(1);
}
}
}
static void intel_dp_prepare(struct drm_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev;
/* Wake up the sink first */
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
if (is_edp(intel_dp)) {
ironlake_edp_backlight_off(dev);
ironlake_edp_panel_off(dev);
@ -991,6 +1024,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (mode != DRM_MODE_DPMS_ON) {
if (is_edp(intel_dp))
ironlake_edp_backlight_off(dev);
intel_dp_sink_dpms(intel_dp, mode);
intel_dp_link_down(intel_dp);
if (is_edp(intel_dp))
ironlake_edp_panel_off(dev);
@ -999,6 +1033,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
} else {
if (is_edp(intel_dp))
ironlake_edp_panel_vdd_on(intel_dp);
intel_dp_sink_dpms(intel_dp, mode);
if (!(dp_reg & DP_PORT_EN)) {
intel_dp_start_link_train(intel_dp);
if (is_edp(intel_dp)) {
@ -1010,7 +1045,31 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (is_edp(intel_dp))
ironlake_edp_backlight_on(dev);
}
intel_dp->dpms_mode = mode;
}
/*
* Native read with retry for link status and receiver capability reads for
* cases where the sink may still be asleep.
*/
static bool
intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address,
uint8_t *recv, int recv_bytes)
{
int ret, i;
/*
* Sinks are *supposed* to come up within 1ms from an off state,
* but we're also supposed to retry 3 times per the spec.
*/
for (i = 0; i < 3; i++) {
ret = intel_dp_aux_native_read(intel_dp, address, recv,
recv_bytes);
if (ret == recv_bytes)
return true;
msleep(1);
}
return false;
}
/*
@ -1020,14 +1079,10 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
static bool
intel_dp_get_link_status(struct intel_dp *intel_dp)
{
int ret;
ret = intel_dp_aux_native_read(intel_dp,
DP_LANE0_1_STATUS,
intel_dp->link_status, DP_LINK_STATUS_SIZE);
if (ret != DP_LINK_STATUS_SIZE)
return false;
return true;
return intel_dp_aux_native_read_retry(intel_dp,
DP_LANE0_1_STATUS,
intel_dp->link_status,
DP_LINK_STATUS_SIZE);
}
static uint8_t
@ -1516,6 +1571,8 @@ intel_dp_link_down(struct intel_dp *intel_dp)
static void
intel_dp_check_link_status(struct intel_dp *intel_dp)
{
int ret;
if (!intel_dp->base.base.crtc)
return;
@ -1524,6 +1581,15 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
return;
}
/* Try to read receiver status if the link appears to be up */
ret = intel_dp_aux_native_read(intel_dp,
0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd));
if (ret != sizeof(intel_dp->dpcd)) {
intel_dp_link_down(intel_dp);
return;
}
if (!intel_channel_eq_ok(intel_dp)) {
intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
@ -1534,6 +1600,7 @@ static enum drm_connector_status
ironlake_dp_detect(struct intel_dp *intel_dp)
{
enum drm_connector_status status;
bool ret;
/* Can't disconnect eDP, but you can close the lid... */
if (is_edp(intel_dp)) {
@ -1544,13 +1611,11 @@ ironlake_dp_detect(struct intel_dp *intel_dp)
}
status = connector_status_disconnected;
if (intel_dp_aux_native_read(intel_dp,
0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd))
== sizeof(intel_dp->dpcd)) {
if (intel_dp->dpcd[0] != 0)
status = connector_status_connected;
}
ret = intel_dp_aux_native_read_retry(intel_dp,
0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd));
if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0)
status = connector_status_connected;
DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
return status;
@ -1587,7 +1652,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
{
if (intel_dp->dpcd[0] != 0)
if (intel_dp->dpcd[DP_DPCD_REV] != 0)
status = connector_status_connected;
}
@ -1791,8 +1856,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder)
{
struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
if (intel_dp->dpms_mode == DRM_MODE_DPMS_ON)
intel_dp_check_link_status(intel_dp);
intel_dp_check_link_status(intel_dp);
}
/* Return which DP Port should be selected for Transcoder DP control */
@ -1860,7 +1924,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
return;
intel_dp->output_reg = output_reg;
intel_dp->dpms_mode = -1;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) {
@ -1955,8 +2018,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
sizeof(intel_dp->dpcd));
ironlake_edp_panel_vdd_off(intel_dp);
if (ret == sizeof(intel_dp->dpcd)) {
if (intel_dp->dpcd[0] >= 0x11)
dev_priv->no_aux_handshake = intel_dp->dpcd[3] &
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
dev_priv->no_aux_handshake =
intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
} else {
/* if this fails, presume the device is a ghost */

View File

@ -371,7 +371,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->vram.flags_valid = nv50_vram_flags_valid;
break;
case 0xC0:
case 0xD0:
engine->instmem.init = nvc0_instmem_init;
engine->instmem.takedown = nvc0_instmem_takedown;
engine->instmem.suspend = nvc0_instmem_suspend;
@ -923,7 +922,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->card_type = NV_50;
break;
case 0xc0:
case 0xd0:
dev_priv->card_type = NV_C0;
break;
default:

View File

@ -2248,7 +2248,10 @@ int evergreen_mc_init(struct radeon_device *rdev)
/* Get VRAM informations */
rdev->mc.vram_is_ddr = true;
tmp = RREG32(MC_ARB_RAMCFG);
if (rdev->flags & RADEON_IS_IGP)
tmp = RREG32(FUS_MC_ARB_RAMCFG);
else
tmp = RREG32(MC_ARB_RAMCFG);
if (tmp & CHANSIZE_OVERRIDE) {
chansize = 16;
} else if (tmp & CHANSIZE_MASK) {

View File

@ -320,7 +320,7 @@
#define CGTS_USER_TCC_DISABLE 0x914C
#define TCC_DISABLE_MASK 0xFFFF0000
#define TCC_DISABLE_SHIFT 16
#define CGTS_SM_CTRL_REG 0x915C
#define CGTS_SM_CTRL_REG 0x9150
#define OVERRIDE (1 << 21)
#define TA_CNTL_AUX 0x9508

View File

@ -104,7 +104,7 @@ static bool radeon_read_bios(struct radeon_device *rdev)
static bool radeon_atrm_get_bios(struct radeon_device *rdev)
{
int ret;
int size = 64 * 1024;
int size = 256 * 1024;
int i;
if (!radeon_atrm_supported(rdev->pdev))

View File

@ -575,6 +575,12 @@ static void rv770_program_channel_remap(struct radeon_device *rdev)
else
tcp_chan_steer = 0x00fac688;
/* RV770 CE has special chremap setup */
if (rdev->pdev->device == 0x944e) {
tcp_chan_steer = 0x00b08b08;
mc_shared_chremap = 0x00b08b08;
}
WREG32(TCP_CHAN_STEER, tcp_chan_steer);
WREG32(MC_SHARED_CHREMAP, mc_shared_chremap);
}

View File

@ -333,7 +333,7 @@ config SENSORS_F71882FG
F71858FG
F71862FG
F71863FG
F71869F/E
F71869F/E/A
F71882FG
F71883FG
F71889FG/ED/A

View File

@ -32,6 +32,7 @@ static int adm1275_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int config;
int ret;
struct pmbus_driver_info *info;
if (!i2c_check_functionality(client->adapter,
@ -43,8 +44,10 @@ static int adm1275_probe(struct i2c_client *client,
return -ENOMEM;
config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
if (config < 0)
return config;
if (config < 0) {
ret = config;
goto err_mem;
}
info->pages = 1;
info->direct[PSC_VOLTAGE_IN] = true;
@ -76,7 +79,14 @@ static int adm1275_probe(struct i2c_client *client,
else
info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
return pmbus_do_probe(client, id, info);
ret = pmbus_do_probe(client, id, info);
if (ret)
goto err_mem;
return 0;
err_mem:
kfree(info);
return ret;
}
static int adm1275_remove(struct i2c_client *client)

View File

@ -78,8 +78,9 @@ static u16 emc6w201_read16(struct i2c_client *client, u8 reg)
lsb = i2c_smbus_read_byte_data(client, reg);
msb = i2c_smbus_read_byte_data(client, reg + 1);
if (lsb < 0 || msb < 0) {
dev_err(&client->dev, "16-bit read failed at 0x%02x\n", reg);
if (unlikely(lsb < 0 || msb < 0)) {
dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
16, "read", reg);
return 0xFFFF; /* Arbitrary value */
}
@ -95,10 +96,39 @@ static int emc6w201_write16(struct i2c_client *client, u8 reg, u16 val)
int err;
err = i2c_smbus_write_byte_data(client, reg, val & 0xff);
if (!err)
if (likely(!err))
err = i2c_smbus_write_byte_data(client, reg + 1, val >> 8);
if (err < 0)
dev_err(&client->dev, "16-bit write failed at 0x%02x\n", reg);
if (unlikely(err < 0))
dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
16, "write", reg);
return err;
}
/* Read 8-bit value from register */
static u8 emc6w201_read8(struct i2c_client *client, u8 reg)
{
int val;
val = i2c_smbus_read_byte_data(client, reg);
if (unlikely(val < 0)) {
dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
8, "read", reg);
return 0x00; /* Arbitrary value */
}
return val;
}
/* Write 8-bit value to register */
static int emc6w201_write8(struct i2c_client *client, u8 reg, u8 val)
{
int err;
err = i2c_smbus_write_byte_data(client, reg, val);
if (unlikely(err < 0))
dev_err(&client->dev, "%d-bit %s failed at 0x%02x\n",
8, "write", reg);
return err;
}
@ -114,25 +144,25 @@ static struct emc6w201_data *emc6w201_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
for (nr = 0; nr < 6; nr++) {
data->in[input][nr] =
i2c_smbus_read_byte_data(client,
emc6w201_read8(client,
EMC6W201_REG_IN(nr));
data->in[min][nr] =
i2c_smbus_read_byte_data(client,
emc6w201_read8(client,
EMC6W201_REG_IN_LOW(nr));
data->in[max][nr] =
i2c_smbus_read_byte_data(client,
emc6w201_read8(client,
EMC6W201_REG_IN_HIGH(nr));
}
for (nr = 0; nr < 6; nr++) {
data->temp[input][nr] =
i2c_smbus_read_byte_data(client,
emc6w201_read8(client,
EMC6W201_REG_TEMP(nr));
data->temp[min][nr] =
i2c_smbus_read_byte_data(client,
emc6w201_read8(client,
EMC6W201_REG_TEMP_LOW(nr));
data->temp[max][nr] =
i2c_smbus_read_byte_data(client,
emc6w201_read8(client,
EMC6W201_REG_TEMP_HIGH(nr));
}
@ -192,7 +222,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
mutex_lock(&data->update_lock);
data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255);
err = i2c_smbus_write_byte_data(client, reg, data->in[sf][nr]);
err = emc6w201_write8(client, reg, data->in[sf][nr]);
mutex_unlock(&data->update_lock);
return err < 0 ? err : count;
@ -229,7 +259,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
mutex_lock(&data->update_lock);
data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128);
err = i2c_smbus_write_byte_data(client, reg, data->temp[sf][nr]);
err = emc6w201_write8(client, reg, data->temp[sf][nr]);
mutex_unlock(&data->update_lock);
return err < 0 ? err : count;
@ -444,7 +474,7 @@ static int emc6w201_detect(struct i2c_client *client,
/* Check configuration */
config = i2c_smbus_read_byte_data(client, EMC6W201_REG_CONFIG);
if ((config & 0xF4) != 0x04)
if (config < 0 || (config & 0xF4) != 0x04)
return -ENODEV;
if (!(config & 0x01)) {
dev_err(&client->dev, "Monitoring not enabled\n");

View File

@ -52,6 +52,7 @@
#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */
#define SIO_F71869_ID 0x0814 /* Chipset ID */
#define SIO_F71869A_ID 0x1007 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */
#define SIO_F71889_ID 0x0723 /* Chipset ID */
#define SIO_F71889E_ID 0x0909 /* Chipset ID */
@ -108,8 +109,8 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
f71889ed, f71889a, f8000, f81865f };
enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71869a, f71882fg,
f71889fg, f71889ed, f71889a, f8000, f81865f };
static const char *f71882fg_names[] = {
"f71808e",
@ -117,6 +118,7 @@ static const char *f71882fg_names[] = {
"f71858fg",
"f71862fg",
"f71869", /* Both f71869f and f71869e, reg. compatible and same id */
"f71869a",
"f71882fg",
"f71889fg", /* f81801u too, same id */
"f71889ed",
@ -131,6 +133,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
[f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
[f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
@ -145,6 +148,7 @@ static const char f71882fg_has_in1_alarm[] = {
[f71858fg] = 0,
[f71862fg] = 0,
[f71869] = 0,
[f71869a] = 0,
[f71882fg] = 1,
[f71889fg] = 1,
[f71889ed] = 1,
@ -159,6 +163,7 @@ static const char f71882fg_fan_has_beep[] = {
[f71858fg] = 0,
[f71862fg] = 1,
[f71869] = 1,
[f71869a] = 1,
[f71882fg] = 1,
[f71889fg] = 1,
[f71889ed] = 1,
@ -173,6 +178,7 @@ static const char f71882fg_nr_fans[] = {
[f71858fg] = 3,
[f71862fg] = 3,
[f71869] = 3,
[f71869a] = 3,
[f71882fg] = 4,
[f71889fg] = 3,
[f71889ed] = 3,
@ -187,6 +193,7 @@ static const char f71882fg_temp_has_beep[] = {
[f71858fg] = 0,
[f71862fg] = 1,
[f71869] = 1,
[f71869a] = 1,
[f71882fg] = 1,
[f71889fg] = 1,
[f71889ed] = 1,
@ -201,6 +208,7 @@ static const char f71882fg_nr_temps[] = {
[f71858fg] = 3,
[f71862fg] = 3,
[f71869] = 3,
[f71869a] = 3,
[f71882fg] = 3,
[f71889fg] = 3,
[f71889ed] = 3,
@ -2243,6 +2251,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
case f71808e:
case f71808a:
case f71869:
case f71869a:
/* These always have signed auto point temps */
data->auto_point_temp_signed = 1;
/* Fall through to select correct fan/pwm reg bank! */
@ -2305,6 +2314,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
case f71808e:
case f71808a:
case f71869:
case f71869a:
case f71889fg:
case f71889ed:
case f71889a:
@ -2528,6 +2538,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
case SIO_F71869_ID:
sio_data->type = f71869;
break;
case SIO_F71869A_ID:
sio_data->type = f71869a;
break;
case SIO_F71882_ID:
sio_data->type = f71882fg;
break;
@ -2662,7 +2675,7 @@ static void __exit f71882fg_exit(void)
}
MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
MODULE_AUTHOR("Hans Edgington, Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
module_init(f71882fg_init);

View File

@ -202,7 +202,7 @@ static struct vrm_model vrm_models[] = {
{X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */
{X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */
{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nemiah */
{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nehemiah */
{X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */
{X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */
{X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */

View File

@ -47,12 +47,14 @@ static void pmbus_find_sensor_groups(struct i2c_client *client,
if (info->func[0]
&& pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT))
info->func[0] |= PMBUS_HAVE_STATUS_INPUT;
if (pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_12) &&
pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
info->func[0] |= PMBUS_HAVE_FAN12;
if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12))
info->func[0] |= PMBUS_HAVE_STATUS_FAN12;
}
if (pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) &&
pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
info->func[0] |= PMBUS_HAVE_FAN34;
if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34))
info->func[0] |= PMBUS_HAVE_STATUS_FAN34;
@ -63,6 +65,10 @@ static void pmbus_find_sensor_groups(struct i2c_client *client,
PMBUS_STATUS_TEMPERATURE))
info->func[0] |= PMBUS_HAVE_STATUS_TEMP;
}
if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2))
info->func[0] |= PMBUS_HAVE_TEMP2;
if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3))
info->func[0] |= PMBUS_HAVE_TEMP3;
/* Sensors detected on all pages */
for (page = 0; page < info->pages; page++) {

View File

@ -1430,14 +1430,9 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
/*
* Bail out if status register or PMBus revision register
* does not exist.
*/
if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0
|| i2c_smbus_read_byte_data(client, PMBUS_REVISION) < 0) {
dev_err(&client->dev,
"Status or revision register not found\n");
/* Bail out if PMBus status register does not exist. */
if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) {
dev_err(&client->dev, "PMBus status register not found\n");
ret = -ENODEV;
goto out_data;
}

View File

@ -887,7 +887,7 @@ static void __exit sch5627_exit(void)
}
MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");
MODULE_AUTHOR("Hans de Goede (hdegoede@redhat.com)");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_LICENSE("GPL");
module_init(sch5627_init);

View File

@ -234,7 +234,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv)
if (taos->state != TAOS_STATE_IDLE) {
err = -ENODEV;
dev_dbg(&serio->dev, "TAOS EVM reset failed (state=%d, "
dev_err(&serio->dev, "TAOS EVM reset failed (state=%d, "
"pos=%d)\n", taos->state, taos->pos);
goto exit_close;
}
@ -255,7 +255,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv)
msecs_to_jiffies(250));
if (taos->state != TAOS_STATE_IDLE) {
err = -ENODEV;
dev_err(&adapter->dev, "Echo off failed "
dev_err(&serio->dev, "TAOS EVM echo off failed "
"(state=%d)\n", taos->state);
goto exit_close;
}
@ -263,7 +263,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv)
err = i2c_add_adapter(adapter);
if (err)
goto exit_close;
dev_dbg(&serio->dev, "Connected to TAOS EVM\n");
dev_info(&serio->dev, "Connected to TAOS EVM\n");
taos->client = taos_instantiate_device(adapter);
return 0;
@ -288,7 +288,7 @@ static void taos_disconnect(struct serio *serio)
serio_set_drvdata(serio, NULL);
kfree(taos);
dev_dbg(&serio->dev, "Disconnected from TAOS EVM\n");
dev_info(&serio->dev, "Disconnected from TAOS EVM\n");
}
static struct serio_device_id taos_serio_ids[] = {

View File

@ -201,10 +201,11 @@ static int pca954x_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
/* Read the mux register at addr to verify
* that the mux is in fact present.
/* Write the mux register at addr to verify
* that the mux is in fact present. This also
* initializes the mux to disconnected state.
*/
if (i2c_smbus_read_byte(client) < 0) {
if (i2c_smbus_write_byte(client, 0) < 0) {
dev_warn(&client->dev, "probe failed\n");
goto exit_free;
}

View File

@ -3641,7 +3641,8 @@ static struct kobj_type cm_port_obj_type = {
static char *cm_devnode(struct device *dev, mode_t *mode)
{
*mode = 0666;
if (mode)
*mode = 0666;
return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}

View File

@ -826,7 +826,8 @@ static void ib_uverbs_remove_one(struct ib_device *device)
static char *uverbs_devnode(struct device *dev, mode_t *mode)
{
*mode = 0666;
if (mode)
*mode = 0666;
return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
}

View File

@ -339,9 +339,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
(FIR_OP_UA << FIR_OP1_SHIFT) |
(FIR_OP_RBW << FIR_OP2_SHIFT));
out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
/* 5 bytes for manuf, device and exts */
out_be32(&lbc->fbcr, 5);
elbc_fcm_ctrl->read_bytes = 5;
/* nand_get_flash_type() reads 8 bytes of entire ID string */
out_be32(&lbc->fbcr, 8);
elbc_fcm_ctrl->read_bytes = 8;
elbc_fcm_ctrl->use_mdr = 1;
elbc_fcm_ctrl->mdr = 0;

View File

@ -3416,7 +3416,8 @@ config NETCONSOLE
config NETCONSOLE_DYNAMIC
bool "Dynamic reconfiguration of logging targets"
depends on NETCONSOLE && SYSFS && CONFIGFS_FS
depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \
!(NETCONSOLE=y && CONFIGFS_FS=m)
help
This option enables the ability to dynamically reconfigure target
parameters (interface, IP addresses, port numbers, MAC addresses)

View File

@ -49,6 +49,7 @@
#include <linux/zlib.h>
#include <linux/io.h>
#include <linux/stringify.h>
#include <linux/vmalloc.h>
#define BNX2X_MAIN
#include "bnx2x.h"
@ -4537,8 +4538,7 @@ static int bnx2x_gunzip_init(struct bnx2x *bp)
if (bp->strm == NULL)
goto gunzip_nomem2;
bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(),
GFP_KERNEL);
bp->strm->workspace = vmalloc(zlib_inflate_workspacesize());
if (bp->strm->workspace == NULL)
goto gunzip_nomem3;
@ -4562,7 +4562,7 @@ gunzip_nomem1:
static void bnx2x_gunzip_end(struct bnx2x *bp)
{
if (bp->strm) {
kfree(bp->strm->workspace);
vfree(bp->strm->workspace);
kfree(bp->strm);
bp->strm = NULL;
}

View File

@ -36,7 +36,7 @@ config CAN_SLCAN
config CAN_DEV
tristate "Platform CAN drivers with Netlink support"
depends on CAN
default Y
default y
---help---
Enables the common framework for platform CAN drivers with Netlink
support. This is the standard library for CAN drivers.
@ -45,7 +45,7 @@ config CAN_DEV
config CAN_CALC_BITTIMING
bool "CAN bit-timing calculation"
depends on CAN_DEV
default Y
default y
---help---
If enabled, CAN bit-timing parameters will be calculated for the
bit-rate specified via Netlink argument "bitrate" when the device

View File

@ -2026,7 +2026,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else
skb_checksum_none_assert(skb);
skb_record_rx_queue(skb, qs - &adap->sge.qs[0]);
skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]);
if (unlikely(p->vlan_valid)) {
struct vlan_group *grp = pi->vlan_grp;
@ -2145,7 +2145,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
if (!complete)
return;
skb_record_rx_queue(skb, qs - &adap->sge.qs[0]);
skb_record_rx_queue(skb, qs - &adap->sge.qs[pi->first_qset]);
if (unlikely(cpl->vlan_valid)) {
struct vlan_group *grp = pi->vlan_grp;

View File

@ -305,7 +305,7 @@ static void z_decomp_free(void *arg)
if (state) {
zlib_inflateEnd(&state->strm);
kfree(state->strm.workspace);
vfree(state->strm.workspace);
kfree(state);
}
}
@ -345,8 +345,7 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len)
state->w_size = w_size;
state->strm.next_out = NULL;
state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
GFP_KERNEL|__GFP_REPEAT);
state->strm.workspace = vmalloc(zlib_inflate_workspacesize());
if (state->strm.workspace == NULL)
goto out_free;

View File

@ -742,7 +742,7 @@ static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
msleep(2);
for (i = 0; i < 5; i++) {
udelay(100);
if (!(RTL_R32(ERIDR) & ERIAR_FLAG))
if (!(RTL_R32(ERIAR) & ERIAR_FLAG))
break;
}

View File

@ -378,7 +378,7 @@ static int rionet_close(struct net_device *ndev)
static void rionet_remove(struct rio_dev *rdev)
{
struct net_device *ndev = NULL;
struct net_device *ndev = rio_get_drvdata(rdev);
struct rionet_peer *peer, *tmp;
free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ?
@ -433,22 +433,12 @@ static const struct net_device_ops rionet_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
};
static int rionet_setup_netdev(struct rio_mport *mport)
static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
{
int rc = 0;
struct net_device *ndev = NULL;
struct rionet_private *rnet;
u16 device_id;
/* Allocate our net_device structure */
ndev = alloc_etherdev(sizeof(struct rionet_private));
if (ndev == NULL) {
printk(KERN_INFO "%s: could not allocate ethernet device.\n",
DRV_NAME);
rc = -ENOMEM;
goto out;
}
rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
mport->sys_size ? __fls(sizeof(void *)) + 4 : 0);
if (!rionet_active) {
@ -504,11 +494,21 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
int rc = -ENODEV;
u32 lpef, lsrc_ops, ldst_ops;
struct rionet_peer *peer;
struct net_device *ndev = NULL;
/* If local device is not rionet capable, give up quickly */
if (!rionet_capable)
goto out;
/* Allocate our net_device structure */
ndev = alloc_etherdev(sizeof(struct rionet_private));
if (ndev == NULL) {
printk(KERN_INFO "%s: could not allocate ethernet device.\n",
DRV_NAME);
rc = -ENOMEM;
goto out;
}
/*
* First time through, make sure local device is rionet
* capable, setup netdev, and set flags so this is skipped
@ -529,7 +529,7 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
goto out;
}
rc = rionet_setup_netdev(rdev->net->hport);
rc = rionet_setup_netdev(rdev->net->hport, ndev);
rionet_check = 1;
}
@ -546,6 +546,8 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
list_add_tail(&peer->node, &rionet_peers);
}
rio_set_drvdata(rdev, ndev);
out:
return rc;
}

View File

@ -100,34 +100,42 @@ kalmia_send_init_packet(struct usbnet *dev, u8 *init_msg, u8 init_msg_len,
static int
kalmia_init_and_get_ethernet_addr(struct usbnet *dev, u8 *ethernet_addr)
{
char init_msg_1[] =
const static char init_msg_1[] =
{ 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00,
0x00, 0x00 };
char init_msg_2[] =
const static char init_msg_2[] =
{ 0x57, 0x50, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xf4,
0x00, 0x00 };
char receive_buf[28];
const static int buflen = 28;
char *usb_buf;
int status;
status = kalmia_send_init_packet(dev, init_msg_1, sizeof(init_msg_1)
/ sizeof(init_msg_1[0]), receive_buf, 24);
usb_buf = kmalloc(buflen, GFP_DMA | GFP_KERNEL);
if (!usb_buf)
return -ENOMEM;
memcpy(usb_buf, init_msg_1, 12);
status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_1)
/ sizeof(init_msg_1[0]), usb_buf, 24);
if (status != 0)
return status;
status = kalmia_send_init_packet(dev, init_msg_2, sizeof(init_msg_2)
/ sizeof(init_msg_2[0]), receive_buf, 28);
memcpy(usb_buf, init_msg_2, 12);
status = kalmia_send_init_packet(dev, usb_buf, sizeof(init_msg_2)
/ sizeof(init_msg_2[0]), usb_buf, 28);
if (status != 0)
return status;
memcpy(ethernet_addr, receive_buf + 10, ETH_ALEN);
memcpy(ethernet_addr, usb_buf + 10, ETH_ALEN);
kfree(usb_buf);
return status;
}
static int
kalmia_bind(struct usbnet *dev, struct usb_interface *intf)
{
u8 status;
int status;
u8 ethernet_addr[ETH_ALEN];
/* Don't bind to AT command interface */
@ -190,7 +198,8 @@ kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
dev_kfree_skb_any(skb);
skb = skb2;
done: header_start = skb_push(skb, KALMIA_HEADER_LENGTH);
done:
header_start = skb_push(skb, KALMIA_HEADER_LENGTH);
ether_type_1 = header_start[KALMIA_HEADER_LENGTH + 12];
ether_type_2 = header_start[KALMIA_HEADER_LENGTH + 13];
@ -201,9 +210,8 @@ kalmia_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
header_start[0] = 0x57;
header_start[1] = 0x44;
content_len = skb->len - KALMIA_HEADER_LENGTH;
header_start[2] = (content_len & 0xff); /* low byte */
header_start[3] = (content_len >> 8); /* high byte */
put_unaligned_le16(content_len, &header_start[2]);
header_start[4] = ether_type_1;
header_start[5] = ether_type_2;
@ -231,13 +239,13 @@ kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
* Our task here is to strip off framing, leaving skb with one
* data frame for the usbnet framework code to process.
*/
const u8 HEADER_END_OF_USB_PACKET[] =
const static u8 HEADER_END_OF_USB_PACKET[] =
{ 0x57, 0x5a, 0x00, 0x00, 0x08, 0x00 };
const u8 EXPECTED_UNKNOWN_HEADER_1[] =
const static u8 EXPECTED_UNKNOWN_HEADER_1[] =
{ 0x57, 0x43, 0x1e, 0x00, 0x15, 0x02 };
const u8 EXPECTED_UNKNOWN_HEADER_2[] =
const static u8 EXPECTED_UNKNOWN_HEADER_2[] =
{ 0x57, 0x50, 0x0e, 0x00, 0x00, 0x00 };
u8 i = 0;
int i = 0;
/* incomplete header? */
if (skb->len < KALMIA_HEADER_LENGTH)
@ -285,7 +293,7 @@ kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
/* subtract start header and end header */
usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH);
ether_packet_length = header_start[2] + (header_start[3] << 8);
ether_packet_length = get_unaligned_le16(&header_start[2]);
skb_pull(skb, KALMIA_HEADER_LENGTH);
/* Some small packets misses end marker */

View File

@ -331,17 +331,7 @@ static const struct usb_device_id products [] = {
ZAURUS_MASTER_INTERFACE,
.driver_info = ZAURUS_PXA_INFO,
},
/* At least some of the newest PXA units have very different lies about
* their standards support: they claim to be cell phones offering
* direct access to their radios! (No, they don't conform to CDC MDLM.)
*/
{
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &bogus_mdlm_info,
}, {
/* Motorola MOTOMAGX phones */
USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM,
USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),

View File

@ -1624,6 +1624,16 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
pci_read_config_byte(pdev, 0x8, &revisionid);
pci_read_config_word(pdev, 0x3C, &irqline);
/* PCI ID 0x10ec:0x8192 occurs for both RTL8192E, which uses
* r8192e_pci, and RTL8192SE, which uses this driver. If the
* revision ID is RTL_PCI_REVISION_ID_8192PCIE (0x01), then
* the correct driver is r8192e_pci, thus this routine should
* return false.
*/
if (deviceid == RTL_PCI_8192SE_DID &&
revisionid == RTL_PCI_REVISION_ID_8192PCIE)
return false;
if (deviceid == RTL_PCI_8192_DID ||
deviceid == RTL_PCI_0044_DID ||
deviceid == RTL_PCI_0047_DID ||
@ -1856,7 +1866,8 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
pci_write_config_byte(pdev, 0x04, 0x07);
/* find adapter */
_rtl_pci_find_adapter(pdev, hw);
if (!_rtl_pci_find_adapter(pdev, hw))
goto fail3;
/* Init IO handler */
_rtl_pci_io_handler_init(&pdev->dev, hw);

View File

@ -53,6 +53,8 @@ MODULE_FIRMWARE("rtlwifi/rtl8192cufw.bin");
static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
const struct firmware *firmware;
int err;
rtlpriv->dm.dm_initialgain_enable = 1;
rtlpriv->dm.dm_flag = 0;
@ -64,6 +66,24 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw)
("Can't alloc buffer for fw.\n"));
return 1;
}
/* request fw */
err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
rtlpriv->io.dev);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("Failed to request firmware!\n"));
return 1;
}
if (firmware->size > 0x4000) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("Firmware is too big!\n"));
release_firmware(firmware);
return 1;
}
memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
rtlpriv->rtlhal.fwsize = firmware->size;
release_firmware(firmware);
return 0;
}

View File

@ -830,6 +830,19 @@ config SCSI_GDTH
To compile this driver as a module, choose M here: the
module will be called gdth.
config SCSI_ISCI
tristate "Intel(R) C600 Series Chipset SAS Controller"
depends on PCI && SCSI
depends on X86
# (temporary): known alpha quality driver
depends on EXPERIMENTAL
select SCSI_SAS_LIBSAS
---help---
This driver supports the 6Gb/s SAS capabilities of the storage
control unit found in the Intel(R) C600 series chipset.
The experimental tag will be removed after the driver exits alpha
config SCSI_GENERIC_NCR5380
tristate "Generic NCR5380/53c400 SCSI PIO support"
depends on ISA && SCSI

View File

@ -73,6 +73,7 @@ obj-$(CONFIG_SCSI_AACRAID) += aacraid/
obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_PM8001) += pm8001/
obj-$(CONFIG_SCSI_ISCI) += isci/
obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o

View File

@ -1037,6 +1037,7 @@ static void complete_scsi_command(struct CommandList *cp)
unsigned char sense_key;
unsigned char asc; /* additional sense code */
unsigned char ascq; /* additional sense code qualifier */
unsigned long sense_data_size;
ei = cp->err_info;
cmd = (struct scsi_cmnd *) cp->scsi_cmd;
@ -1051,10 +1052,14 @@ static void complete_scsi_command(struct CommandList *cp)
cmd->result |= ei->ScsiStatus;
/* copy the sense data whether we need to or not. */
memcpy(cmd->sense_buffer, ei->SenseInfo,
ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
SCSI_SENSE_BUFFERSIZE :
ei->SenseLen);
if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo))
sense_data_size = SCSI_SENSE_BUFFERSIZE;
else
sense_data_size = sizeof(ei->SenseInfo);
if (ei->SenseLen < sense_data_size)
sense_data_size = ei->SenseLen;
memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size);
scsi_set_resid(cmd, ei->ResidualCnt);
if (ei->CommandStatus == 0) {
@ -2580,7 +2585,8 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
c->SG[0].Ext = 0; /* we are not chaining*/
}
hpsa_scsi_do_simple_cmd_core(h, c);
hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL);
if (iocommand.buf_size > 0)
hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL);
check_ioctl_unit_attention(h, c);
/* Copy the error information out */

View File

@ -4306,8 +4306,8 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
spin_lock_irqsave(vhost->host->host_lock, flags);
if (rc == H_CLOSED)
vio_enable_interrupts(to_vio_dev(vhost->dev));
else if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
(rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
(rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc);
}

View File

@ -0,0 +1,8 @@
obj-$(CONFIG_SCSI_ISCI) += isci.o
isci-objs := init.o phy.o request.o \
remote_device.o port.o \
host.o task.o probe_roms.o \
remote_node_context.o \
remote_node_table.o \
unsolicited_frame_control.o \
port_config.o \

View File

@ -0,0 +1,19 @@
# Makefile for create_fw
#
CC=gcc
CFLAGS=-c -Wall -O2 -g
LDFLAGS=
SOURCES=create_fw.c
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=create_fw
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $@
.c.o:
$(CC) $(CFLAGS) $< -O $@
clean:
rm -f *.o $(EXECUTABLE)

View File

@ -0,0 +1,36 @@
This defines the temporary binary blow we are to pass to the SCU
driver to emulate the binary firmware that we will eventually be
able to access via NVRAM on the SCU controller.
The current size of the binary blob is expected to be 149 bytes or larger
Header Types:
0x1: Phy Masks
0x2: Phy Gens
0x3: SAS Addrs
0xff: End of Data
ID string - u8[12]: "#SCU MAGIC#\0"
Version - u8: 1
SubVersion - u8: 0
Header Type - u8: 0x1
Size - u8: 8
Phy Mask - u32[8]
Header Type - u8: 0x2
Size - u8: 8
Phy Gen - u32[8]
Header Type - u8: 0x3
Size - u8: 8
Sas Addr - u64[8]
Header Type - u8: 0xf
==============================================================================
Place isci_firmware.bin in /lib/firmware
Be sure to recreate the initramfs image to include the firmware.

View File

@ -0,0 +1,99 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <asm/types.h>
#include <strings.h>
#include <stdint.h>
#include "create_fw.h"
#include "../probe_roms.h"
int write_blob(struct isci_orom *isci_orom)
{
FILE *fd;
int err;
size_t count;
fd = fopen(blob_name, "w+");
if (!fd) {
perror("Open file for write failed");
fclose(fd);
return -EIO;
}
count = fwrite(isci_orom, sizeof(struct isci_orom), 1, fd);
if (count != 1) {
perror("Write data failed");
fclose(fd);
return -EIO;
}
fclose(fd);
return 0;
}
void set_binary_values(struct isci_orom *isci_orom)
{
int ctrl_idx, phy_idx, port_idx;
/* setting OROM signature */
strncpy(isci_orom->hdr.signature, sig, strlen(sig));
isci_orom->hdr.version = version;
isci_orom->hdr.total_block_length = sizeof(struct isci_orom);
isci_orom->hdr.hdr_length = sizeof(struct sci_bios_oem_param_block_hdr);
isci_orom->hdr.num_elements = num_elements;
for (ctrl_idx = 0; ctrl_idx < 2; ctrl_idx++) {
isci_orom->ctrl[ctrl_idx].controller.mode_type = mode_type;
isci_orom->ctrl[ctrl_idx].controller.max_concurrent_dev_spin_up =
max_num_concurrent_dev_spin_up;
isci_orom->ctrl[ctrl_idx].controller.do_enable_ssc =
enable_ssc;
for (port_idx = 0; port_idx < 4; port_idx++)
isci_orom->ctrl[ctrl_idx].ports[port_idx].phy_mask =
phy_mask[ctrl_idx][port_idx];
for (phy_idx = 0; phy_idx < 4; phy_idx++) {
isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.high =
(__u32)(sas_addr[ctrl_idx][phy_idx] >> 32);
isci_orom->ctrl[ctrl_idx].phys[phy_idx].sas_address.low =
(__u32)(sas_addr[ctrl_idx][phy_idx]);
isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control0 =
afe_tx_amp_control0;
isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control1 =
afe_tx_amp_control1;
isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control2 =
afe_tx_amp_control2;
isci_orom->ctrl[ctrl_idx].phys[phy_idx].afe_tx_amp_control3 =
afe_tx_amp_control3;
}
}
}
int main(void)
{
int err;
struct isci_orom *isci_orom;
isci_orom = malloc(sizeof(struct isci_orom));
memset(isci_orom, 0, sizeof(struct isci_orom));
set_binary_values(isci_orom);
err = write_blob(isci_orom);
if (err < 0) {
free(isci_orom);
return err;
}
free(isci_orom);
return 0;
}

View File

@ -0,0 +1,77 @@
#ifndef _CREATE_FW_H_
#define _CREATE_FW_H_
#include "../probe_roms.h"
/* we are configuring for 2 SCUs */
static const int num_elements = 2;
/*
* For all defined arrays:
* elements 0-3 are for SCU0, ports 0-3
* elements 4-7 are for SCU1, ports 0-3
*
* valid configurations for one SCU are:
* P0 P1 P2 P3
* ----------------
* 0xF,0x0,0x0,0x0 # 1 x4 port
* 0x3,0x0,0x4,0x8 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are each x1
* # ports
* 0x1,0x2,0xC,0x0 # Phys 0 and 1 are each x1 ports, phy 2 and phy 3 are a x2
* # port
* 0x3,0x0,0xC,0x0 # Phys 0 and 1 are a x2 port, phy 2 and phy 3 are a x2 port
* 0x1,0x2,0x4,0x8 # Each phy is a x1 port (this is the default configuration)
*
* if there is a port/phy on which you do not wish to override the default
* values, use the value assigned to UNINIT_PARAM (255).
*/
/* discovery mode type (port auto config mode by default ) */
/*
* if there is a port/phy on which you do not wish to override the default
* values, use the value "0000000000000000". SAS address of zero's is
* considered invalid and will not be used.
*/
#ifdef MPC
static const int mode_type = SCIC_PORT_MANUAL_CONFIGURATION_MODE;
static const __u8 phy_mask[2][4] = { {1, 2, 4, 8},
{1, 2, 4, 8} };
static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFFF0000001ULL,
0x5FCFFFFFF0000002ULL,
0x5FCFFFFFF0000003ULL,
0x5FCFFFFFF0000004ULL },
{ 0x5FCFFFFFF0000005ULL,
0x5FCFFFFFF0000006ULL,
0x5FCFFFFFF0000007ULL,
0x5FCFFFFFF0000008ULL } };
#else /* APC (default) */
static const int mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
static const __u8 phy_mask[2][4];
static const unsigned long long sas_addr[2][4] = { { 0x5FCFFFFF00000001ULL,
0x5FCFFFFF00000001ULL,
0x5FCFFFFF00000001ULL,
0x5FCFFFFF00000001ULL },
{ 0x5FCFFFFF00000002ULL,
0x5FCFFFFF00000002ULL,
0x5FCFFFFF00000002ULL,
0x5FCFFFFF00000002ULL } };
#endif
/* Maximum number of concurrent device spin up */
static const int max_num_concurrent_dev_spin_up = 1;
/* enable of ssc operation */
static const int enable_ssc;
/* AFE_TX_AMP_CONTROL */
static const unsigned int afe_tx_amp_control0 = 0x000bdd08;
static const unsigned int afe_tx_amp_control1 = 0x000ffc00;
static const unsigned int afe_tx_amp_control2 = 0x000b7c09;
static const unsigned int afe_tx_amp_control3 = 0x000afc6e;
static const char blob_name[] = "isci_firmware.bin";
static const char sig[] = "ISCUOEMB";
static const unsigned char version = 0x10;
#endif

2751
drivers/scsi/isci/host.c Normal file

File diff suppressed because it is too large Load Diff

542
drivers/scsi/isci/host.h Normal file
View File

@ -0,0 +1,542 @@
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* BSD LICENSE
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SCI_HOST_H_
#define _SCI_HOST_H_
#include "remote_device.h"
#include "phy.h"
#include "isci.h"
#include "remote_node_table.h"
#include "registers.h"
#include "unsolicited_frame_control.h"
#include "probe_roms.h"
struct isci_request;
struct scu_task_context;
/**
* struct sci_power_control -
*
* This structure defines the fields for managing power control for direct
* attached disk devices.
*/
struct sci_power_control {
/**
* This field is set when the power control timer is running and cleared when
* it is not.
*/
bool timer_started;
/**
* Timer to control when the directed attached disks can consume power.
*/
struct sci_timer timer;
/**
* This field is used to keep track of how many phys are put into the
* requesters field.
*/
u8 phys_waiting;
/**
* This field is used to keep track of how many phys have been granted to consume power
*/
u8 phys_granted_power;
/**
* This field is an array of phys that we are waiting on. The phys are direct
* mapped into requesters via struct sci_phy.phy_index
*/
struct isci_phy *requesters[SCI_MAX_PHYS];
};
struct sci_port_configuration_agent;
typedef void (*port_config_fn)(struct isci_host *,
struct sci_port_configuration_agent *,
struct isci_port *, struct isci_phy *);
struct sci_port_configuration_agent {
u16 phy_configured_mask;
u16 phy_ready_mask;
struct {
u8 min_index;
u8 max_index;
} phy_valid_port_range[SCI_MAX_PHYS];
bool timer_pending;
port_config_fn link_up_handler;
port_config_fn link_down_handler;
struct sci_timer timer;
};
/**
* isci_host - primary host/controller object
* @timer: timeout start/stop operations
* @device_table: rni (hw remote node index) to remote device lookup table
* @available_remote_nodes: rni allocator
* @power_control: manage device spin up
* @io_request_sequence: generation number for tci's (task contexts)
* @task_context_table: hw task context table
* @remote_node_context_table: hw remote node context table
* @completion_queue: hw-producer driver-consumer communication ring
* @completion_queue_get: tracks the driver 'head' of the ring to notify hw
* @logical_port_entries: min({driver|silicon}-supported-port-count)
* @remote_node_entries: min({driver|silicon}-supported-node-count)
* @task_context_entries: min({driver|silicon}-supported-task-count)
* @phy_timer: phy startup timer
* @invalid_phy_mask: if an invalid_link_up notification is reported a bit for
* the phy index is set so further notifications are not
* made. Once the phy reports link up and is made part of a
* port then this bit is cleared.
*/
struct isci_host {
struct sci_base_state_machine sm;
/* XXX can we time this externally */
struct sci_timer timer;
/* XXX drop reference module params directly */
struct sci_user_parameters user_parameters;
/* XXX no need to be a union */
struct sci_oem_params oem_parameters;
struct sci_port_configuration_agent port_agent;
struct isci_remote_device *device_table[SCI_MAX_REMOTE_DEVICES];
struct sci_remote_node_table available_remote_nodes;
struct sci_power_control power_control;
u8 io_request_sequence[SCI_MAX_IO_REQUESTS];
struct scu_task_context *task_context_table;
dma_addr_t task_context_dma;
union scu_remote_node_context *remote_node_context_table;
u32 *completion_queue;
u32 completion_queue_get;
u32 logical_port_entries;
u32 remote_node_entries;
u32 task_context_entries;
struct sci_unsolicited_frame_control uf_control;
/* phy startup */
struct sci_timer phy_timer;
/* XXX kill */
bool phy_startup_timer_pending;
u32 next_phy_to_start;
/* XXX convert to unsigned long and use bitops */
u8 invalid_phy_mask;
/* TODO attempt dynamic interrupt coalescing scheme */
u16 interrupt_coalesce_number;
u32 interrupt_coalesce_timeout;
struct smu_registers __iomem *smu_registers;
struct scu_registers __iomem *scu_registers;
u16 tci_head;
u16 tci_tail;
u16 tci_pool[SCI_MAX_IO_REQUESTS];
int id; /* unique within a given pci device */
struct isci_phy phys[SCI_MAX_PHYS];
struct isci_port ports[SCI_MAX_PORTS + 1]; /* includes dummy port */
struct sas_ha_struct sas_ha;
spinlock_t state_lock;
struct pci_dev *pdev;
enum isci_status status;
#define IHOST_START_PENDING 0
#define IHOST_STOP_PENDING 1
unsigned long flags;
wait_queue_head_t eventq;
struct Scsi_Host *shost;
struct tasklet_struct completion_tasklet;
struct list_head requests_to_complete;
struct list_head requests_to_errorback;
spinlock_t scic_lock;
struct isci_request *reqs[SCI_MAX_IO_REQUESTS];
struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES];
};
/**
* enum sci_controller_states - This enumeration depicts all the states
* for the common controller state machine.
*/
enum sci_controller_states {
/**
* Simply the initial state for the base controller state machine.
*/
SCIC_INITIAL = 0,
/**
* This state indicates that the controller is reset. The memory for
* the controller is in it's initial state, but the controller requires
* initialization.
* This state is entered from the INITIAL state.
* This state is entered from the RESETTING state.
*/
SCIC_RESET,
/**
* This state is typically an action state that indicates the controller
* is in the process of initialization. In this state no new IO operations
* are permitted.
* This state is entered from the RESET state.
*/
SCIC_INITIALIZING,
/**
* This state indicates that the controller has been successfully
* initialized. In this state no new IO operations are permitted.
* This state is entered from the INITIALIZING state.
*/
SCIC_INITIALIZED,
/**
* This state indicates the the controller is in the process of becoming
* ready (i.e. starting). In this state no new IO operations are permitted.
* This state is entered from the INITIALIZED state.
*/
SCIC_STARTING,
/**
* This state indicates the controller is now ready. Thus, the user
* is able to perform IO operations on the controller.
* This state is entered from the STARTING state.
*/
SCIC_READY,
/**
* This state is typically an action state that indicates the controller
* is in the process of resetting. Thus, the user is unable to perform
* IO operations on the controller. A reset is considered destructive in
* most cases.
* This state is entered from the READY state.
* This state is entered from the FAILED state.
* This state is entered from the STOPPED state.
*/
SCIC_RESETTING,
/**
* This state indicates that the controller is in the process of stopping.
* In this state no new IO operations are permitted, but existing IO
* operations are allowed to complete.
* This state is entered from the READY state.
*/
SCIC_STOPPING,
/**
* This state indicates that the controller has successfully been stopped.
* In this state no new IO operations are permitted.
* This state is entered from the STOPPING state.
*/
SCIC_STOPPED,
/**
* This state indicates that the controller could not successfully be
* initialized. In this state no new IO operations are permitted.
* This state is entered from the INITIALIZING state.
* This state is entered from the STARTING state.
* This state is entered from the STOPPING state.
* This state is entered from the RESETTING state.
*/
SCIC_FAILED,
};
/**
* struct isci_pci_info - This class represents the pci function containing the
* controllers. Depending on PCI SKU, there could be up to 2 controllers in
* the PCI function.
*/
#define SCI_MAX_MSIX_INT (SCI_NUM_MSI_X_INT*SCI_MAX_CONTROLLERS)
struct isci_pci_info {
struct msix_entry msix_entries[SCI_MAX_MSIX_INT];
struct isci_host *hosts[SCI_MAX_CONTROLLERS];
struct isci_orom *orom;
};
static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev)
{
return pci_get_drvdata(pdev);
}
#define for_each_isci_host(id, ihost, pdev) \
for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
ihost = to_pci_info(pdev)->hosts[++id])
static inline enum isci_status isci_host_get_state(struct isci_host *isci_host)
{
return isci_host->status;
}
static inline void isci_host_change_state(struct isci_host *isci_host,
enum isci_status status)
{
unsigned long flags;
dev_dbg(&isci_host->pdev->dev,
"%s: isci_host = %p, state = 0x%x",
__func__,
isci_host,
status);
spin_lock_irqsave(&isci_host->state_lock, flags);
isci_host->status = status;
spin_unlock_irqrestore(&isci_host->state_lock, flags);
}
static inline void wait_for_start(struct isci_host *ihost)
{
wait_event(ihost->eventq, !test_bit(IHOST_START_PENDING, &ihost->flags));
}
static inline void wait_for_stop(struct isci_host *ihost)
{
wait_event(ihost->eventq, !test_bit(IHOST_STOP_PENDING, &ihost->flags));
}
static inline void wait_for_device_start(struct isci_host *ihost, struct isci_remote_device *idev)
{
wait_event(ihost->eventq, !test_bit(IDEV_START_PENDING, &idev->flags));
}
static inline void wait_for_device_stop(struct isci_host *ihost, struct isci_remote_device *idev)
{
wait_event(ihost->eventq, !test_bit(IDEV_STOP_PENDING, &idev->flags));
}
static inline struct isci_host *dev_to_ihost(struct domain_device *dev)
{
return dev->port->ha->lldd_ha;
}
/* we always use protocol engine group zero */
#define ISCI_PEG 0
/* see sci_controller_io_tag_allocate|free for how seq and tci are built */
#define ISCI_TAG(seq, tci) (((u16) (seq)) << 12 | tci)
/* these are returned by the hardware, so sanitize them */
#define ISCI_TAG_SEQ(tag) (((tag) >> 12) & (SCI_MAX_SEQ-1))
#define ISCI_TAG_TCI(tag) ((tag) & (SCI_MAX_IO_REQUESTS-1))
/* expander attached sata devices require 3 rnc slots */
static inline int sci_remote_device_node_count(struct isci_remote_device *idev)
{
struct domain_device *dev = idev->domain_dev;
if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) &&
!idev->is_direct_attached)
return SCU_STP_REMOTE_NODE_COUNT;
return SCU_SSP_REMOTE_NODE_COUNT;
}
/**
* sci_controller_clear_invalid_phy() -
*
* This macro will clear the bit in the invalid phy mask for this controller
* object. This is used to control messages reported for invalid link up
* notifications.
*/
#define sci_controller_clear_invalid_phy(controller, phy) \
((controller)->invalid_phy_mask &= ~(1 << (phy)->phy_index))
static inline struct device *sciphy_to_dev(struct isci_phy *iphy)
{
if (!iphy || !iphy->isci_port || !iphy->isci_port->isci_host)
return NULL;
return &iphy->isci_port->isci_host->pdev->dev;
}
static inline struct device *sciport_to_dev(struct isci_port *iport)
{
if (!iport || !iport->isci_host)
return NULL;
return &iport->isci_host->pdev->dev;
}
static inline struct device *scirdev_to_dev(struct isci_remote_device *idev)
{
if (!idev || !idev->isci_port || !idev->isci_port->isci_host)
return NULL;
return &idev->isci_port->isci_host->pdev->dev;
}
static inline bool is_a2(struct pci_dev *pdev)
{
if (pdev->revision < 4)
return true;
return false;
}
static inline bool is_b0(struct pci_dev *pdev)
{
if (pdev->revision == 4)
return true;
return false;
}
static inline bool is_c0(struct pci_dev *pdev)
{
if (pdev->revision >= 5)
return true;
return false;
}
void sci_controller_post_request(struct isci_host *ihost,
u32 request);
void sci_controller_release_frame(struct isci_host *ihost,
u32 frame_index);
void sci_controller_copy_sata_response(void *response_buffer,
void *frame_header,
void *frame_buffer);
enum sci_status sci_controller_allocate_remote_node_context(struct isci_host *ihost,
struct isci_remote_device *idev,
u16 *node_id);
void sci_controller_free_remote_node_context(
struct isci_host *ihost,
struct isci_remote_device *idev,
u16 node_id);
struct isci_request *sci_request_by_tag(struct isci_host *ihost,
u16 io_tag);
void sci_controller_power_control_queue_insert(
struct isci_host *ihost,
struct isci_phy *iphy);
void sci_controller_power_control_queue_remove(
struct isci_host *ihost,
struct isci_phy *iphy);
void sci_controller_link_up(
struct isci_host *ihost,
struct isci_port *iport,
struct isci_phy *iphy);
void sci_controller_link_down(
struct isci_host *ihost,
struct isci_port *iport,
struct isci_phy *iphy);
void sci_controller_remote_device_stopped(
struct isci_host *ihost,
struct isci_remote_device *idev);
void sci_controller_copy_task_context(
struct isci_host *ihost,
struct isci_request *ireq);
void sci_controller_register_setup(struct isci_host *ihost);
enum sci_status sci_controller_continue_io(struct isci_request *ireq);
int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
void isci_host_scan_start(struct Scsi_Host *);
u16 isci_alloc_tag(struct isci_host *ihost);
enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
void isci_tci_free(struct isci_host *ihost, u16 tci);
int isci_host_init(struct isci_host *);
void isci_host_init_controller_names(
struct isci_host *isci_host,
unsigned int controller_idx);
void isci_host_deinit(
struct isci_host *);
void isci_host_port_link_up(
struct isci_host *,
struct isci_port *,
struct isci_phy *);
int isci_host_dev_found(struct domain_device *);
void isci_host_remote_device_start_complete(
struct isci_host *,
struct isci_remote_device *,
enum sci_status);
void sci_controller_disable_interrupts(
struct isci_host *ihost);
enum sci_status sci_controller_start_io(
struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_request *ireq);
enum sci_task_status sci_controller_start_task(
struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_request *ireq);
enum sci_status sci_controller_terminate_request(
struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_request *ireq);
enum sci_status sci_controller_complete_io(
struct isci_host *ihost,
struct isci_remote_device *idev,
struct isci_request *ireq);
void sci_port_configuration_agent_construct(
struct sci_port_configuration_agent *port_agent);
enum sci_status sci_port_configuration_agent_initialize(
struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent);
#endif

565
drivers/scsi/isci/init.c Normal file
View File

@ -0,0 +1,565 @@
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* BSD LICENSE
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/efi.h>
#include <asm/string.h>
#include "isci.h"
#include "task.h"
#include "probe_roms.h"
static struct scsi_transport_template *isci_transport_template;
static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = {
{ PCI_VDEVICE(INTEL, 0x1D61),},
{ PCI_VDEVICE(INTEL, 0x1D63),},
{ PCI_VDEVICE(INTEL, 0x1D65),},
{ PCI_VDEVICE(INTEL, 0x1D67),},
{ PCI_VDEVICE(INTEL, 0x1D69),},
{ PCI_VDEVICE(INTEL, 0x1D6B),},
{ PCI_VDEVICE(INTEL, 0x1D60),},
{ PCI_VDEVICE(INTEL, 0x1D62),},
{ PCI_VDEVICE(INTEL, 0x1D64),},
{ PCI_VDEVICE(INTEL, 0x1D66),},
{ PCI_VDEVICE(INTEL, 0x1D68),},
{ PCI_VDEVICE(INTEL, 0x1D6A),},
{}
};
MODULE_DEVICE_TABLE(pci, isci_id_table);
/* linux isci specific settings */
unsigned char no_outbound_task_to = 20;
module_param(no_outbound_task_to, byte, 0);
MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)");
u16 ssp_max_occ_to = 20;
module_param(ssp_max_occ_to, ushort, 0);
MODULE_PARM_DESC(ssp_max_occ_to, "SSP Max occupancy timeout (100us incr)");
u16 stp_max_occ_to = 5;
module_param(stp_max_occ_to, ushort, 0);
MODULE_PARM_DESC(stp_max_occ_to, "STP Max occupancy timeout (100us incr)");
u16 ssp_inactive_to = 5;
module_param(ssp_inactive_to, ushort, 0);
MODULE_PARM_DESC(ssp_inactive_to, "SSP inactivity timeout (100us incr)");
u16 stp_inactive_to = 5;
module_param(stp_inactive_to, ushort, 0);
MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)");
unsigned char phy_gen = 3;
module_param(phy_gen, byte, 0);
MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)");
unsigned char max_concurr_spinup = 1;
module_param(max_concurr_spinup, byte, 0);
MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup");
static struct scsi_host_template isci_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.proc_name = DRV_NAME,
.queuecommand = sas_queuecommand,
.target_alloc = sas_target_alloc,
.slave_configure = sas_slave_configure,
.slave_destroy = sas_slave_destroy,
.scan_finished = isci_host_scan_finished,
.scan_start = isci_host_scan_start,
.change_queue_depth = sas_change_queue_depth,
.change_queue_type = sas_change_queue_type,
.bios_param = sas_bios_param,
.can_queue = ISCI_CAN_QUEUE_VAL,
.cmd_per_lun = 1,
.this_id = -1,
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = isci_bus_reset_handler,
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
};
static struct sas_domain_function_template isci_transport_ops = {
/* The class calls these to notify the LLDD of an event. */
.lldd_port_formed = isci_port_formed,
.lldd_port_deformed = isci_port_deformed,
/* The class calls these when a device is found or gone. */
.lldd_dev_found = isci_remote_device_found,
.lldd_dev_gone = isci_remote_device_gone,
.lldd_execute_task = isci_task_execute_task,
/* Task Management Functions. Must be called from process context. */
.lldd_abort_task = isci_task_abort_task,
.lldd_abort_task_set = isci_task_abort_task_set,
.lldd_clear_aca = isci_task_clear_aca,
.lldd_clear_task_set = isci_task_clear_task_set,
.lldd_I_T_nexus_reset = isci_task_I_T_nexus_reset,
.lldd_lu_reset = isci_task_lu_reset,
.lldd_query_task = isci_task_query_task,
/* Port and Adapter management */
.lldd_clear_nexus_port = isci_task_clear_nexus_port,
.lldd_clear_nexus_ha = isci_task_clear_nexus_ha,
/* Phy management */
.lldd_control_phy = isci_phy_control,
};
/******************************************************************************
* P R O T E C T E D M E T H O D S
******************************************************************************/
/**
* isci_register_sas_ha() - This method initializes various lldd
* specific members of the sas_ha struct and calls the libsas
* sas_register_ha() function.
* @isci_host: This parameter specifies the lldd specific wrapper for the
* libsas sas_ha struct.
*
* This method returns an error code indicating sucess or failure. The user
* should check for possible memory allocation error return otherwise, a zero
* indicates success.
*/
static int isci_register_sas_ha(struct isci_host *isci_host)
{
int i;
struct sas_ha_struct *sas_ha = &(isci_host->sas_ha);
struct asd_sas_phy **sas_phys;
struct asd_sas_port **sas_ports;
sas_phys = devm_kzalloc(&isci_host->pdev->dev,
SCI_MAX_PHYS * sizeof(void *),
GFP_KERNEL);
if (!sas_phys)
return -ENOMEM;
sas_ports = devm_kzalloc(&isci_host->pdev->dev,
SCI_MAX_PORTS * sizeof(void *),
GFP_KERNEL);
if (!sas_ports)
return -ENOMEM;
/*----------------- Libsas Initialization Stuff----------------------
* Set various fields in the sas_ha struct:
*/
sas_ha->sas_ha_name = DRV_NAME;
sas_ha->lldd_module = THIS_MODULE;
sas_ha->sas_addr = &isci_host->phys[0].sas_addr[0];
/* set the array of phy and port structs. */
for (i = 0; i < SCI_MAX_PHYS; i++) {
sas_phys[i] = &isci_host->phys[i].sas_phy;
sas_ports[i] = &isci_host->ports[i].sas_port;
}
sas_ha->sas_phy = sas_phys;
sas_ha->sas_port = sas_ports;
sas_ha->num_phys = SCI_MAX_PHYS;
sas_ha->lldd_queue_size = ISCI_CAN_QUEUE_VAL;
sas_ha->lldd_max_execute_num = 1;
sas_ha->strict_wide_ports = 1;
sas_register_ha(sas_ha);
return 0;
}
static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf)
{
struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev);
struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha);
return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id);
}
static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL);
static void isci_unregister(struct isci_host *isci_host)
{
struct Scsi_Host *shost;
if (!isci_host)
return;
shost = isci_host->shost;
device_remove_file(&shost->shost_dev, &dev_attr_isci_id);
sas_unregister_ha(&isci_host->sas_ha);
sas_remove_host(isci_host->shost);
scsi_remove_host(isci_host->shost);
scsi_host_put(isci_host->shost);
}
static int __devinit isci_pci_init(struct pci_dev *pdev)
{
int err, bar_num, bar_mask = 0;
void __iomem * const *iomap;
err = pcim_enable_device(pdev);
if (err) {
dev_err(&pdev->dev,
"failed enable PCI device %s!\n",
pci_name(pdev));
return err;
}
for (bar_num = 0; bar_num < SCI_PCI_BAR_COUNT; bar_num++)
bar_mask |= 1 << (bar_num * 2);
err = pcim_iomap_regions(pdev, bar_mask, DRV_NAME);
if (err)
return err;
iomap = pcim_iomap_table(pdev);
if (!iomap)
return -ENOMEM;
pci_set_master(pdev);
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
if (err) {
err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err)
return err;
}
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
if (err) {
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (err)
return err;
}
return 0;
}
static int num_controllers(struct pci_dev *pdev)
{
/* bar size alone can tell us if we are running with a dual controller
* part, no need to trust revision ids that might be under broken firmware
* control
*/
resource_size_t scu_bar_size = pci_resource_len(pdev, SCI_SCU_BAR*2);
resource_size_t smu_bar_size = pci_resource_len(pdev, SCI_SMU_BAR*2);
if (scu_bar_size >= SCI_SCU_BAR_SIZE*SCI_MAX_CONTROLLERS &&
smu_bar_size >= SCI_SMU_BAR_SIZE*SCI_MAX_CONTROLLERS)
return SCI_MAX_CONTROLLERS;
else
return 1;
}
static int isci_setup_interrupts(struct pci_dev *pdev)
{
int err, i, num_msix;
struct isci_host *ihost;
struct isci_pci_info *pci_info = to_pci_info(pdev);
/*
* Determine the number of vectors associated with this
* PCI function.
*/
num_msix = num_controllers(pdev) * SCI_NUM_MSI_X_INT;
for (i = 0; i < num_msix; i++)
pci_info->msix_entries[i].entry = i;
err = pci_enable_msix(pdev, pci_info->msix_entries, num_msix);
if (err)
goto intx;
for (i = 0; i < num_msix; i++) {
int id = i / SCI_NUM_MSI_X_INT;
struct msix_entry *msix = &pci_info->msix_entries[i];
irq_handler_t isr;
ihost = pci_info->hosts[id];
/* odd numbered vectors are error interrupts */
if (i & 1)
isr = isci_error_isr;
else
isr = isci_msix_isr;
err = devm_request_irq(&pdev->dev, msix->vector, isr, 0,
DRV_NAME"-msix", ihost);
if (!err)
continue;
dev_info(&pdev->dev, "msix setup failed falling back to intx\n");
while (i--) {
id = i / SCI_NUM_MSI_X_INT;
ihost = pci_info->hosts[id];
msix = &pci_info->msix_entries[i];
devm_free_irq(&pdev->dev, msix->vector, ihost);
}
pci_disable_msix(pdev);
goto intx;
}
return 0;
intx:
for_each_isci_host(i, ihost, pdev) {
err = devm_request_irq(&pdev->dev, pdev->irq, isci_intx_isr,
IRQF_SHARED, DRV_NAME"-intx", ihost);
if (err)
break;
}
return err;
}
static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id)
{
struct isci_host *isci_host;
struct Scsi_Host *shost;
int err;
isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL);
if (!isci_host)
return NULL;
isci_host->pdev = pdev;
isci_host->id = id;
shost = scsi_host_alloc(&isci_sht, sizeof(void *));
if (!shost)
return NULL;
isci_host->shost = shost;
err = isci_host_init(isci_host);
if (err)
goto err_shost;
SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha;
isci_host->sas_ha.core.shost = shost;
shost->transportt = isci_transport_template;
shost->max_id = ~0;
shost->max_lun = ~0;
shost->max_cmd_len = MAX_COMMAND_SIZE;
err = scsi_add_host(shost, &pdev->dev);
if (err)
goto err_shost;
err = isci_register_sas_ha(isci_host);
if (err)
goto err_shost_remove;
err = device_create_file(&shost->shost_dev, &dev_attr_isci_id);
if (err)
goto err_unregister_ha;
return isci_host;
err_unregister_ha:
sas_unregister_ha(&(isci_host->sas_ha));
err_shost_remove:
scsi_remove_host(shost);
err_shost:
scsi_host_put(shost);
return NULL;
}
static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct isci_pci_info *pci_info;
int err, i;
struct isci_host *isci_host;
const struct firmware *fw = NULL;
struct isci_orom *orom = NULL;
char *source = "(platform)";
dev_info(&pdev->dev, "driver configured for rev: %d silicon\n",
pdev->revision);
pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL);
if (!pci_info)
return -ENOMEM;
pci_set_drvdata(pdev, pci_info);
if (efi_enabled)
orom = isci_get_efi_var(pdev);
if (!orom)
orom = isci_request_oprom(pdev);
for (i = 0; orom && i < ARRAY_SIZE(orom->ctrl); i++) {
if (sci_oem_parameters_validate(&orom->ctrl[i])) {
dev_warn(&pdev->dev,
"[%d]: invalid oem parameters detected, falling back to firmware\n", i);
devm_kfree(&pdev->dev, orom);
orom = NULL;
break;
}
}
if (!orom) {
source = "(firmware)";
orom = isci_request_firmware(pdev, fw);
if (!orom) {
/* TODO convert this to WARN_TAINT_ONCE once the
* orom/efi parameter support is widely available
*/
dev_warn(&pdev->dev,
"Loading user firmware failed, using default "
"values\n");
dev_warn(&pdev->dev,
"Default OEM configuration being used: 4 "
"narrow ports, and default SAS Addresses\n");
}
}
if (orom)
dev_info(&pdev->dev,
"OEM SAS parameters (version: %u.%u) loaded %s\n",
(orom->hdr.version & 0xf0) >> 4,
(orom->hdr.version & 0xf), source);
pci_info->orom = orom;
err = isci_pci_init(pdev);
if (err)
return err;
for (i = 0; i < num_controllers(pdev); i++) {
struct isci_host *h = isci_host_alloc(pdev, i);
if (!h) {
err = -ENOMEM;
goto err_host_alloc;
}
pci_info->hosts[i] = h;
}
err = isci_setup_interrupts(pdev);
if (err)
goto err_host_alloc;
for_each_isci_host(i, isci_host, pdev)
scsi_scan_host(isci_host->shost);
return 0;
err_host_alloc:
for_each_isci_host(i, isci_host, pdev)
isci_unregister(isci_host);
return err;
}
static void __devexit isci_pci_remove(struct pci_dev *pdev)
{
struct isci_host *ihost;
int i;
for_each_isci_host(i, ihost, pdev) {
isci_unregister(ihost);
isci_host_deinit(ihost);
sci_controller_disable_interrupts(ihost);
}
}
static struct pci_driver isci_pci_driver = {
.name = DRV_NAME,
.id_table = isci_id_table,
.probe = isci_pci_probe,
.remove = __devexit_p(isci_pci_remove),
};
static __init int isci_init(void)
{
int err;
pr_info("%s: Intel(R) C600 SAS Controller Driver\n", DRV_NAME);
isci_transport_template = sas_domain_attach_transport(&isci_transport_ops);
if (!isci_transport_template)
return -ENOMEM;
err = pci_register_driver(&isci_pci_driver);
if (err)
sas_release_transport(isci_transport_template);
return err;
}
static __exit void isci_exit(void)
{
pci_unregister_driver(&isci_pci_driver);
sas_release_transport(isci_transport_template);
}
MODULE_LICENSE("Dual BSD/GPL");
MODULE_FIRMWARE(ISCI_FW_NAME);
module_init(isci_init);
module_exit(isci_exit);

538
drivers/scsi/isci/isci.h Normal file
View File

@ -0,0 +1,538 @@
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* BSD LICENSE
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ISCI_H__
#define __ISCI_H__
#include <linux/interrupt.h>
#include <linux/types.h>
#define DRV_NAME "isci"
#define SCI_PCI_BAR_COUNT 2
#define SCI_NUM_MSI_X_INT 2
#define SCI_SMU_BAR 0
#define SCI_SMU_BAR_SIZE (16*1024)
#define SCI_SCU_BAR 1
#define SCI_SCU_BAR_SIZE (4*1024*1024)
#define SCI_IO_SPACE_BAR0 2
#define SCI_IO_SPACE_BAR1 3
#define ISCI_CAN_QUEUE_VAL 250 /* < SCI_MAX_IO_REQUESTS ? */
#define SCIC_CONTROLLER_STOP_TIMEOUT 5000
#define SCI_CONTROLLER_INVALID_IO_TAG 0xFFFF
#define SCI_MAX_PHYS (4UL)
#define SCI_MAX_PORTS SCI_MAX_PHYS
#define SCI_MAX_SMP_PHYS (384) /* not silicon constrained */
#define SCI_MAX_REMOTE_DEVICES (256UL)
#define SCI_MAX_IO_REQUESTS (256UL)
#define SCI_MAX_SEQ (16)
#define SCI_MAX_MSIX_MESSAGES (2)
#define SCI_MAX_SCATTER_GATHER_ELEMENTS 130 /* not silicon constrained */
#define SCI_MAX_CONTROLLERS 2
#define SCI_MAX_DOMAINS SCI_MAX_PORTS
#define SCU_MAX_CRITICAL_NOTIFICATIONS (384)
#define SCU_MAX_EVENTS_SHIFT (7)
#define SCU_MAX_EVENTS (1 << SCU_MAX_EVENTS_SHIFT)
#define SCU_MAX_UNSOLICITED_FRAMES (128)
#define SCU_MAX_COMPLETION_QUEUE_SCRATCH (128)
#define SCU_MAX_COMPLETION_QUEUE_ENTRIES (SCU_MAX_CRITICAL_NOTIFICATIONS \
+ SCU_MAX_EVENTS \
+ SCU_MAX_UNSOLICITED_FRAMES \
+ SCI_MAX_IO_REQUESTS \
+ SCU_MAX_COMPLETION_QUEUE_SCRATCH)
#define SCU_MAX_COMPLETION_QUEUE_SHIFT (ilog2(SCU_MAX_COMPLETION_QUEUE_ENTRIES))
#define SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES (4096)
#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE (1024)
#define SCU_INVALID_FRAME_INDEX (0xFFFF)
#define SCU_IO_REQUEST_MAX_SGE_SIZE (0x00FFFFFF)
#define SCU_IO_REQUEST_MAX_TRANSFER_LENGTH (0x00FFFFFF)
static inline void check_sizes(void)
{
BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_EVENTS);
BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES <= 8);
BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_UNSOLICITED_FRAMES);
BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_COMPLETION_QUEUE_ENTRIES);
BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES > SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES);
BUILD_BUG_ON_NOT_POWER_OF_2(SCI_MAX_IO_REQUESTS);
BUILD_BUG_ON_NOT_POWER_OF_2(SCI_MAX_SEQ);
}
/**
* enum sci_status - This is the general return status enumeration for non-IO,
* non-task management related SCI interface methods.
*
*
*/
enum sci_status {
/**
* This member indicates successful completion.
*/
SCI_SUCCESS = 0,
/**
* This value indicates that the calling method completed successfully,
* but that the IO may have completed before having it's start method
* invoked. This occurs during SAT translation for requests that do
* not require an IO to the target or for any other requests that may
* be completed without having to submit IO.
*/
SCI_SUCCESS_IO_COMPLETE_BEFORE_START,
/**
* This Value indicates that the SCU hardware returned an early response
* because the io request specified more data than is returned by the
* target device (mode pages, inquiry data, etc.). The completion routine
* will handle this case to get the actual number of bytes transferred.
*/
SCI_SUCCESS_IO_DONE_EARLY,
/**
* This member indicates that the object for which a state change is
* being requested is already in said state.
*/
SCI_WARNING_ALREADY_IN_STATE,
/**
* This member indicates interrupt coalescence timer may cause SAS
* specification compliance issues (i.e. SMP target mode response
* frames must be returned within 1.9 milliseconds).
*/
SCI_WARNING_TIMER_CONFLICT,
/**
* This field indicates a sequence of action is not completed yet. Mostly,
* this status is used when multiple ATA commands are needed in a SATI translation.
*/
SCI_WARNING_SEQUENCE_INCOMPLETE,
/**
* This member indicates that there was a general failure.
*/
SCI_FAILURE,
/**
* This member indicates that the SCI implementation is unable to complete
* an operation due to a critical flaw the prevents any further operation
* (i.e. an invalid pointer).
*/
SCI_FATAL_ERROR,
/**
* This member indicates the calling function failed, because the state
* of the controller is in a state that prevents successful completion.
*/
SCI_FAILURE_INVALID_STATE,
/**
* This member indicates the calling function failed, because there is
* insufficient resources/memory to complete the request.
*/
SCI_FAILURE_INSUFFICIENT_RESOURCES,
/**
* This member indicates the calling function failed, because the
* controller object required for the operation can't be located.
*/
SCI_FAILURE_CONTROLLER_NOT_FOUND,
/**
* This member indicates the calling function failed, because the
* discovered controller type is not supported by the library.
*/
SCI_FAILURE_UNSUPPORTED_CONTROLLER_TYPE,
/**
* This member indicates the calling function failed, because the
* requested initialization data version isn't supported.
*/
SCI_FAILURE_UNSUPPORTED_INIT_DATA_VERSION,
/**
* This member indicates the calling function failed, because the
* requested configuration of SAS Phys into SAS Ports is not supported.
*/
SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION,
/**
* This member indicates the calling function failed, because the
* requested protocol is not supported by the remote device, port,
* or controller.
*/
SCI_FAILURE_UNSUPPORTED_PROTOCOL,
/**
* This member indicates the calling function failed, because the
* requested information type is not supported by the SCI implementation.
*/
SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE,
/**
* This member indicates the calling function failed, because the
* device already exists.
*/
SCI_FAILURE_DEVICE_EXISTS,
/**
* This member indicates the calling function failed, because adding
* a phy to the object is not possible.
*/
SCI_FAILURE_ADDING_PHY_UNSUPPORTED,
/**
* This member indicates the calling function failed, because the
* requested information type is not supported by the SCI implementation.
*/
SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD,
/**
* This member indicates the calling function failed, because the SCI
* implementation does not support the supplied time limit.
*/
SCI_FAILURE_UNSUPPORTED_TIME_LIMIT,
/**
* This member indicates the calling method failed, because the SCI
* implementation does not contain the specified Phy.
*/
SCI_FAILURE_INVALID_PHY,
/**
* This member indicates the calling method failed, because the SCI
* implementation does not contain the specified Port.
*/
SCI_FAILURE_INVALID_PORT,
/**
* This member indicates the calling method was partly successful
* The port was reset but not all phys in port are operational
*/
SCI_FAILURE_RESET_PORT_PARTIAL_SUCCESS,
/**
* This member indicates that calling method failed
* The port reset did not complete because none of the phys are operational
*/
SCI_FAILURE_RESET_PORT_FAILURE,
/**
* This member indicates the calling method failed, because the SCI
* implementation does not contain the specified remote device.
*/
SCI_FAILURE_INVALID_REMOTE_DEVICE,
/**
* This member indicates the calling method failed, because the remote
* device is in a bad state and requires a reset.
*/
SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
/**
* This member indicates the calling method failed, because the SCI
* implementation does not contain or support the specified IO tag.
*/
SCI_FAILURE_INVALID_IO_TAG,
/**
* This member indicates that the operation failed and the user should
* check the response data associated with the IO.
*/
SCI_FAILURE_IO_RESPONSE_VALID,
/**
* This member indicates that the operation failed, the failure is
* controller implementation specific, and the response data associated
* with the request is not valid. You can query for the controller
* specific error information via sci_controller_get_request_status()
*/
SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
/**
* This member indicated that the operation failed because the
* user requested this IO to be terminated.
*/
SCI_FAILURE_IO_TERMINATED,
/**
* This member indicates that the operation failed and the associated
* request requires a SCSI abort task to be sent to the target.
*/
SCI_FAILURE_IO_REQUIRES_SCSI_ABORT,
/**
* This member indicates that the operation failed because the supplied
* device could not be located.
*/
SCI_FAILURE_DEVICE_NOT_FOUND,
/**
* This member indicates that the operation failed because the
* objects association is required and is not correctly set.
*/
SCI_FAILURE_INVALID_ASSOCIATION,
/**
* This member indicates that the operation failed, because a timeout
* occurred.
*/
SCI_FAILURE_TIMEOUT,
/**
* This member indicates that the operation failed, because the user
* specified a value that is either invalid or not supported.
*/
SCI_FAILURE_INVALID_PARAMETER_VALUE,
/**
* This value indicates that the operation failed, because the number
* of messages (MSI-X) is not supported.
*/
SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT,
/**
* This value indicates that the method failed due to a lack of
* available NCQ tags.
*/
SCI_FAILURE_NO_NCQ_TAG_AVAILABLE,
/**
* This value indicates that a protocol violation has occurred on the
* link.
*/
SCI_FAILURE_PROTOCOL_VIOLATION,
/**
* This value indicates a failure condition that retry may help to clear.
*/
SCI_FAILURE_RETRY_REQUIRED,
/**
* This field indicates the retry limit was reached when a retry is attempted
*/
SCI_FAILURE_RETRY_LIMIT_REACHED,
/**
* This member indicates the calling method was partly successful.
* Mostly, this status is used when a LUN_RESET issued to an expander attached
* STP device in READY NCQ substate needs to have RNC suspended/resumed
* before posting TC.
*/
SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS,
/**
* This field indicates an illegal phy connection based on the routing attribute
* of both expander phy attached to each other.
*/
SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION,
/**
* This field indicates a CONFIG ROUTE INFO command has a response with function result
* INDEX DOES NOT EXIST, usually means exceeding max route index.
*/
SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX,
/**
* This value indicates that an unsupported PCI device ID has been
* specified. This indicates that attempts to invoke
* sci_library_allocate_controller() will fail.
*/
SCI_FAILURE_UNSUPPORTED_PCI_DEVICE_ID
};
/**
* enum sci_io_status - This enumeration depicts all of the possible IO
* completion status values. Each value in this enumeration maps directly
* to a value in the enum sci_status enumeration. Please refer to that
* enumeration for detailed comments concerning what the status represents.
*
* Add the API to retrieve the SCU status from the core. Check to see that the
* following status are properly handled: - SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL
* - SCI_IO_FAILURE_INVALID_IO_TAG
*/
enum sci_io_status {
SCI_IO_SUCCESS = SCI_SUCCESS,
SCI_IO_FAILURE = SCI_FAILURE,
SCI_IO_SUCCESS_COMPLETE_BEFORE_START = SCI_SUCCESS_IO_COMPLETE_BEFORE_START,
SCI_IO_SUCCESS_IO_DONE_EARLY = SCI_SUCCESS_IO_DONE_EARLY,
SCI_IO_FAILURE_INVALID_STATE = SCI_FAILURE_INVALID_STATE,
SCI_IO_FAILURE_INSUFFICIENT_RESOURCES = SCI_FAILURE_INSUFFICIENT_RESOURCES,
SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL = SCI_FAILURE_UNSUPPORTED_PROTOCOL,
SCI_IO_FAILURE_RESPONSE_VALID = SCI_FAILURE_IO_RESPONSE_VALID,
SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
SCI_IO_FAILURE_TERMINATED = SCI_FAILURE_IO_TERMINATED,
SCI_IO_FAILURE_REQUIRES_SCSI_ABORT = SCI_FAILURE_IO_REQUIRES_SCSI_ABORT,
SCI_IO_FAILURE_INVALID_PARAMETER_VALUE = SCI_FAILURE_INVALID_PARAMETER_VALUE,
SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE = SCI_FAILURE_NO_NCQ_TAG_AVAILABLE,
SCI_IO_FAILURE_PROTOCOL_VIOLATION = SCI_FAILURE_PROTOCOL_VIOLATION,
SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
SCI_IO_FAILURE_RETRY_REQUIRED = SCI_FAILURE_RETRY_REQUIRED,
SCI_IO_FAILURE_RETRY_LIMIT_REACHED = SCI_FAILURE_RETRY_LIMIT_REACHED,
SCI_IO_FAILURE_INVALID_REMOTE_DEVICE = SCI_FAILURE_INVALID_REMOTE_DEVICE
};
/**
* enum sci_task_status - This enumeration depicts all of the possible task
* completion status values. Each value in this enumeration maps directly
* to a value in the enum sci_status enumeration. Please refer to that
* enumeration for detailed comments concerning what the status represents.
*
* Check to see that the following status are properly handled:
*/
enum sci_task_status {
SCI_TASK_SUCCESS = SCI_SUCCESS,
SCI_TASK_FAILURE = SCI_FAILURE,
SCI_TASK_FAILURE_INVALID_STATE = SCI_FAILURE_INVALID_STATE,
SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES = SCI_FAILURE_INSUFFICIENT_RESOURCES,
SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL = SCI_FAILURE_UNSUPPORTED_PROTOCOL,
SCI_TASK_FAILURE_INVALID_TAG = SCI_FAILURE_INVALID_IO_TAG,
SCI_TASK_FAILURE_RESPONSE_VALID = SCI_FAILURE_IO_RESPONSE_VALID,
SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR,
SCI_TASK_FAILURE_TERMINATED = SCI_FAILURE_IO_TERMINATED,
SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE = SCI_FAILURE_INVALID_PARAMETER_VALUE,
SCI_TASK_FAILURE_REMOTE_DEVICE_RESET_REQUIRED = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED,
SCI_TASK_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS = SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS
};
/**
* sci_swab32_cpy - convert between scsi and scu-hardware byte format
* @dest: receive the 4-byte endian swapped version of src
* @src: word aligned source buffer
*
* scu hardware handles SSP/SMP control, response, and unidentified
* frames in "big endian dword" order. Regardless of host endian this
* is always a swab32()-per-dword conversion of the standard definition,
* i.e. single byte fields swapped and multi-byte fields in little-
* endian
*/
static inline void sci_swab32_cpy(void *_dest, void *_src, ssize_t word_cnt)
{
u32 *dest = _dest, *src = _src;
while (--word_cnt >= 0)
dest[word_cnt] = swab32(src[word_cnt]);
}
extern unsigned char no_outbound_task_to;
extern u16 ssp_max_occ_to;
extern u16 stp_max_occ_to;
extern u16 ssp_inactive_to;
extern u16 stp_inactive_to;
extern unsigned char phy_gen;
extern unsigned char max_concurr_spinup;
irqreturn_t isci_msix_isr(int vec, void *data);
irqreturn_t isci_intx_isr(int vec, void *data);
irqreturn_t isci_error_isr(int vec, void *data);
/*
* Each timer is associated with a cancellation flag that is set when
* del_timer() is called and checked in the timer callback function. This
* is needed since del_timer_sync() cannot be called with sci_lock held.
* For deinit however, del_timer_sync() is used without holding the lock.
*/
struct sci_timer {
struct timer_list timer;
bool cancel;
};
static inline
void sci_init_timer(struct sci_timer *tmr, void (*fn)(unsigned long))
{
tmr->timer.function = fn;
tmr->timer.data = (unsigned long) tmr;
tmr->cancel = 0;
init_timer(&tmr->timer);
}
static inline void sci_mod_timer(struct sci_timer *tmr, unsigned long msec)
{
tmr->cancel = 0;
mod_timer(&tmr->timer, jiffies + msecs_to_jiffies(msec));
}
static inline void sci_del_timer(struct sci_timer *tmr)
{
tmr->cancel = 1;
del_timer(&tmr->timer);
}
struct sci_base_state_machine {
const struct sci_base_state *state_table;
u32 initial_state_id;
u32 current_state_id;
u32 previous_state_id;
};
typedef void (*sci_state_transition_t)(struct sci_base_state_machine *sm);
struct sci_base_state {
sci_state_transition_t enter_state; /* Called on state entry */
sci_state_transition_t exit_state; /* Called on state exit */
};
extern void sci_init_sm(struct sci_base_state_machine *sm,
const struct sci_base_state *state_table,
u32 initial_state);
extern void sci_change_state(struct sci_base_state_machine *sm, u32 next_state);
#endif /* __ISCI_H__ */

1312
drivers/scsi/isci/phy.c Normal file

File diff suppressed because it is too large Load Diff

504
drivers/scsi/isci/phy.h Normal file
View File

@ -0,0 +1,504 @@
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* BSD LICENSE
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ISCI_PHY_H_
#define _ISCI_PHY_H_
#include <scsi/sas.h>
#include <scsi/libsas.h>
#include "isci.h"
#include "sas.h"
/* This is the timeout value for the SATA phy to wait for a SIGNATURE FIS
* before restarting the starting state machine. Technically, the old parallel
* ATA specification required up to 30 seconds for a device to issue its
* signature FIS as a result of a soft reset. Now we see that devices respond
* generally within 15 seconds, but we'll use 25 for now.
*/
#define SCIC_SDS_SIGNATURE_FIS_TIMEOUT 25000
/* This is the timeout for the SATA OOB/SN because the hardware does not
* recognize a hot plug after OOB signal but before the SN signals. We need to
* make sure after a hotplug timeout if we have not received the speed event
* notification from the hardware that we restart the hardware OOB state
* machine.
*/
#define SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT 250
enum sci_phy_protocol {
SCIC_SDS_PHY_PROTOCOL_UNKNOWN,
SCIC_SDS_PHY_PROTOCOL_SAS,
SCIC_SDS_PHY_PROTOCOL_SATA,
SCIC_SDS_MAX_PHY_PROTOCOLS
};
/**
* isci_phy - hba local phy infrastructure
* @sm:
* @protocol: attached device protocol
* @phy_index: physical index relative to the controller (0-3)
* @bcn_received_while_port_unassigned: bcn to report after port association
* @sata_timer: timeout SATA signature FIS arrival
*/
struct isci_phy {
struct sci_base_state_machine sm;
struct isci_port *owning_port;
enum sas_linkrate max_negotiated_speed;
enum sci_phy_protocol protocol;
u8 phy_index;
bool bcn_received_while_port_unassigned;
bool is_in_link_training;
struct sci_timer sata_timer;
struct scu_transport_layer_registers __iomem *transport_layer_registers;
struct scu_link_layer_registers __iomem *link_layer_registers;
struct asd_sas_phy sas_phy;
struct isci_port *isci_port;
u8 sas_addr[SAS_ADDR_SIZE];
union {
struct sas_identify_frame iaf;
struct dev_to_host_fis fis;
} frame_rcvd;
};
static inline struct isci_phy *to_iphy(struct asd_sas_phy *sas_phy)
{
struct isci_phy *iphy = container_of(sas_phy, typeof(*iphy), sas_phy);
return iphy;
}
struct sci_phy_cap {
union {
struct {
/*
* The SAS specification indicates the start bit shall
* always be set to
* 1. This implementation will have the start bit set
* to 0 if the PHY CAPABILITIES were either not
* received or speed negotiation failed.
*/
u8 start:1;
u8 tx_ssc_type:1;
u8 res1:2;
u8 req_logical_linkrate:4;
u32 gen1_no_ssc:1;
u32 gen1_ssc:1;
u32 gen2_no_ssc:1;
u32 gen2_ssc:1;
u32 gen3_no_ssc:1;
u32 gen3_ssc:1;
u32 res2:17;
u32 parity:1;
};
u32 all;
};
} __packed;
/* this data structure reflects the link layer transmit identification reg */
struct sci_phy_proto {
union {
struct {
u16 _r_a:1;
u16 smp_iport:1;
u16 stp_iport:1;
u16 ssp_iport:1;
u16 _r_b:4;
u16 _r_c:1;
u16 smp_tport:1;
u16 stp_tport:1;
u16 ssp_tport:1;
u16 _r_d:4;
};
u16 all;
};
} __packed;
/**
* struct sci_phy_properties - This structure defines the properties common to
* all phys that can be retrieved.
*
*
*/
struct sci_phy_properties {
/**
* This field specifies the port that currently contains the
* supplied phy. This field may be set to NULL
* if the phy is not currently contained in a port.
*/
struct isci_port *iport;
/**
* This field specifies the link rate at which the phy is
* currently operating.
*/
enum sas_linkrate negotiated_link_rate;
/**
* This field specifies the index of the phy in relation to other
* phys within the controller. This index is zero relative.
*/
u8 index;
};
/**
* struct sci_sas_phy_properties - This structure defines the properties,
* specific to a SAS phy, that can be retrieved.
*
*
*/
struct sci_sas_phy_properties {
/**
* This field delineates the Identify Address Frame received
* from the remote end point.
*/
struct sas_identify_frame rcvd_iaf;
/**
* This field delineates the Phy capabilities structure received
* from the remote end point.
*/
struct sci_phy_cap rcvd_cap;
};
/**
* struct sci_sata_phy_properties - This structure defines the properties,
* specific to a SATA phy, that can be retrieved.
*
*
*/
struct sci_sata_phy_properties {
/**
* This field delineates the signature FIS received from the
* attached target.
*/
struct dev_to_host_fis signature_fis;
/**
* This field specifies to the user if a port selector is connected
* on the specified phy.
*/
bool is_port_selector_present;
};
/**
* enum sci_phy_counter_id - This enumeration depicts the various pieces of
* optional information that can be retrieved for a specific phy.
*
*
*/
enum sci_phy_counter_id {
/**
* This PHY information field tracks the number of frames received.
*/
SCIC_PHY_COUNTER_RECEIVED_FRAME,
/**
* This PHY information field tracks the number of frames transmitted.
*/
SCIC_PHY_COUNTER_TRANSMITTED_FRAME,
/**
* This PHY information field tracks the number of DWORDs received.
*/
SCIC_PHY_COUNTER_RECEIVED_FRAME_WORD,
/**
* This PHY information field tracks the number of DWORDs transmitted.
*/
SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD,
/**
* This PHY information field tracks the number of times DWORD
* synchronization was lost.
*/
SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR,
/**
* This PHY information field tracks the number of received DWORDs with
* running disparity errors.
*/
SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR,
/**
* This PHY information field tracks the number of received frames with a
* CRC error (not including short or truncated frames).
*/
SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR,
/**
* This PHY information field tracks the number of DONE (ACK/NAK TIMEOUT)
* primitives received.
*/
SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT,
/**
* This PHY information field tracks the number of DONE (ACK/NAK TIMEOUT)
* primitives transmitted.
*/
SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT,
/**
* This PHY information field tracks the number of times the inactivity
* timer for connections on the phy has been utilized.
*/
SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED,
/**
* This PHY information field tracks the number of DONE (CREDIT TIMEOUT)
* primitives received.
*/
SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT,
/**
* This PHY information field tracks the number of DONE (CREDIT TIMEOUT)
* primitives transmitted.
*/
SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT,
/**
* This PHY information field tracks the number of CREDIT BLOCKED
* primitives received.
* @note Depending on remote device implementation, credit blocks
* may occur regularly.
*/
SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED,
/**
* This PHY information field contains the number of short frames
* received. A short frame is simply a frame smaller then what is
* allowed by either the SAS or SATA specification.
*/
SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME,
/**
* This PHY information field contains the number of frames received after
* credit has been exhausted.
*/
SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT,
/**
* This PHY information field contains the number of frames received after
* a DONE has been received.
*/
SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE,
/**
* This PHY information field contains the number of times the phy
* failed to achieve DWORD synchronization during speed negotiation.
*/
SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR
};
enum sci_phy_states {
/**
* Simply the initial state for the base domain state machine.
*/
SCI_PHY_INITIAL,
/**
* This state indicates that the phy has successfully been stopped.
* In this state no new IO operations are permitted on this phy.
* This state is entered from the INITIAL state.
* This state is entered from the STARTING state.
* This state is entered from the READY state.
* This state is entered from the RESETTING state.
*/
SCI_PHY_STOPPED,
/**
* This state indicates that the phy is in the process of becomming
* ready. In this state no new IO operations are permitted on this phy.
* This state is entered from the STOPPED state.
* This state is entered from the READY state.
* This state is entered from the RESETTING state.
*/
SCI_PHY_STARTING,
/**
* Initial state
*/
SCI_PHY_SUB_INITIAL,
/**
* Wait state for the hardware OSSP event type notification
*/
SCI_PHY_SUB_AWAIT_OSSP_EN,
/**
* Wait state for the PHY speed notification
*/
SCI_PHY_SUB_AWAIT_SAS_SPEED_EN,
/**
* Wait state for the IAF Unsolicited frame notification
*/
SCI_PHY_SUB_AWAIT_IAF_UF,
/**
* Wait state for the request to consume power
*/
SCI_PHY_SUB_AWAIT_SAS_POWER,
/**
* Wait state for request to consume power
*/
SCI_PHY_SUB_AWAIT_SATA_POWER,
/**
* Wait state for the SATA PHY notification
*/
SCI_PHY_SUB_AWAIT_SATA_PHY_EN,
/**
* Wait for the SATA PHY speed notification
*/
SCI_PHY_SUB_AWAIT_SATA_SPEED_EN,
/**
* Wait state for the SIGNATURE FIS unsolicited frame notification
*/
SCI_PHY_SUB_AWAIT_SIG_FIS_UF,
/**
* Exit state for this state machine
*/
SCI_PHY_SUB_FINAL,
/**
* This state indicates the the phy is now ready. Thus, the user
* is able to perform IO operations utilizing this phy as long as it
* is currently part of a valid port.
* This state is entered from the STARTING state.
*/
SCI_PHY_READY,
/**
* This state indicates that the phy is in the process of being reset.
* In this state no new IO operations are permitted on this phy.
* This state is entered from the READY state.
*/
SCI_PHY_RESETTING,
/**
* Simply the final state for the base phy state machine.
*/
SCI_PHY_FINAL,
};
void sci_phy_construct(
struct isci_phy *iphy,
struct isci_port *iport,
u8 phy_index);
struct isci_port *phy_get_non_dummy_port(struct isci_phy *iphy);
void sci_phy_set_port(
struct isci_phy *iphy,
struct isci_port *iport);
enum sci_status sci_phy_initialize(
struct isci_phy *iphy,
struct scu_transport_layer_registers __iomem *transport_layer_registers,
struct scu_link_layer_registers __iomem *link_layer_registers);
enum sci_status sci_phy_start(
struct isci_phy *iphy);
enum sci_status sci_phy_stop(
struct isci_phy *iphy);
enum sci_status sci_phy_reset(
struct isci_phy *iphy);
void sci_phy_resume(
struct isci_phy *iphy);
void sci_phy_setup_transport(
struct isci_phy *iphy,
u32 device_id);
enum sci_status sci_phy_event_handler(
struct isci_phy *iphy,
u32 event_code);
enum sci_status sci_phy_frame_handler(
struct isci_phy *iphy,
u32 frame_index);
enum sci_status sci_phy_consume_power_handler(
struct isci_phy *iphy);
void sci_phy_get_sas_address(
struct isci_phy *iphy,
struct sci_sas_address *sas_address);
void sci_phy_get_attached_sas_address(
struct isci_phy *iphy,
struct sci_sas_address *sas_address);
struct sci_phy_proto;
void sci_phy_get_protocols(
struct isci_phy *iphy,
struct sci_phy_proto *protocols);
enum sas_linkrate sci_phy_linkrate(struct isci_phy *iphy);
struct isci_host;
void isci_phy_init(struct isci_phy *iphy, struct isci_host *ihost, int index);
int isci_phy_control(struct asd_sas_phy *phy, enum phy_func func, void *buf);
#endif /* !defined(_ISCI_PHY_H_) */

1757
drivers/scsi/isci/port.c Normal file

File diff suppressed because it is too large Load Diff

306
drivers/scsi/isci/port.h Normal file
View File

@ -0,0 +1,306 @@
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* BSD LICENSE
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ISCI_PORT_H_
#define _ISCI_PORT_H_
#include <scsi/libsas.h>
#include "isci.h"
#include "sas.h"
#include "phy.h"
#define SCIC_SDS_DUMMY_PORT 0xFF
struct isci_phy;
struct isci_host;
enum isci_status {
isci_freed = 0x00,
isci_starting = 0x01,
isci_ready = 0x02,
isci_ready_for_io = 0x03,
isci_stopping = 0x04,
isci_stopped = 0x05,
};
/**
* struct isci_port - isci direct attached sas port object
* @event: counts bcns and port stop events (for bcn filtering)
* @ready_exit: several states constitute 'ready'. When exiting ready we
* need to take extra port-teardown actions that are
* skipped when exiting to another 'ready' state.
* @logical_port_index: software port index
* @physical_port_index: hardware port index
* @active_phy_mask: identifies phy members
* @reserved_tag:
* @reserved_rni: reserver for port task scheduler workaround
* @started_request_count: reference count for outstanding commands
* @not_ready_reason: set during state transitions and notified
* @timer: timeout start/stop operations
*/
struct isci_port {
enum isci_status status;
#define IPORT_BCN_BLOCKED 0
#define IPORT_BCN_PENDING 1
unsigned long flags;
atomic_t event;
struct isci_host *isci_host;
struct asd_sas_port sas_port;
struct list_head remote_dev_list;
spinlock_t state_lock;
struct list_head domain_dev_list;
struct completion start_complete;
struct completion hard_reset_complete;
enum sci_status hard_reset_status;
struct sci_base_state_machine sm;
bool ready_exit;
u8 logical_port_index;
u8 physical_port_index;
u8 active_phy_mask;
u16 reserved_rni;
u16 reserved_tag;
u32 started_request_count;
u32 assigned_device_count;
u32 not_ready_reason;
struct isci_phy *phy_table[SCI_MAX_PHYS];
struct isci_host *owning_controller;
struct sci_timer timer;
struct scu_port_task_scheduler_registers __iomem *port_task_scheduler_registers;
/* XXX rework: only one register, no need to replicate per-port */
u32 __iomem *port_pe_configuration_register;
struct scu_viit_entry __iomem *viit_registers;
};
enum sci_port_not_ready_reason_code {
SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS,
SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED,
SCIC_PORT_NOT_READY_INVALID_PORT_CONFIGURATION,
SCIC_PORT_NOT_READY_RECONFIGURING,
SCIC_PORT_NOT_READY_REASON_CODE_MAX
};
struct sci_port_end_point_properties {
struct sci_sas_address sas_address;
struct sci_phy_proto protocols;
};
struct sci_port_properties {
u32 index;
struct sci_port_end_point_properties local;
struct sci_port_end_point_properties remote;
u32 phy_mask;
};
/**
* enum sci_port_states - This enumeration depicts all the states for the
* common port state machine.
*
*
*/
enum sci_port_states {
/**
* This state indicates that the port has successfully been stopped.
* In this state no new IO operations are permitted.
* This state is entered from the STOPPING state.
*/
SCI_PORT_STOPPED,
/**
* This state indicates that the port is in the process of stopping.
* In this state no new IO operations are permitted, but existing IO
* operations are allowed to complete.
* This state is entered from the READY state.
*/
SCI_PORT_STOPPING,
/**
* This state indicates the port is now ready. Thus, the user is
* able to perform IO operations on this port.
* This state is entered from the STARTING state.
*/
SCI_PORT_READY,
/**
* The substate where the port is started and ready but has no
* active phys.
*/
SCI_PORT_SUB_WAITING,
/**
* The substate where the port is started and ready and there is
* at least one phy operational.
*/
SCI_PORT_SUB_OPERATIONAL,
/**
* The substate where the port is started and there was an
* add/remove phy event. This state is only used in Automatic
* Port Configuration Mode (APC)
*/
SCI_PORT_SUB_CONFIGURING,
/**
* This state indicates the port is in the process of performing a hard
* reset. Thus, the user is unable to perform IO operations on this
* port.
* This state is entered from the READY state.
*/
SCI_PORT_RESETTING,
/**
* This state indicates the port has failed a reset request. This state
* is entered when a port reset request times out.
* This state is entered from the RESETTING state.
*/
SCI_PORT_FAILED,
};
static inline void sci_port_decrement_request_count(struct isci_port *iport)
{
if (WARN_ONCE(iport->started_request_count == 0,
"%s: tried to decrement started_request_count past 0!?",
__func__))
/* pass */;
else
iport->started_request_count--;
}
#define sci_port_active_phy(port, phy) \
(((port)->active_phy_mask & (1 << (phy)->phy_index)) != 0)
void sci_port_construct(
struct isci_port *iport,
u8 port_index,
struct isci_host *ihost);
enum sci_status sci_port_start(struct isci_port *iport);
enum sci_status sci_port_stop(struct isci_port *iport);
enum sci_status sci_port_add_phy(
struct isci_port *iport,
struct isci_phy *iphy);
enum sci_status sci_port_remove_phy(
struct isci_port *iport,
struct isci_phy *iphy);
void sci_port_setup_transports(
struct isci_port *iport,
u32 device_id);
void isci_port_bcn_enable(struct isci_host *, struct isci_port *);
void sci_port_deactivate_phy(
struct isci_port *iport,
struct isci_phy *iphy,
bool do_notify_user);
bool sci_port_link_detected(
struct isci_port *iport,
struct isci_phy *iphy);
enum sci_status sci_port_link_up(struct isci_port *iport,
struct isci_phy *iphy);
enum sci_status sci_port_link_down(struct isci_port *iport,
struct isci_phy *iphy);
struct isci_request;
struct isci_remote_device;
enum sci_status sci_port_start_io(
struct isci_port *iport,
struct isci_remote_device *idev,
struct isci_request *ireq);
enum sci_status sci_port_complete_io(
struct isci_port *iport,
struct isci_remote_device *idev,
struct isci_request *ireq);
enum sas_linkrate sci_port_get_max_allowed_speed(
struct isci_port *iport);
void sci_port_broadcast_change_received(
struct isci_port *iport,
struct isci_phy *iphy);
bool sci_port_is_valid_phy_assignment(
struct isci_port *iport,
u32 phy_index);
void sci_port_get_sas_address(
struct isci_port *iport,
struct sci_sas_address *sas_address);
void sci_port_get_attached_sas_address(
struct isci_port *iport,
struct sci_sas_address *sas_address);
enum isci_status isci_port_get_state(
struct isci_port *isci_port);
void isci_port_formed(struct asd_sas_phy *);
void isci_port_deformed(struct asd_sas_phy *);
void isci_port_init(
struct isci_port *port,
struct isci_host *host,
int index);
int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport,
struct isci_phy *iphy);
#endif /* !defined(_ISCI_PORT_H_) */

View File

@ -0,0 +1,754 @@
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* BSD LICENSE
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "host.h"
#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10)
#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10)
#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (100)
enum SCIC_SDS_APC_ACTIVITY {
SCIC_SDS_APC_SKIP_PHY,
SCIC_SDS_APC_ADD_PHY,
SCIC_SDS_APC_START_TIMER,
SCIC_SDS_APC_ACTIVITY_MAX
};
/*
* ******************************************************************************
* General port configuration agent routines
* ****************************************************************************** */
/**
*
* @address_one: A SAS Address to be compared.
* @address_two: A SAS Address to be compared.
*
* Compare the two SAS Address and if SAS Address One is greater than SAS
* Address Two then return > 0 else if SAS Address One is less than SAS Address
* Two return < 0 Otherwise they are the same return 0 A signed value of x > 0
* > y where x is returned for Address One > Address Two y is returned for
* Address One < Address Two 0 is returned ofr Address One = Address Two
*/
static s32 sci_sas_address_compare(
struct sci_sas_address address_one,
struct sci_sas_address address_two)
{
if (address_one.high > address_two.high) {
return 1;
} else if (address_one.high < address_two.high) {
return -1;
} else if (address_one.low > address_two.low) {
return 1;
} else if (address_one.low < address_two.low) {
return -1;
}
/* The two SAS Address must be identical */
return 0;
}
/**
*
* @controller: The controller object used for the port search.
* @phy: The phy object to match.
*
* This routine will find a matching port for the phy. This means that the
* port and phy both have the same broadcast sas address and same received sas
* address. The port address or the NULL if there is no matching
* port. port address if the port can be found to match the phy.
* NULL if there is no matching port for the phy.
*/
static struct isci_port *sci_port_configuration_agent_find_port(
struct isci_host *ihost,
struct isci_phy *iphy)
{
u8 i;
struct sci_sas_address port_sas_address;
struct sci_sas_address port_attached_device_address;
struct sci_sas_address phy_sas_address;
struct sci_sas_address phy_attached_device_address;
/*
* Since this phy can be a member of a wide port check to see if one or
* more phys match the sent and received SAS address as this phy in which
* case it should participate in the same port.
*/
sci_phy_get_sas_address(iphy, &phy_sas_address);
sci_phy_get_attached_sas_address(iphy, &phy_attached_device_address);
for (i = 0; i < ihost->logical_port_entries; i++) {
struct isci_port *iport = &ihost->ports[i];
sci_port_get_sas_address(iport, &port_sas_address);
sci_port_get_attached_sas_address(iport, &port_attached_device_address);
if (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0 &&
sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0)
return iport;
}
return NULL;
}
/**
*
* @controller: This is the controller object that contains the port agent
* @port_agent: This is the port configruation agent for the controller.
*
* This routine will validate the port configuration is correct for the SCU
* hardware. The SCU hardware allows for port configurations as follows. LP0
* -> (PE0), (PE0, PE1), (PE0, PE1, PE2, PE3) LP1 -> (PE1) LP2 -> (PE2), (PE2,
* PE3) LP3 -> (PE3) enum sci_status SCI_SUCCESS the port configuration is valid for
* this port configuration agent. SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION
* the port configuration is not valid for this port configuration agent.
*/
static enum sci_status sci_port_configuration_agent_validate_ports(
struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent)
{
struct sci_sas_address first_address;
struct sci_sas_address second_address;
/*
* Sanity check the max ranges for all the phys the max index
* is always equal to the port range index */
if (port_agent->phy_valid_port_range[0].max_index != 0 ||
port_agent->phy_valid_port_range[1].max_index != 1 ||
port_agent->phy_valid_port_range[2].max_index != 2 ||
port_agent->phy_valid_port_range[3].max_index != 3)
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
/*
* This is a request to configure a single x4 port or at least attempt
* to make all the phys into a single port */
if (port_agent->phy_valid_port_range[0].min_index == 0 &&
port_agent->phy_valid_port_range[1].min_index == 0 &&
port_agent->phy_valid_port_range[2].min_index == 0 &&
port_agent->phy_valid_port_range[3].min_index == 0)
return SCI_SUCCESS;
/*
* This is a degenerate case where phy 1 and phy 2 are assigned
* to the same port this is explicitly disallowed by the hardware
* unless they are part of the same x4 port and this condition was
* already checked above. */
if (port_agent->phy_valid_port_range[2].min_index == 1) {
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
}
/*
* PE0 and PE3 can never have the same SAS Address unless they
* are part of the same x4 wide port and we have already checked
* for this condition. */
sci_phy_get_sas_address(&ihost->phys[0], &first_address);
sci_phy_get_sas_address(&ihost->phys[3], &second_address);
if (sci_sas_address_compare(first_address, second_address) == 0) {
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
}
/*
* PE0 and PE1 are configured into a 2x1 ports make sure that the
* SAS Address for PE0 and PE2 are different since they can not be
* part of the same port. */
if (port_agent->phy_valid_port_range[0].min_index == 0 &&
port_agent->phy_valid_port_range[1].min_index == 1) {
sci_phy_get_sas_address(&ihost->phys[0], &first_address);
sci_phy_get_sas_address(&ihost->phys[2], &second_address);
if (sci_sas_address_compare(first_address, second_address) == 0) {
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
}
}
/*
* PE2 and PE3 are configured into a 2x1 ports make sure that the
* SAS Address for PE1 and PE3 are different since they can not be
* part of the same port. */
if (port_agent->phy_valid_port_range[2].min_index == 2 &&
port_agent->phy_valid_port_range[3].min_index == 3) {
sci_phy_get_sas_address(&ihost->phys[1], &first_address);
sci_phy_get_sas_address(&ihost->phys[3], &second_address);
if (sci_sas_address_compare(first_address, second_address) == 0) {
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
}
}
return SCI_SUCCESS;
}
/*
* ******************************************************************************
* Manual port configuration agent routines
* ****************************************************************************** */
/* verify all of the phys in the same port are using the same SAS address */
static enum sci_status
sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent)
{
u32 phy_mask;
u32 assigned_phy_mask;
struct sci_sas_address sas_address;
struct sci_sas_address phy_assigned_address;
u8 port_index;
u8 phy_index;
assigned_phy_mask = 0;
sas_address.high = 0;
sas_address.low = 0;
for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) {
phy_mask = ihost->oem_parameters.ports[port_index].phy_mask;
if (!phy_mask)
continue;
/*
* Make sure that one or more of the phys were not already assinged to
* a different port. */
if ((phy_mask & ~assigned_phy_mask) == 0) {
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
}
/* Find the starting phy index for this round through the loop */
for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) {
if ((phy_mask & (1 << phy_index)) == 0)
continue;
sci_phy_get_sas_address(&ihost->phys[phy_index],
&sas_address);
/*
* The phy_index can be used as the starting point for the
* port range since the hardware starts all logical ports
* the same as the PE index. */
port_agent->phy_valid_port_range[phy_index].min_index = port_index;
port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
if (phy_index != port_index) {
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
}
break;
}
/*
* See how many additional phys are being added to this logical port.
* Note: We have not moved the current phy_index so we will actually
* compare the startting phy with itself.
* This is expected and required to add the phy to the port. */
while (phy_index < SCI_MAX_PHYS) {
if ((phy_mask & (1 << phy_index)) == 0)
continue;
sci_phy_get_sas_address(&ihost->phys[phy_index],
&phy_assigned_address);
if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) {
/*
* The phy mask specified that this phy is part of the same port
* as the starting phy and it is not so fail this configuration */
return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
}
port_agent->phy_valid_port_range[phy_index].min_index = port_index;
port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
sci_port_add_phy(&ihost->ports[port_index],
&ihost->phys[phy_index]);
assigned_phy_mask |= (1 << phy_index);
}
phy_index++;
}
return sci_port_configuration_agent_validate_ports(ihost, port_agent);
}
static void mpc_agent_timeout(unsigned long data)
{
u8 index;
struct sci_timer *tmr = (struct sci_timer *)data;
struct sci_port_configuration_agent *port_agent;
struct isci_host *ihost;
unsigned long flags;
u16 configure_phy_mask;
port_agent = container_of(tmr, typeof(*port_agent), timer);
ihost = container_of(port_agent, typeof(*ihost), port_agent);
spin_lock_irqsave(&ihost->scic_lock, flags);
if (tmr->cancel)
goto done;
port_agent->timer_pending = false;
/* Find the mask of phys that are reported read but as yet unconfigured into a port */
configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask;
for (index = 0; index < SCI_MAX_PHYS; index++) {
struct isci_phy *iphy = &ihost->phys[index];
if (configure_phy_mask & (1 << index)) {
port_agent->link_up_handler(ihost, port_agent,
phy_get_non_dummy_port(iphy),
iphy);
}
}
done:
spin_unlock_irqrestore(&ihost->scic_lock, flags);
}
static void sci_mpc_agent_link_up(struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent,
struct isci_port *iport,
struct isci_phy *iphy)
{
/* If the port is NULL then the phy was not assigned to a port.
* This is because the phy was not given the same SAS Address as
* the other PHYs in the port.
*/
if (!iport)
return;
port_agent->phy_ready_mask |= (1 << iphy->phy_index);
sci_port_link_up(iport, iphy);
if ((iport->active_phy_mask & (1 << iphy->phy_index)))
port_agent->phy_configured_mask |= (1 << iphy->phy_index);
}
/**
*
* @controller: This is the controller object that receives the link down
* notification.
* @port: This is the port object associated with the phy. If the is no
* associated port this is an NULL. The port is an invalid
* handle only if the phy was never port of this port. This happens when
* the phy is not broadcasting the same SAS address as the other phys in the
* assigned port.
* @phy: This is the phy object which has gone link down.
*
* This function handles the manual port configuration link down notifications.
* Since all ports and phys are associated at initialization time we just turn
* around and notifiy the port object of the link down event. If this PHY is
* not associated with a port there is no action taken. Is it possible to get a
* link down notification from a phy that has no assocoated port?
*/
static void sci_mpc_agent_link_down(
struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent,
struct isci_port *iport,
struct isci_phy *iphy)
{
if (iport != NULL) {
/*
* If we can form a new port from the remainder of the phys
* then we want to start the timer to allow the SCI User to
* cleanup old devices and rediscover the port before
* rebuilding the port with the phys that remain in the ready
* state.
*/
port_agent->phy_ready_mask &= ~(1 << iphy->phy_index);
port_agent->phy_configured_mask &= ~(1 << iphy->phy_index);
/*
* Check to see if there are more phys waiting to be
* configured into a port. If there are allow the SCI User
* to tear down this port, if necessary, and then reconstruct
* the port after the timeout.
*/
if ((port_agent->phy_configured_mask == 0x0000) &&
(port_agent->phy_ready_mask != 0x0000) &&
!port_agent->timer_pending) {
port_agent->timer_pending = true;
sci_mod_timer(&port_agent->timer,
SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT);
}
sci_port_link_down(iport, iphy);
}
}
/* verify phys are assigned a valid SAS address for automatic port
* configuration mode.
*/
static enum sci_status
sci_apc_agent_validate_phy_configuration(struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent)
{
u8 phy_index;
u8 port_index;
struct sci_sas_address sas_address;
struct sci_sas_address phy_assigned_address;
phy_index = 0;
while (phy_index < SCI_MAX_PHYS) {
port_index = phy_index;
/* Get the assigned SAS Address for the first PHY on the controller. */
sci_phy_get_sas_address(&ihost->phys[phy_index],
&sas_address);
while (++phy_index < SCI_MAX_PHYS) {
sci_phy_get_sas_address(&ihost->phys[phy_index],
&phy_assigned_address);
/* Verify each of the SAS address are all the same for every PHY */
if (sci_sas_address_compare(sas_address, phy_assigned_address) == 0) {
port_agent->phy_valid_port_range[phy_index].min_index = port_index;
port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
} else {
port_agent->phy_valid_port_range[phy_index].min_index = phy_index;
port_agent->phy_valid_port_range[phy_index].max_index = phy_index;
break;
}
}
}
return sci_port_configuration_agent_validate_ports(ihost, port_agent);
}
static void sci_apc_agent_configure_ports(struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent,
struct isci_phy *iphy,
bool start_timer)
{
u8 port_index;
enum sci_status status;
struct isci_port *iport;
enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY;
iport = sci_port_configuration_agent_find_port(ihost, iphy);
if (iport) {
if (sci_port_is_valid_phy_assignment(iport, iphy->phy_index))
apc_activity = SCIC_SDS_APC_ADD_PHY;
else
apc_activity = SCIC_SDS_APC_SKIP_PHY;
} else {
/*
* There is no matching Port for this PHY so lets search through the
* Ports and see if we can add the PHY to its own port or maybe start
* the timer and wait to see if a wider port can be made.
*
* Note the break when we reach the condition of the port id == phy id */
for (port_index = port_agent->phy_valid_port_range[iphy->phy_index].min_index;
port_index <= port_agent->phy_valid_port_range[iphy->phy_index].max_index;
port_index++) {
iport = &ihost->ports[port_index];
/* First we must make sure that this PHY can be added to this Port. */
if (sci_port_is_valid_phy_assignment(iport, iphy->phy_index)) {
/*
* Port contains a PHY with a greater PHY ID than the current
* PHY that has gone link up. This phy can not be part of any
* port so skip it and move on. */
if (iport->active_phy_mask > (1 << iphy->phy_index)) {
apc_activity = SCIC_SDS_APC_SKIP_PHY;
break;
}
/*
* We have reached the end of our Port list and have not found
* any reason why we should not either add the PHY to the port
* or wait for more phys to become active. */
if (iport->physical_port_index == iphy->phy_index) {
/*
* The Port either has no active PHYs.
* Consider that if the port had any active PHYs we would have
* or active PHYs with
* a lower PHY Id than this PHY. */
if (apc_activity != SCIC_SDS_APC_START_TIMER) {
apc_activity = SCIC_SDS_APC_ADD_PHY;
}
break;
}
/*
* The current Port has no active PHYs and this PHY could be part
* of this Port. Since we dont know as yet setup to start the
* timer and see if there is a better configuration. */
if (iport->active_phy_mask == 0) {
apc_activity = SCIC_SDS_APC_START_TIMER;
}
} else if (iport->active_phy_mask != 0) {
/*
* The Port has an active phy and the current Phy can not
* participate in this port so skip the PHY and see if
* there is a better configuration. */
apc_activity = SCIC_SDS_APC_SKIP_PHY;
}
}
}
/*
* Check to see if the start timer operations should instead map to an
* add phy operation. This is caused because we have been waiting to
* add a phy to a port but could not becuase the automatic port
* configuration engine had a choice of possible ports for the phy.
* Since we have gone through a timeout we are going to restrict the
* choice to the smallest possible port. */
if (
(start_timer == false)
&& (apc_activity == SCIC_SDS_APC_START_TIMER)
) {
apc_activity = SCIC_SDS_APC_ADD_PHY;
}
switch (apc_activity) {
case SCIC_SDS_APC_ADD_PHY:
status = sci_port_add_phy(iport, iphy);
if (status == SCI_SUCCESS) {
port_agent->phy_configured_mask |= (1 << iphy->phy_index);
}
break;
case SCIC_SDS_APC_START_TIMER:
/*
* This can occur for either a link down event, or a link
* up event where we cannot yet tell the port to which a
* phy belongs.
*/
if (port_agent->timer_pending)
sci_del_timer(&port_agent->timer);
port_agent->timer_pending = true;
sci_mod_timer(&port_agent->timer,
SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
break;
case SCIC_SDS_APC_SKIP_PHY:
default:
/* do nothing the PHY can not be made part of a port at this time. */
break;
}
}
/**
* sci_apc_agent_link_up - handle apc link up events
* @scic: This is the controller object that receives the link up
* notification.
* @sci_port: This is the port object associated with the phy. If the is no
* associated port this is an NULL.
* @sci_phy: This is the phy object which has gone link up.
*
* This method handles the automatic port configuration for link up
* notifications. Is it possible to get a link down notification from a phy
* that has no assocoated port?
*/
static void sci_apc_agent_link_up(struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent,
struct isci_port *iport,
struct isci_phy *iphy)
{
u8 phy_index = iphy->phy_index;
if (!iport) {
/* the phy is not the part of this port */
port_agent->phy_ready_mask |= 1 << phy_index;
sci_apc_agent_configure_ports(ihost, port_agent, iphy, true);
} else {
/* the phy is already the part of the port */
u32 port_state = iport->sm.current_state_id;
/* if the PORT'S state is resetting then the link up is from
* port hard reset in this case, we need to tell the port
* that link up is recieved
*/
BUG_ON(port_state != SCI_PORT_RESETTING);
port_agent->phy_ready_mask |= 1 << phy_index;
sci_port_link_up(iport, iphy);
}
}
/**
*
* @controller: This is the controller object that receives the link down
* notification.
* @iport: This is the port object associated with the phy. If the is no
* associated port this is an NULL.
* @iphy: This is the phy object which has gone link down.
*
* This method handles the automatic port configuration link down
* notifications. not associated with a port there is no action taken. Is it
* possible to get a link down notification from a phy that has no assocoated
* port?
*/
static void sci_apc_agent_link_down(
struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent,
struct isci_port *iport,
struct isci_phy *iphy)
{
port_agent->phy_ready_mask &= ~(1 << iphy->phy_index);
if (!iport)
return;
if (port_agent->phy_configured_mask & (1 << iphy->phy_index)) {
enum sci_status status;
status = sci_port_remove_phy(iport, iphy);
if (status == SCI_SUCCESS)
port_agent->phy_configured_mask &= ~(1 << iphy->phy_index);
}
}
/* configure the phys into ports when the timer fires */
static void apc_agent_timeout(unsigned long data)
{
u32 index;
struct sci_timer *tmr = (struct sci_timer *)data;
struct sci_port_configuration_agent *port_agent;
struct isci_host *ihost;
unsigned long flags;
u16 configure_phy_mask;
port_agent = container_of(tmr, typeof(*port_agent), timer);
ihost = container_of(port_agent, typeof(*ihost), port_agent);
spin_lock_irqsave(&ihost->scic_lock, flags);
if (tmr->cancel)
goto done;
port_agent->timer_pending = false;
configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask;
if (!configure_phy_mask)
return;
for (index = 0; index < SCI_MAX_PHYS; index++) {
if ((configure_phy_mask & (1 << index)) == 0)
continue;
sci_apc_agent_configure_ports(ihost, port_agent,
&ihost->phys[index], false);
}
done:
spin_unlock_irqrestore(&ihost->scic_lock, flags);
}
/*
* ******************************************************************************
* Public port configuration agent routines
* ****************************************************************************** */
/**
*
*
* This method will construct the port configuration agent for operation. This
* call is universal for both manual port configuration and automatic port
* configuration modes.
*/
void sci_port_configuration_agent_construct(
struct sci_port_configuration_agent *port_agent)
{
u32 index;
port_agent->phy_configured_mask = 0x00;
port_agent->phy_ready_mask = 0x00;
port_agent->link_up_handler = NULL;
port_agent->link_down_handler = NULL;
port_agent->timer_pending = false;
for (index = 0; index < SCI_MAX_PORTS; index++) {
port_agent->phy_valid_port_range[index].min_index = 0;
port_agent->phy_valid_port_range[index].max_index = 0;
}
}
enum sci_status sci_port_configuration_agent_initialize(
struct isci_host *ihost,
struct sci_port_configuration_agent *port_agent)
{
enum sci_status status;
enum sci_port_configuration_mode mode;
mode = ihost->oem_parameters.controller.mode_type;
if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) {
status = sci_mpc_agent_validate_phy_configuration(
ihost, port_agent);
port_agent->link_up_handler = sci_mpc_agent_link_up;
port_agent->link_down_handler = sci_mpc_agent_link_down;
sci_init_timer(&port_agent->timer, mpc_agent_timeout);
} else {
status = sci_apc_agent_validate_phy_configuration(
ihost, port_agent);
port_agent->link_up_handler = sci_apc_agent_link_up;
port_agent->link_down_handler = sci_apc_agent_link_down;
sci_init_timer(&port_agent->timer, apc_agent_timeout);
}
return status;
}

View File

@ -0,0 +1,243 @@
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*/
/* probe_roms - scan for oem parameters */
#include <linux/kernel.h>
#include <linux/firmware.h>
#include <linux/uaccess.h>
#include <linux/efi.h>
#include <asm/probe_roms.h>
#include "isci.h"
#include "task.h"
#include "probe_roms.h"
static efi_char16_t isci_efivar_name[] = {
'R', 's', 't', 'S', 'c', 'u', 'O'
};
struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
{
void __iomem *oprom = pci_map_biosrom(pdev);
struct isci_orom *rom = NULL;
size_t len, i;
int j;
char oem_sig[4];
struct isci_oem_hdr oem_hdr;
u8 *tmp, sum;
if (!oprom)
return NULL;
len = pci_biosrom_size(pdev);
rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL);
if (!rom) {
dev_warn(&pdev->dev,
"Unable to allocate memory for orom\n");
return NULL;
}
for (i = 0; i < len && rom; i += ISCI_OEM_SIG_SIZE) {
memcpy_fromio(oem_sig, oprom + i, ISCI_OEM_SIG_SIZE);
/* we think we found the OEM table */
if (memcmp(oem_sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) == 0) {
size_t copy_len;
memcpy_fromio(&oem_hdr, oprom + i, sizeof(oem_hdr));
copy_len = min(oem_hdr.len - sizeof(oem_hdr),
sizeof(*rom));
memcpy_fromio(rom,
oprom + i + sizeof(oem_hdr),
copy_len);
/* calculate checksum */
tmp = (u8 *)&oem_hdr;
for (j = 0, sum = 0; j < sizeof(oem_hdr); j++, tmp++)
sum += *tmp;
tmp = (u8 *)rom;
for (j = 0; j < sizeof(*rom); j++, tmp++)
sum += *tmp;
if (sum != 0) {
dev_warn(&pdev->dev,
"OEM table checksum failed\n");
continue;
}
/* keep going if that's not the oem param table */
if (memcmp(rom->hdr.signature,
ISCI_ROM_SIG,
ISCI_ROM_SIG_SIZE) != 0)
continue;
dev_info(&pdev->dev,
"OEM parameter table found in OROM\n");
break;
}
}
if (i >= len) {
dev_err(&pdev->dev, "oprom parse error\n");
devm_kfree(&pdev->dev, rom);
rom = NULL;
}
pci_unmap_biosrom(oprom);
return rom;
}
enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem,
struct isci_orom *orom, int scu_index)
{
/* check for valid inputs */
if (scu_index < 0 || scu_index >= SCI_MAX_CONTROLLERS ||
scu_index > orom->hdr.num_elements || !oem)
return -EINVAL;
*oem = orom->ctrl[scu_index];
return 0;
}
struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw)
{
struct isci_orom *orom = NULL, *data;
int i, j;
if (request_firmware(&fw, ISCI_FW_NAME, &pdev->dev) != 0)
return NULL;
if (fw->size < sizeof(*orom))
goto out;
data = (struct isci_orom *)fw->data;
if (strncmp(ISCI_ROM_SIG, data->hdr.signature,
strlen(ISCI_ROM_SIG)) != 0)
goto out;
orom = devm_kzalloc(&pdev->dev, fw->size, GFP_KERNEL);
if (!orom)
goto out;
memcpy(orom, fw->data, fw->size);
if (is_c0(pdev))
goto out;
/*
* deprecated: override default amp_control for pre-preproduction
* silicon revisions
*/
for (i = 0; i < ARRAY_SIZE(orom->ctrl); i++)
for (j = 0; j < ARRAY_SIZE(orom->ctrl[i].phys); j++) {
orom->ctrl[i].phys[j].afe_tx_amp_control0 = 0xe7c03;
orom->ctrl[i].phys[j].afe_tx_amp_control1 = 0xe7c03;
orom->ctrl[i].phys[j].afe_tx_amp_control2 = 0xe7c03;
orom->ctrl[i].phys[j].afe_tx_amp_control3 = 0xe7c03;
}
out:
release_firmware(fw);
return orom;
}
static struct efi *get_efi(void)
{
#ifdef CONFIG_EFI
return &efi;
#else
return NULL;
#endif
}
struct isci_orom *isci_get_efi_var(struct pci_dev *pdev)
{
efi_status_t status;
struct isci_orom *rom;
struct isci_oem_hdr *oem_hdr;
u8 *tmp, sum;
int j;
unsigned long data_len;
u8 *efi_data;
u32 efi_attrib = 0;
data_len = 1024;
efi_data = devm_kzalloc(&pdev->dev, data_len, GFP_KERNEL);
if (!efi_data) {
dev_warn(&pdev->dev,
"Unable to allocate memory for EFI data\n");
return NULL;
}
rom = (struct isci_orom *)(efi_data + sizeof(struct isci_oem_hdr));
if (get_efi())
status = get_efi()->get_variable(isci_efivar_name,
&ISCI_EFI_VENDOR_GUID,
&efi_attrib,
&data_len,
efi_data);
else
status = EFI_NOT_FOUND;
if (status != EFI_SUCCESS) {
dev_warn(&pdev->dev,
"Unable to obtain EFI var data for OEM parms\n");
return NULL;
}
oem_hdr = (struct isci_oem_hdr *)efi_data;
if (memcmp(oem_hdr->sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) != 0) {
dev_warn(&pdev->dev,
"Invalid OEM header signature\n");
return NULL;
}
/* calculate checksum */
tmp = (u8 *)efi_data;
for (j = 0, sum = 0; j < (sizeof(*oem_hdr) + sizeof(*rom)); j++, tmp++)
sum += *tmp;
if (sum != 0) {
dev_warn(&pdev->dev,
"OEM table checksum failed\n");
return NULL;
}
if (memcmp(rom->hdr.signature,
ISCI_ROM_SIG,
ISCI_ROM_SIG_SIZE) != 0) {
dev_warn(&pdev->dev,
"Invalid OEM table signature\n");
return NULL;
}
return rom;
}

View File

@ -0,0 +1,249 @@
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
*
* BSD LICENSE
*
* Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ISCI_PROBE_ROMS_H_
#define _ISCI_PROBE_ROMS_H_
#ifdef __KERNEL__
#include <linux/firmware.h>
#include <linux/pci.h>
#include <linux/efi.h>
#include "isci.h"
#define SCIC_SDS_PARM_NO_SPEED 0
/* generation 1 (i.e. 1.5 Gb/s) */
#define SCIC_SDS_PARM_GEN1_SPEED 1
/* generation 2 (i.e. 3.0 Gb/s) */
#define SCIC_SDS_PARM_GEN2_SPEED 2
/* generation 3 (i.e. 6.0 Gb/s) */
#define SCIC_SDS_PARM_GEN3_SPEED 3
#define SCIC_SDS_PARM_MAX_SPEED SCIC_SDS_PARM_GEN3_SPEED
/* parameters that can be set by module parameters */
struct sci_user_parameters {
struct sci_phy_user_params {
/**
* This field specifies the NOTIFY (ENABLE SPIN UP) primitive
* insertion frequency for this phy index.
*/
u32 notify_enable_spin_up_insertion_frequency;
/**
* This method specifies the number of transmitted DWORDs within which
* to transmit a single ALIGN primitive. This value applies regardless
* of what type of device is attached or connection state. A value of
* 0 indicates that no ALIGN primitives will be inserted.
*/
u16 align_insertion_frequency;
/**
* This method specifies the number of transmitted DWORDs within which
* to transmit 2 ALIGN primitives. This applies for SAS connections
* only. A minimum value of 3 is required for this field.
*/
u16 in_connection_align_insertion_frequency;
/**
* This field indicates the maximum speed generation to be utilized
* by phys in the supplied port.
* - A value of 1 indicates generation 1 (i.e. 1.5 Gb/s).
* - A value of 2 indicates generation 2 (i.e. 3.0 Gb/s).
* - A value of 3 indicates generation 3 (i.e. 6.0 Gb/s).
*/
u8 max_speed_generation;
} phys[SCI_MAX_PHYS];
/**
* This field specifies the maximum number of direct attached devices
* that can have power supplied to them simultaneously.
*/
u8 max_number_concurrent_device_spin_up;
/**
* This field specifies the number of seconds to allow a phy to consume
* power before yielding to another phy.
*
*/
u8 phy_spin_up_delay_interval;
/**
* These timer values specifies how long a link will remain open with no
* activity in increments of a microsecond, it can be in increments of
* 100 microseconds if the upper most bit is set.
*
*/
u16 stp_inactivity_timeout;
u16 ssp_inactivity_timeout;
/**
* These timer values specifies how long a link will remain open in increments
* of 100 microseconds.
*
*/
u16 stp_max_occupancy_timeout;
u16 ssp_max_occupancy_timeout;
/**
* This timer value specifies how long a link will remain open with no
* outbound traffic in increments of a microsecond.
*
*/
u8 no_outbound_task_timeout;
};
#define SCIC_SDS_PARM_PHY_MASK_MIN 0x0
#define SCIC_SDS_PARM_PHY_MASK_MAX 0xF
#define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4
struct sci_oem_params;
int sci_oem_parameters_validate(struct sci_oem_params *oem);
struct isci_orom;
struct isci_orom *isci_request_oprom(struct pci_dev *pdev);
enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem,
struct isci_orom *orom, int scu_index);
struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw);
struct isci_orom *isci_get_efi_var(struct pci_dev *pdev);
struct isci_oem_hdr {
u8 sig[4];
u8 rev_major;
u8 rev_minor;
u16 len;
u8 checksum;
u8 reserved1;
u16 reserved2;
} __attribute__ ((packed));
#else
#define SCI_MAX_PORTS 4
#define SCI_MAX_PHYS 4
#define SCI_MAX_CONTROLLERS 2
#endif
#define ISCI_FW_NAME "isci/isci_firmware.bin"
#define ROMSIGNATURE 0xaa55
#define ISCI_OEM_SIG "$OEM"
#define ISCI_OEM_SIG_SIZE 4
#define ISCI_ROM_SIG "ISCUOEMB"
#define ISCI_ROM_SIG_SIZE 8
#define ISCI_EFI_VENDOR_GUID \
EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, \
0x1a, 0x04, 0xc6)
#define ISCI_EFI_VAR_NAME "RstScuO"
/* Allowed PORT configuration modes APC Automatic PORT configuration mode is
* defined by the OEM configuration parameters providing no PHY_MASK parameters
* for any PORT. i.e. There are no phys assigned to any of the ports at start.
* MPC Manual PORT configuration mode is defined by the OEM configuration
* parameters providing a PHY_MASK value for any PORT. It is assumed that any
* PORT with no PHY_MASK is an invalid port and not all PHYs must be assigned.
* A PORT_PHY mask that assigns just a single PHY to a port and no other PHYs
* being assigned is sufficient to declare manual PORT configuration.
*/
enum sci_port_configuration_mode {
SCIC_PORT_MANUAL_CONFIGURATION_MODE = 0,
SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE = 1
};
struct sci_bios_oem_param_block_hdr {
uint8_t signature[ISCI_ROM_SIG_SIZE];
uint16_t total_block_length;
uint8_t hdr_length;
uint8_t version;
uint8_t preboot_source;
uint8_t num_elements;
uint16_t element_length;
uint8_t reserved[8];
} __attribute__ ((packed));
struct sci_oem_params {
struct {
uint8_t mode_type;
uint8_t max_concurrent_dev_spin_up;
uint8_t do_enable_ssc;
uint8_t reserved;
} controller;
struct {
uint8_t phy_mask;
} ports[SCI_MAX_PORTS];
struct sci_phy_oem_params {
struct {
uint32_t high;
uint32_t low;
} sas_address;
uint32_t afe_tx_amp_control0;
uint32_t afe_tx_amp_control1;
uint32_t afe_tx_amp_control2;
uint32_t afe_tx_amp_control3;
} phys[SCI_MAX_PHYS];
} __attribute__ ((packed));
struct isci_orom {
struct sci_bios_oem_param_block_hdr hdr;
struct sci_oem_params ctrl[SCI_MAX_CONTROLLERS];
} __attribute__ ((packed));
#endif

Some files were not shown because too many files have changed in this diff Show More