Lenovo IdeaPad Y580

From ArchWiki
Revision as of 05:10, 11 July 2012 by Onefire (Talk | contribs)

Jump to: navigation, search

Introduction

The Lenovo IdeaPad Y580 started shipping in June 2012. It is a fairly powerful machine, but it has its own compatibility issues. Hopefully this will help someone who wants to set it up with Arch Linux (it may also work with other distros).

Installation

As of 07/11/2012, the latest official iso is from 08/19/2011. Unfortunately this iso does not have the firmware necessary for the Y580. As a result, I could not get wifi with it. Download a snapshot: http://releng.archlinux.org/isos/ and you should be able to set it up to use wpa_supplicant to connect to a wireless network. However, AIF may not work with these images (sometimes it gets stuck on the partitioning phase). If that happens you can use this guide to install from the livecd: https://wiki.archlinux.org/index.php/Install_from_Existing_Linux. In theory this can be done from any distro, but it is much easier to do it from the Arch live cd since in this case you do not need to manually install Pacman.

If you cannot get wireless working, you can use an ethernet connection with the help of the driver alx. This driver is not yet part of the Linux kernel, and that is why your ethernet card is not recognized at first. You need to download the driver from the Linux Foundation's website:

wget http://www.orbit-lab.org/kernel/compat-wireless-2.6/2012/03/compat-wireless-2012-03-12-p.tar.bz2

Copy the tarball to a flash drive, boot the live cd, mount the flash drive, cd to the directory with the tarball and use:

tar -xjvf compat*
cd compat*
./scripts/driver-select alx 
make
sudo make install   

After this, load the module (modprobe alx) and you should be able to get ethernet working easily.

My model has a 32GB SSD drive and a 1TB 5400 rpm drive. It comes with Windows 7 and some Lenovo partitions that may be important if you need to recover the Windows install. Since I was positive about only using Linux, I just deleted everything so that I could use the SSD drive to install Arch (and get a faster boot). But you may want to think twice before doing this, or at least backup the partition's contents before erasing them.

Also, this laptop can use UEFI. If you want to use it, you need to a GPT partition (see below).

UEFI

At this point, I am not sure whether UEFI is actually necessary, but it seems to be the future, so I do suggest that you set it up. First read these pages: ttps://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface and https://wiki.archlinux.org/index.php/GRUB2.

Among other things, you need a gpt partition and grub2. You can do these things when you are installing the system, but I suggest that you get a base system working with grub first, and then install grub2. To install Arch on the SSD drive, you need at least two partitions: one small (100 MB) boot partition, and another partition for /. To partition the drives, you can use cgdisk, which you can get by installing the package gpttools.

I suggest that you partition both drives using gpt, but i is even possible to convert a MBR partition table to gpt, which is what I ended up doing. You should also create a third partition (with about 1GB) for EFI. This partition needs to be of EFI system type (code ef00 on gdisk) and it should be formatted as FAT32. If the partition is /dev/sda2, use:

mkfs.vfat -F32 /dev/sda3  

After you have your base system up and running, install the grub 2 firmware:

pacman -S grub2-efi-x86_64

mount the system partition at /boot/efi:

mkdir /boot/efi
mount -t vfat /dev/sda3 /boot/efi

Install grub2 efi app (grubx64.efi) to /boot/efi/EFI/arch_grub, and its modules to /boot/efi/EFI/grub/x86_64-efi:

grub-install --directory=/usr/lib/grub/x86_64-efi --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=arch_grub --boot-directory=/boot/efi/EFI --recheck --debug
mkdir -p /boot/efi/EFI/grub/locale
cp /usr/share/locale/en@quot/LC_MESSAGES/grub.mo /boot/efi/EFI/grub/locale/en.mo

The grub2 wiki page says to copy the app to other places. This is probably not necessary, but you may want to do:

mkdir /boot/efi/EFI/tools
cp /boot/efi/EFI/arch_grub/grubx64.efi /boot/efi/shellx64.efi
cp /boot/efi/EFI/arch_grub/grubx64.efi /boot/efi/EFI/shellx64.efi
cp /boot/efi/EFI/arch_grub/grubx64.efi /boot/efi/EFI/tools/shellx64.efi   

