Repository navigation
Expand file tree
/
Copy pathnpu_installer.sh
More file actions
executable file
·566 lines (486 loc) · 19.1 KB
/
Copy pathnpu_installer.sh
File metadata and controls
executable file
·566 lines (486 loc) · 19.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
#!/bin/bash
# NPU (Neural Processing Unit) Installer for Core Ultra platforms
# Installs Intel NPU drivers with Level Zero support
# Copyright (C) 2026 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
#
# Version Management:
#
# By default the newest upstream release is installed. It is resolved from the
# github.com release pages (the /releases/latest redirect and the expanded
# assets list), not from api.github.com, which is rate limited to 60
# requests/hour per source IP and made installs fail behind shared NAT or
# corporate proxies. See issue #1038.
#
# The libze1 Level Zero loader URL is read from the same release notes, so it
# follows the driver release.
#
# If the release pages cannot be parsed, the API is tried, then the pinned
# release below is installed.
#
# Overrides:
# NPU_VERSION=pinned install the pinned fallback release, no lookup
# NPU_VERSION + NPU_BUILD_ID install a specific release, no lookup
# NPU_ASSET_URL full tar.gz URL, no lookup
# LIBZE1_URL full libze1 .deb URL
# GITHUB_TOKEN raises the API quota to 5000/hour when used
#
# Releases: https://github.com/intel/linux-npu-driver/releases
#
# Usage:
# sudo ./npu_installer.sh
# sudo NPU_VERSION=pinned ./npu_installer.sh
# sudo NPU_VERSION=1.32.1 NPU_BUILD_ID=20260422-24767473183 ./npu_installer.sh
# Fallback release, used only when the newest release cannot be resolved.
readonly NPU_PINNED_VERSION="1.38.0"
readonly NPU_PINNED_BUILD_ID="20260910-34487311128"
# Fallback libze1, used when the release notes don't list one
readonly LIBZE1_VERSION="1.32.0-1"
readonly LIBZE1_SNAPSHOT="20260830T100000Z"
readonly NPU_REPO_URL="https://github.com/intel/linux-npu-driver"
NPU_VERSION="${NPU_VERSION:-latest}"
NPU_BUILD_ID="${NPU_BUILD_ID:-}"
NPU_ASSET_URL="${NPU_ASSET_URL:-}"
LIBZE1_URL="${LIBZE1_URL:-}"
NPU_SOURCE=""
log_success() {
echo "$S_VALID $1"
}
# Print the libze1 .deb URL for this Ubuntu release found in stdin, if any
extract_libze1_url() {
grep -oE "https://snapshot\.ppa\.launchpadcontent\.net/[^\"<[:space:]\\]+/libze1_[^\"<[:space:]/\\]+~${UBUNTU_RELEASE}~ppa1_amd64\.deb" | head -1
}
# Resolve the newest release from github.com pages (not the rate limited API)
resolve_latest_web() {
local tag path name
local -a curl_opts=(-sS -L --connect-timeout 10 --max-time 30)
tag=$(curl -sS -o /dev/null -w '%{redirect_url}' --connect-timeout 10 --max-time 30 \
"${NPU_REPO_URL}/releases/latest" 2>/dev/null | sed -nE 's#.*/releases/tag/v([0-9]+(\.[0-9]+)*)$#\1#p')
[ -n "$tag" ] || return 1
path=$(curl "${curl_opts[@]}" "${NPU_REPO_URL}/releases/expanded_assets/v${tag}" 2>/dev/null \
| grep -oE "href=\"/intel/linux-npu-driver/releases/download/v${tag}/linux-npu-driver-v${tag}\.[0-9]+-[0-9]+-${UBUNTU_VERSION}\.tar\.gz\"" \
| head -1 | sed -E 's/^href="([^"]+)"$/\1/')
if [ -z "$path" ]; then
GITHUB_API_ERROR="Latest release v${tag} has no ${UBUNTU_VERSION} package"
return 1
fi
name=$(basename "$path")
name="${name#linux-npu-driver-v"${tag}".}"
NPU_BUILD_ID="${name%-"${UBUNTU_VERSION}".tar.gz}"
NPU_VERSION="$tag"
NPU_ASSET_URL="https://github.com${path}"
[ -z "$LIBZE1_URL" ] && LIBZE1_URL=$(curl "${curl_opts[@]}" "${NPU_REPO_URL}/releases/tag/v${tag}" 2>/dev/null | extract_libze1_url)
return 0
}
# Resolve latest release and asset URL from GitHub (no jq required)
GITHUB_API_ERROR=""
resolve_latest_release() {
local json url tag asset_name http_code body hdr
local -a auth=()
[ -n "${GITHUB_TOKEN:-}" ] && auth=(-H "Authorization: Bearer ${GITHUB_TOKEN}")
body=$(mktemp); hdr="${body}.hdr"
http_code=$(curl -sS -L -o "$body" -D "$hdr" -w '%{http_code}' \
--connect-timeout 10 --max-time 30 \
-H "Accept: application/vnd.github+json" "${auth[@]}" \
https://api.github.com/repos/intel/linux-npu-driver/releases/latest 2>/dev/null) || http_code="000"
case "$http_code" in
200) json=$(cat "$body") ;;
403|429)
if [ "$(grep -i '^x-ratelimit-remaining:' "$hdr" 2>/dev/null | tr -d '\r' | awk '{print $2}')" = "0" ]; then
GITHUB_API_ERROR="GitHub API rate limit exhausted for this source IP"
else
GITHUB_API_ERROR="GitHub API returned HTTP $http_code"
fi
;;
000) GITHUB_API_ERROR="Cannot reach api.github.com (network or proxy)" ;;
*) GITHUB_API_ERROR="GitHub API returned HTTP $http_code" ;;
esac
rm -f "$body" "$hdr"
if [ -n "$json" ]; then
tag=$(echo "$json" | grep -m1 '"tag_name"' | sed -E 's/.*"v?([^"]+)".*/\1/' )
url=$(echo "$json" | grep '"browser_download_url"' | grep -E "${UBUNTU_VERSION}\.tar\.gz" | head -1 | sed -E 's/.*"(https:[^"]+)".*/\1/')
[ -z "$url" ] && GITHUB_API_ERROR="Latest release v${tag} has no ${UBUNTU_VERSION} package"
if [ -n "$url" ]; then
NPU_ASSET_URL="$url"
NPU_VERSION="$tag"
asset_name=$(basename "$url")
# Expected: linux-npu-driver-v<version>.<build>-<ubuntu>.tar.gz
NPU_BUILD_ID=$(echo "$asset_name" | sed -E 's/^linux-npu-driver-v[0-9.]+\.([0-9]+-[0-9]+)-.*/\1/' )
[ -z "$LIBZE1_URL" ] && LIBZE1_URL=$(echo "$json" | extract_libze1_url)
return 0
fi
fi
return 1
}
# Derive/resolve versions honoring overrides
resolve_versions() {
# If user provided a direct asset URL, prefer it
if [ -n "${NPU_ASSET_URL:-}" ]; then
local asset_name
asset_name=$(basename "$NPU_ASSET_URL")
if [ "$NPU_VERSION" = "latest" ] || [ "$NPU_VERSION" = "pinned" ]; then
NPU_VERSION=$(echo "$asset_name" | sed -E 's/^linux-npu-driver-v([0-9.]+)\.[0-9]+-[0-9]+-.*/\1/')
fi
NPU_BUILD_ID=${NPU_BUILD_ID:-$(echo "$asset_name" | sed -E 's/^linux-npu-driver-v[0-9.]+\.([0-9]+-[0-9]+)-.*/\1/')}
NPU_SOURCE="${NPU_SOURCE:-override}"
return 0
fi
if [ "$NPU_VERSION" = "latest" ]; then
NPU_VERSION=""
if resolve_latest_web || resolve_latest_release; then
NPU_SOURCE="latest"
return 0
fi
print_warning "Unable to resolve the latest NPU release, falling back to ${NPU_PINNED_VERSION}"
[ -n "${GITHUB_API_ERROR:-}" ] && print_warning " $GITHUB_API_ERROR"
NPU_VERSION="pinned"
fi
if [ "$NPU_VERSION" = "pinned" ]; then
NPU_VERSION="$NPU_PINNED_VERSION"
NPU_BUILD_ID="$NPU_PINNED_BUILD_ID"
NPU_SOURCE="pinned"
fi
# Version + build id, construct the URL
if [ -n "${NPU_VERSION:-}" ] && [ -n "${NPU_BUILD_ID:-}" ]; then
NPU_ASSET_URL="${NPU_REPO_URL}/releases/download/v${NPU_VERSION}/linux-npu-driver-v${NPU_VERSION}.${NPU_BUILD_ID}-${UBUNTU_VERSION}.tar.gz"
NPU_SOURCE="${NPU_SOURCE:-override}"
return 0
fi
print_error "Unable to resolve the NPU release"
print_error "NPU_VERSION=${NPU_VERSION} also needs NPU_BUILD_ID, or set NPU_ASSET_URL"
return 1
}
# Auto-detect Ubuntu version
UBUNTU_VERSION=""
UBUNTU_RELEASE=""
detect_ubuntu_version() {
local ubuntu_ver
ubuntu_ver=$(lsb_release -r | awk '{print $2}')
case "$ubuntu_ver" in
"24.04")
UBUNTU_VERSION="ubuntu2404"
;;
"26.04")
UBUNTU_VERSION="ubuntu2604"
;;
*)
print_warning "Unsupported Ubuntu version: $ubuntu_ver"
print_warning "This script supports Ubuntu 24.04 and 26.04 LTS"
print_error "Please upgrade to Ubuntu 24.04 or 26.04 LTS for NPU driver support"
exit 1
;;
esac
UBUNTU_RELEASE="$ubuntu_ver"
print_info "Detected Ubuntu version: $ubuntu_ver -> $UBUNTU_VERSION"
}
# Simple version display function (replaces complex GitHub scraping)
display_version_info() {
print_info "Using NPU Driver Version Information:"
if [ -n "${NPU_ASSET_URL:-}" ]; then
local asset_name
asset_name=$(basename "$NPU_ASSET_URL")
print_info "Asset: ${asset_name}"
fi
print_info "NPU Version: ${NPU_VERSION:-auto} | Build: ${NPU_BUILD_ID:-auto}"
print_info "Ubuntu Package: ${UBUNTU_VERSION}"
print_info ""
case "$NPU_SOURCE" in
latest) print_info "Using the latest upstream release." ;;
pinned) print_info "Using the pinned fallback release." ;;
*) print_info "Using an overridden release." ;;
esac
print_info "Override: NPU_VERSION=pinned, NPU_VERSION + NPU_BUILD_ID, or NPU_ASSET_URL."
}
# Status indicators - using ASCII for better compatibility (conditional definition)
if [[ -z "$S_ERROR" ]]; then
S_ERROR="[ERROR]"
fi
if [[ -z "$S_VALID" ]]; then
S_VALID="[✓]"
fi
if [[ -z "$S_WARNING" ]]; then
S_WARNING="[!]"
fi
# Colors for output (conditional definition)
if [[ -z "$RED" ]]; then
RED='\033[0;31m'
fi
if [[ -z "$GREEN" ]]; then
GREEN='\033[0;32m'
fi
if [[ -z "$YELLOW" ]]; then
YELLOW='\033[1;33m'
fi
if [[ -z "$NC" ]]; then
NC='\033[0m' # No Color
fi
# Print colored output (define only if not already defined)
if ! command -v print_error &> /dev/null; then
print_error() { echo -e "${RED}${S_ERROR} $1${NC}"; }
fi
if ! command -v print_success &> /dev/null; then
print_success() { echo -e "${GREEN}${S_VALID} $1${NC}"; }
fi
if ! command -v print_warning &> /dev/null; then
print_warning() { echo -e "${YELLOW}${S_WARNING} $1${NC}"; }
fi
if ! command -v print_info &> /dev/null; then
print_info() { echo -e "$1"; }
fi
# Check if package is actually installed (not just known to dpkg)
is_package_installed() {
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -q "install ok installed"
}
# Clean up old NPU packages and conflicting packages
cleanup_old_packages() {
print_info "Removing old NPU packages and conflicting packages..."
# Remove NPU packages with force to handle conflicts
dpkg --purge --force-remove-reinstreq intel-driver-compiler-npu intel-fw-npu intel-level-zero-npu intel-level-zero-npu-dbgsym 2>/dev/null || true
print_success "Old packages and conflicts cleaned up"
return 0
}
# Install NPU dependencies
install_dependencies() {
print_info "Installing NPU dependencies..."
if ! apt update; then
print_warning "apt update failed, continuing anyway..."
fi
if apt install -y libtbb12 wget curl; then
print_success "Dependencies installed"
return 0
else
print_error "Failed to install dependencies"
return 1
fi
}
# Download NPU driver packages
download_npu_packages() {
print_info "Resolving NPU driver package URL..."
if [ -z "${NPU_ASSET_URL:-}" ]; then
resolve_versions || return 1
fi
local archive_name
archive_name=$(basename "$NPU_ASSET_URL")
print_info " Downloading ${archive_name}..."
if wget -q --timeout=30 "${NPU_ASSET_URL}"; then
print_success " Downloaded ${archive_name}"
# Extract the archive
print_info " Extracting ${archive_name}..."
if tar -xzf "${archive_name}"; then
print_success " Extracted NPU packages from archive"
rm -f "${archive_name}" # Clean up archive after extraction
else
print_error " Failed to extract ${archive_name}"
return 1
fi
else
print_error " Failed to download asset from ${NPU_ASSET_URL}"
return 1
fi
print_success "All NPU packages downloaded successfully"
return 0
}
# Install NPU packages
install_npu_packages() {
print_info "Installing NPU driver packages..."
if dpkg -i ./*.deb; then
print_success "NPU packages installed successfully"
return 0
else
print_warning "NPU package installation failed, attempting to fix dependencies..."
if apt install --fix-broken -y && dpkg -i ./*.deb; then
print_success "NPU packages installed after dependency fix"
return 0
else
print_error "Failed to install NPU packages even after dependency fix"
return 1
fi
fi
}
# Install the libze1 Level Zero loader from the kobuk-team PPA snapshot
install_level_zero_loader() {
local installed required deb url
url="$LIBZE1_URL"
if [ -z "$url" ]; then
url="https://snapshot.ppa.launchpadcontent.net/kobuk-team/intel-graphics/ubuntu/${LIBZE1_SNAPSHOT}/pool/main/l/level-zero-loader/libze1_${LIBZE1_VERSION}~${UBUNTU_RELEASE}~ppa1_amd64.deb"
fi
deb=$(basename "$url")
required="${deb#libze1_}"
required="${required%%~*}"
installed=$(dpkg-query -W -f='${Version}' libze1 2>/dev/null || true)
if is_package_installed libze1 && dpkg --compare-versions "$installed" ge "$required"; then
print_success "libze1 $installed already installed"
return 0
fi
print_info " Downloading ${deb}..."
if ! wget -q --timeout=30 "$url"; then
print_error " Failed to download ${url}"
return 1
fi
if dpkg -i "$deb"; then
print_success "libze1 ${required} installed"
return 0
fi
print_warning "libze1 install failed, removing conflicting Level Zero packages and retrying..."
dpkg --purge --force-remove-reinstreq level-zero level-zero-devel 2>/dev/null || true
if dpkg -i "$deb"; then
print_success "libze1 ${required} installed"
return 0
fi
print_error "Failed to install libze1"
return 1
}
# Setup device permissions
setup_device_permissions() {
print_info "Configuring NPU device permissions..."
# Create udev rules
if echo 'SUBSYSTEM=="accel", KERNEL=="accel*", GROUP="render", MODE="0660"' > /etc/udev/rules.d/10-intel-vpu.rules; then
print_success "udev rules created"
else
print_error "Failed to create udev rules"
return 1
fi
# Reload udev rules
udevadm control --reload-rules
udevadm trigger --subsystem-match=accel
print_success "Device permissions configured"
return 0
}
# User configuration
configure_user_groups() {
echo -e "\n# Configuring user groups"
local groups=("video" "render")
local users=("$USER")
# Add native user if running via sudo
if [ -n "${SUDO_USER:-}" ]; then
users+=("$SUDO_USER")
fi
for user in "${users[@]}"; do
for group in "${groups[@]}"; do
if ! id -nG "$user" | grep -q -w "$group"; then
log_info "Adding user $user to group $group"
usermod -aG "$group" "$user"
else
log_success "User $user already in group $group"
fi
done
done
}
# Check NPU device and dmesg
check_npu_device() {
print_info "Checking NPU device availability..."
if ls /dev/accel/accel0 1>/dev/null 2>&1; then
print_success "NPU device found: /dev/accel/accel0"
# Show device permissions
print_info "Device permissions:"
ls -lah /dev/accel/accel0 2>/dev/null || true
# Check dmesg for intel_vpu state
print_info "Checking dmesg for intel_vpu messages..."
dmesg | grep -i "intel_vpu\|npu" | tail -5 || print_info "No recent intel_vpu messages found"
return 0
else
print_warning "NPU device not found - reboot may be required"
return 1
fi
}
# Verify NPU installation
verify_installation() {
print_info "Verifying NPU installation..."
# Check NPU packages
local npu_packages=("intel-driver-compiler-npu" "intel-fw-npu" "intel-level-zero-npu")
local all_npu_installed=true
for pkg in "${npu_packages[@]}"; do
if is_package_installed "$pkg"; then
print_success "Package $pkg installed"
else
print_error "Package $pkg not installed"
all_npu_installed=false
fi
done
# Check Level Zero packages (either generic or NPU-specific)
if is_package_installed "libze1"; then
print_success "Level Zero loader (libze1) installed"
elif is_package_installed "level-zero"; then
print_success "oneAPI Level Zero installed"
elif is_package_installed "intel-level-zero-npu"; then
print_success "NPU Level Zero installed"
else
print_error "No Level Zero package found"
fi
# Check NPU device and dmesg
check_npu_device
# Check udev rules
if [ -f "/etc/udev/rules.d/10-intel-vpu.rules" ]; then
print_success "NPU udev rules configured"
else
print_error "NPU udev rules not found"
fi
print_info ""
print_info "Installation verification completed"
if [ "$all_npu_installed" = true ]; then
print_success "All NPU components installed successfully"
else
print_warning "Some NPU components may not be installed correctly"
fi
}
# Main installation function
install_npu() {
print_info "Starting NPU installation for Core Ultra platform..."
# Detect Ubuntu version
detect_ubuntu_version
# Resolve versions and asset URL (auto or overridden)
resolve_versions || { print_error "Failed to resolve NPU versions"; exit 1; }
# Display version information
display_version_info
# Check if running as root
if [ "$EUID" -ne 0 ]; then
print_error "This script must be run as root (use sudo)"
exit 1
fi
# Create temporary directory
local temp_dir="/tmp/npu_installer_$$"
mkdir -p "$temp_dir"
cd "$temp_dir" || { print_error "Failed to create/enter temp directory"; exit 1; }
# Installation steps
print_info "Step 1: Cleaning up old packages and conflicts..."
cleanup_old_packages || { print_error "Failed to cleanup old packages"; exit 1; }
print_info "Step 2: Installing dependencies..."
install_dependencies || { print_error "Failed to install dependencies"; exit 1; }
print_info "Step 3: Downloading NPU packages..."
download_npu_packages || { print_error "Failed to download NPU packages"; exit 1; }
print_info "Step 4: Installing NPU packages..."
install_npu_packages || { print_error "Failed to install NPU packages"; exit 1; }
print_info "Step 5: Installing Level Zero loader (libze1)..."
install_level_zero_loader || { print_error "Failed to install Level Zero loader"; exit 1; }
print_info "Step 6: Setting up device permissions..."
setup_device_permissions || { print_error "Failed to setup device permissions"; exit 1; }
configure_user_groups
# Cleanup
print_info "Step 7: Cleaning up temporary files..."
cd / || exit 1
rm -rf "$temp_dir"
print_success "Cleanup completed"
# Verify installation
print_info "Step 8: Verifying installation..."
verify_installation
print_info ""
print_success "NPU installation completed"
print_info ""
# Record the reason instead of a vague "recommended". main_installer.sh
# shows one banner at the end. See issue #987.
if [ "${DEVKIT_POST_REBOOT_PASS:-0}" != "1" ] && [ -w /run ] 2>/dev/null; then
echo "*** System restart required ***" > "${REBOOT_REQUIRED_FILE:-/run/reboot-required}" 2>/dev/null || true
grep -qxF "Intel NPU driver installed (/dev/accel appears after restart)" \
"${REBOOT_REQUIRED_REASONS:-/run/reboot-required.pkgs}" 2>/dev/null || \
echo "Intel NPU driver installed (/dev/accel appears after restart)" \
>> "${REBOOT_REQUIRED_REASONS:-/run/reboot-required.pkgs}" 2>/dev/null || true
fi
print_info "After restarting, verify with: ls /dev/accel/accel0"
print_info "Expected output: crw-rw---- 1 root render 261, 0 <date> /dev/accel/accel0"
print_info "Also check dmesg for intel_vpu messages: dmesg | grep intel_vpu"
print_info ""
}
# Run installation if script is executed directly
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
install_npu
fi