Now comes the part where the grub 2 page is not very clear. You need to add the system to the UEFI menu (the menu that shows up when you press F12 at boot). To do this, you need an UEFI shell. The Y580 does not come with a shell built in, but you can put one in a flash drive and boot from it. To do this, get a bootable flash drive, create a partition (1GB is enough) and format it as FAT32. Assuming that the partition is /dev/sdc1, type the following:

mount /dev/sdc1 /media
mkdir /media/efi/boot
cd /media/efi/boot
wget https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2/ShellBinPkg/UefiShell/X64/Shell.efi
mv Shell.efi bootx64.efi
cd /
umount /media  

The code creates a directory /efi/boot in the flash drive, downloads the shell, copies it to /efi/boot and renames it as bootx64.efi. The shell is downloaded from the link given here: https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface#UEFI_Shell. Note that you need a 2.0 shell, otherwise you will not be able to add an entry to the menu.

Now reboot, go to the BIOS (press F2), enable UEFI and exit, then press F12 and the flash drive should show up in the menu (you want to choose the UEFI entry). Now you should be in the UEFI shell. There is quite a lot that you can do, bu be careful because a mistake can seriously compromise the machine. This guide may be worth looking at: http://software.intel.com/en-us/articles/uefi-shell/

For now, you just need bcfg. To add Arch to the first entry of the menu, use:

bcfg boot add 0 fs1:\EFI\arch_grub\grubx64.efi "Arch Linux"  

The command assumes that the system partition is installed on the first drive. This partition has the loader (grubx64.efi) and this little program is what loads grub2. If you add Arch to the first entry, you can boot to it without pressing F12.

To see the menu entries, use:

bcfg boot dump -v

To delete, say the 3rd entry:

bcfg boot rm 3

Once you are happy with the menu entries, reboot and you should be able to boot into Arch.

Dual Boot With Windows 8

Because of my troubles getting CUDA to work with the Y580 (see below), I installed the Windows 8 release preview. To avoid problems with the Arch install, put Windows on the second drive (this means that the second drive should also have a GUID partition table, since Windows 8 only works with one).

Windows 8 uses UEFI, so you can press F12 to choose between Arch and Windows, or just adjust this at the BIOS. Another option is to use the Windows program EasyBCD and add Arch to the Windows boot loader. However, I decided to add Windows to grub2.

To do this, from Arch, mount the Windows system partition and find its UUID:

mount /dev/sdb1 /mnt
grub-probe --target=fs_uuid /media/EFI/Microsoft/Boot/bootmgfw.efi   

Take note of the output (something like 1ce5-7f28). Now copy the output of:

grub-probe --target=hints_string /media/EFI/Microsoft/Boot/bootmgfw.efi

Then, add something like this to /etc/grub.d/0_custom:

menuentry "Microsoft Windows 8 x86_64 UEFI-GPT" {
    insmod part_gpt
    insmod fat
    insmod search_fs_uuid
    insmod chain
    search --fs-uuid --no-floppy --set=root --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1 1ce5-7f28
    chainloader /efi/Microsoft/Boot/bootmgfw.efi
}

Finally generate the grub2 configuration file (grub.cfg):

grub-mkconfig -o /boot/efi/EFI/grub/grub.cfg

Now you should be able to see an entry for Windows 8 on grub2.

The Y580 has a huge 1TB second drive, making it easy to install other OS. With grub2, you can install other distros, and then run grub-mkconfig to add the new entry. To make this easier, install os-prober so that grub2 can find other OS automatically (it does not work for Windows 8):

pacman -S os-prober

NVIDIA Card

The Y580 uses "switchable graphics" which, according to some, is not really Optimus but something else. NVIDIA does not support Optimus (or whatever the Y580 has) on Linux, so a possible solution is to install Bumblebee (https://wiki.archlinux.org/index.php/Bumblebee) and to access the card with Optirun. As far as I know, this currently does not work with the Y580. However, you can still use CUDA, which is good if you use apps like Blender or if, like me, you develop CUDA C programs.

Lenovo machines (Y470, Y570, Y580) require a hack: https://github.com/koniiiik/bbswitch/tree/hack-lenovo created by https://github.com/koniiiik. Without this, the system cannot even see your card. To compile the acpi-handle-hack module and install it, use:

git clone git://github.com/Bumblebee-Project/bbswitch.git -b hack-lenovo
cd bbswitch
mkdir /usr/src/acpi-handle-hack-0.0.1
cp Makefile acpi-handle-hack.c /usr/src/acpi-handle-hack-0.0.1
cp dkms/acpi-handle-hack.conf /usr/src/acpi-handle-hack-0.0.1/dkms.conf
dkms add acpi-handle-hack/0.0.1
dkms build acpi-handle-hack/0.0.1
dkms install acpi-handle-hack/0.0.1  

There is also an AUR package: https://aur.archlinux.org/packages.php?ID=60474 but I have not tried it.

Add the acpi-handle-hack to your /etc/rc.conf file, so that it is loaded at boot.

Driver

To compile and run CUDA programs, you need a NVIDIA driver and the cuda-toolkit. There are two drivers that are supposedly compatible with the GeForce GTX 660M, 295.59 and 302.17. Many distros (including Arch) have the newest driver, 302.17 as default for their packages, but this did not work for me. The 295.59 did. To install the 295.59, you need to modify two packages from extra, nvidia-utils and nvidia. To do this, you use ABS. If you are not familiar with it, read the wiki: https://wiki.archlinux.org/index.php/Arch_Build_System. The exact way to rebuild a package depends on your own preferences, but I usually download the source code (in this case, the driver, obtained here: http://www.nvidia.com/content/DriverDownload-March2009/confirmation.php?url=/XFree86/Linux-x86_64/295.59/NVIDIA-Linux-x86_64-295.59.run&lang=us&type=GeForce), copy it to the build directory, and then set up the PKGBUILD such that it uses that file instead of downloading it. In the current case, since you need the driver for both packages, nvidia and nvidia-utils, this saves a bit of time.

Edit the PKGBUILD of nvidia-utils. You need to change the pkgver, the source item, and the md5sum. Also, nividia-utils conflicts with libgl, but if you uninstall libgl, Gnome only starts in fallback mode (not sure about other DE). Because of this, you need to modify the PKGBUILD, so that it either does not install certain libraries (libglx.so, libGL.so) or that it installs them in another location.

For the nvidia package, you need to change the pkgver to 295.59, the source, the md5sum and a few other items. After changing the PKGBUILDs, run makepkg to build the packages, and makepkg -is to install them (you need to install nvidia-utils first). The PKGBUILDs that I used are listed below:

nvidia-utils PKGBUILD

# $Id: PKGBUILD 161949 2012-06-16 22:01:05Z ibiru $
# Maintainer: Thomas Baechler <thomas@archlinux.org>
# Contributor: James Rayner <iphitus@gmail.com>
pkgbase=nvidia-utils
pkgname=('nvidia-utils' 'opencl-nvidia')
pkgver=295.59
pkgrel=1
arch=('i686' 'x86_64')
url="http://www.nvidia.com/"
license=('custom')
options=('!strip')

if [ "$CARCH" = "i686" ]; then
    _arch='x86'
    _pkg="NVIDIA-Linux-${_arch}-${pkgver}"
    source=("ftp://download.nvidia.com/XFree86/Linux-${_arch}/${pkgver}/${_pkg}.run")
	md5sums=('b7f908ea08218df08db06026215ec419')
elif [ "$CARCH" = "x86_64" ]; then
    _arch='x86_64'
    _pkg="NVIDIA-Linux-${_arch}-${pkgver}-no-compat32"
    source=("NVIDIA-Linux-x86_64-295.59.run")
    md5sums=('a921cfdb0162b9bb788c4486b1e6d725')
fi

create_links() {
    # create soname links
    while read -d '' _lib; do
        _soname="$(dirname "${_lib}")/$(readelf -d "${_lib}" | sed -nr 's/.*Library soname: \[(.*)\].*/\1/p')"
        [[ -e "${_soname}" ]] || ln -s "$(basename "${_lib}")" "${_soname}"
        [[ -e "${_soname/.[0-9]*/}" ]] || ln -s "$(basename "${_soname}")" "${_soname/.[0-9]*/}"
    done < <(find "${pkgdir}" -type f -name '*.so*' -print0)
}

build() {
    cd "${srcdir}"
    sh "NVIDIA-Linux-x86_64-295.59.run" --extract-only
}

package_opencl-nvidia() {
    pkgdesc="OpenCL implemention for NVIDIA"
    depends=('libcl' 'zlib')
    optdepends=('opencl-headers: headers necessary for OpenCL development')
    cd "${srcdir}/NVIDIA-Linux-x86_64-295.59"

    # OpenCL
    install -D -m644 nvidia.icd "${pkgdir}/etc/OpenCL/vendors/nvidia.icd"
    install -D -m755 "libnvidia-compiler.so.${pkgver}" "${pkgdir}/usr/lib/libnvidia-compiler.so.${pkgver}"
    # CUDA
    install -D -m755 "libcuda.so.${pkgver}" "${pkgdir}/usr/lib/libcuda.so.${pkgver}"
    install -D -m755 "libnvcuvid.so.${pkgver}" "${pkgdir}/usr/lib/libnvcuvid.so.${pkgver}"
    create_links
}

package_nvidia-utils() {
    pkgdesc="NVIDIA drivers utilities and libraries."
    depends=('xorg-server' 'libxvmc')
    optdepends=('gtk2: nvidia-settings' 'pkg-config: nvidia-xconfig'
                'opencl-nvidia: OpenCL support')
    conflicts=('')
    provides=('libgl')
    cd "${srcdir}/NVIDIA-Linux-x86_64-295.59"

    # X driver
    install -D -m755 nvidia_drv.so "${pkgdir}/usr/lib/xorg/modules/drivers/nvidia_drv.so"
    # GLX extension module for X
   # install -D -m755 "libglx.so.${pkgver}" "${pkgdir}/usr/lib/xorg/modules/extensions/libglx.so.${pkgver}"
    #ln -s "libglx.so.${pkgver}" "${pkgdir}/usr/lib/xorg/modules/extensions/libglx.so"	# X doesn't find glx otherwise
    # OpenGL library
    #install -D -m755 "libGL.so.${pkgver}" "${pkgdir}/usr/lib/libGL.so.${pkgver}"
    # OpenGL core library
    install -D -m755 "libnvidia-glcore.so.${pkgver}" "${pkgdir}/usr/lib/libnvidia-glcore.so.${pkgver}"
    # XvMC
    install -D -m644 libXvMCNVIDIA.a "${pkgdir}/usr/lib/libXvMCNVIDIA.a"
    install -D -m755 "libXvMCNVIDIA.so.${pkgver}" "${pkgdir}/usr/lib/libXvMCNVIDIA.so.${pkgver}"
    # VDPAU
    install -D -m755 "libvdpau_nvidia.so.${pkgver}" "${pkgdir}/usr/lib/vdpau/libvdpau_nvidia.so.${pkgver}"
    # nvidia-tls library
    install -D -m755 "tls/libnvidia-tls.so.${pkgver}" "${pkgdir}/usr/lib/libnvidia-tls.so.${pkgver}"
    install -D -m755 "libnvidia-cfg.so.${pkgver}" "${pkgdir}/usr/lib/libnvidia-cfg.so.${pkgver}"

    install -D -m755 "libnvidia-ml.so.${pkgver}" "${pkgdir}/usr/lib/libnvidia-ml.so.${pkgver}"

    # nvidia-xconfig
    install -D -m755 nvidia-xconfig "${pkgdir}/usr/bin/nvidia-xconfig"
    install -D -m644 nvidia-xconfig.1.gz "${pkgdir}/usr/share/man/man1/nvidia-xconfig.1.gz"
    # nvidia-settings
    install -D -m755 nvidia-settings "${pkgdir}/usr/bin/nvidia-settings"
    install -D -m644 nvidia-settings.1.gz "${pkgdir}/usr/share/man/man1/nvidia-settings.1.gz"
    install -D -m644 nvidia-settings.desktop "${pkgdir}/usr/share/applications/nvidia-settings.desktop"
    install -D -m644 nvidia-settings.png "${pkgdir}/usr/share/pixmaps/nvidia-settings.png"
    sed -e 's:__UTILS_PATH__:/usr/bin:' -e 's:__PIXMAP_PATH__:/usr/share/pixmaps:' -i "${pkgdir}/usr/share/applications/nvidia-settings.desktop"
    # nvidia-bug-report
    install -D -m755 nvidia-bug-report.sh "${pkgdir}/usr/bin/nvidia-bug-report.sh"
    # nvidia-smi
    install -D -m755 nvidia-smi "${pkgdir}/usr/bin/nvidia-smi"
    install -D -m644 nvidia-smi.1.gz "${pkgdir}/usr/share/man/man1/nvidia-smi.1.gz"


    install -D -m644 LICENSE "${pkgdir}/usr/share/licenses/nvidia/LICENSE"
    ln -s nvidia "${pkgdir}/usr/share/licenses/nvidia-utils"
    install -D -m644 README.txt "${pkgdir}/usr/share/doc/nvidia/README"
    install -D -m644 NVIDIA_Changelog "${pkgdir}/usr/share/doc/nvidia/NVIDIA_Changelog"
    ln -s nvidia "${pkgdir}/usr/share/doc/nvidia-utils"

    create_links
}

nvidia PKGBUILD

# $Id: PKGBUILD 161948 2012-06-16 22:01:05Z ibiru $
# Maintainer : Thomas Baechler <thomas@archlinux.org>

pkgname=nvidia
pkgver=295.59
_extramodules=extramodules-3.4-ARCH
pkgrel=1
pkgdesc="NVIDIA drivers for linux."
arch=('i686' 'x86_64')
url="http://www.nvidia.com/"
depends=('linux>=3.4' 'linux<3.5' "nvidia-utils=${pkgver}")
makedepends=('linux-headers>=3.4' 'linux-headers<3.5')
conflicts=('nvidia-96xx' 'nvidia-173xx')
license=('custom')
install=nvidia.install
options=(!strip)

if [ "$CARCH" = "i686" ]; then
    _arch='x86'
    _pkg="NVIDIA-Linux-${_arch}-${pkgver}"
    source=("ftp://download.nvidia.com/XFree86/Linux-${_arch}/${pkgver}/${_pkg}.run")
    md5sums=('b7f908ea08218df08db06026215ec419')
elif [ "$CARCH" = "x86_64" ]; then
    _arch='x86_64'
   _pkg="NVIDIA-Linux-${_arch}-${pkgver}"
    source=("NVIDIA-Linux-x86_64-295.59.run")
    md5sums=('a921cfdb0162b9bb788c4486b1e6d725')
fi

build() {
    _kernver="$(cat /lib/modules/${_extramodules}/version)"
    cd "${srcdir}"
    sh "${_pkg}.run" --extract-only
    cd "${_pkg}/kernel"
    make SYSSRC=/lib/modules/"${_kernver}/build" module
}

package() {
    install -D -m644 "${srcdir}/${_pkg}/kernel/nvidia.ko" \
        "${pkgdir}/lib/modules/${_extramodules}/nvidia.ko"
    install -d -m755 "${pkgdir}/usr/lib/modprobe.d"
    echo "blacklist nouveau" >> "${pkgdir}/usr/lib/modprobe.d/nvidia.conf"
    sed -i -e "s/EXTRAMODULES='.*'/EXTRAMODULES='${_extramodules}'/" "${startdir}/nvidia.install"
    gzip "${pkgdir}/lib/modules/${_extramodules}/nvidia.ko"
}

CUDA Toolkit

Install the package from community. If that does not work, rebuild the package so that it uses the ubuntu11.04 version from NVIDIA's website. As before, this can be accomplished by first downloading the executable, copying it to the build directory, and changing the pkgver, source and md5sum entries of the PKGBUILD. In this case you need to edit a few other entries (the official package uses the fedora toolkit), but it should be easy. If you prefer, you can use the version below:

# $Id: PKGBUILD 69720 2012-04-23 02:57:16Z svenstaro $
# Maintainer: Sven-Hendrik Haase <sh@lutzhaase.com>
pkgname=cuda-toolkit
pkgver=4.2.9
pkgrel=1
_fedver=13
pkgdesc="NVIDIA's GPU programming toolkit"
arch=('i686' 'x86_64')
url="http://www.nvidia.com/object/cuda_home.html"
license=('custom')
depends=('gcc-libs' 'opencl-nvidia')
optdepends=('gdb: for cuda-gdb')
if [ "$CARCH" = "i686" ]; then
  _arch=32
  md5sums=('4ef372799a4343a3d9929b5334e1a723'
           '5af5226b36cd3f9993f762f85b5d236a'
           'c0781c63e726eaf03e10135b42b85729')
else
  _arch=64
  md5sums=('6bdf205ea4ef1f846eb66e00dc137e0e'
           '5af5226b36cd3f9993f762f85b5d236a'
           'c0781c63e726eaf03e10135b42b85729')
fi
install=cuda-toolkit.install
source=(cudatoolkit_4.2.9_linux_64_ubuntu11.04.run
        cuda-toolkit.sh
        cuda-toolkit.conf)

build() {
  cd "$srcdir"
}

package() {
  cd "$srcdir"

  mkdir -p $pkgdir/opt/cuda-toolkit
  sh cudatoolkit_4.2.9_linux_64_ubuntu11.04.run --keep -- --prefix=$pkgdir/opt/cuda-toolkit

  sed -i "/unsupported GNU/d" $pkgdir/opt/cuda-toolkit/include/host_config.h
 # sed -i "s|/build/pkg||g" $pkgdir/opt/cuda-toolkit/bin/nvvp

  install -Dm755 cuda-toolkit.sh $pkgdir/etc/profile.d/cuda-toolkit.sh
  install -Dm644 cuda-toolkit.conf $pkgdir/etc/ld.so.conf.d/cuda-toolkit.conf
  install -Dm644 $pkgdir/opt/cuda-toolkit/doc/EULA.txt $pkgdir/usr/share/licenses/$pkgname/LICENSE

  mkdir -p $pkgdir/usr/lib
  cd $pkgdir/usr/lib
  ln -s /usr/lib/libncurses.so.5 libtinfo.so.5
}   

Configurations

You need to load the acpi-handle-hack module first, then the nvidia module. Depending on your system, this may be enough, but it may be necessary to create devices for CUDA. One way to accomplish this is to add the following to your /etc/rc.local:

/sbin/modprobe acpi-handle-hack
/sbin/modprobe nvidia

if [ "$?" -eq 0 ]; then

# Count the number of NVIDIA controllers found.

N3D=`lspci | grep -i NVIDIA | grep "3D controller" | wc -l`

NVGA=`lspci | grep -i NVIDIA | grep "VGA compatible controller" | wc -l`

N=`expr $N3D + $NVGA - 1`

for i in `seq 0 $N`; do
mknod -m 666 /dev/nvidia$i c 195 $i
done

mknod -m 666 /dev/nvidiactl c 195 255
else
exit 1

Testing it

This is not necessary, but you may want to install the community package cuda-sdk:

pacman -S cuda-sdk

The package is installed to /opt/cuda-sdk. To compile the CUDA C samples, use:

cd /opt/cuda-sdk/C
make

Now reboot and cuda should be working. To test it, run deviceQuery from the sdk:

/opt/cuda-sdk/C/bin/linux/release/deviceQuery

Alternatively, you can compile your own code and run it. To compile, say hello.cu, use:

nvcc hello.cu

Now you can run the executable:

./a.out

If this works without errors, you are all set!