Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions kernel/drivers/graphics/nvidia/LICENSE-NVIDIA
Original file line number Diff line number Diff line change
Expand Up @@ -2966,13 +2966,15 @@ src/common/sdk/nvidia/inc/ctrl/ctrl0073/ctrl0073specific.h
field, in display_outputs.h, its rootPortId field, the root port's id for a
display id, in display_active_heads.h, its index field (the output
resource's number among those of its type), its type field and
NV0073_CTRL_SPECIFIC_OR_TYPE_SOR (2), in rm.h, display_active_heads.h and
kernel/tests/graphics/nvidia_display_active_heads.test.cpp, that command,
the layout of its parameters and those two fields, in
NV0073_CTRL_SPECIFIC_OR_TYPE_SOR (2), in rm.h, display_active_heads.h,
display_active_heads.cpp,
kernel/tests/graphics/nvidia_display_active_heads.test.cpp and
kernel/tests/graphics/nvidia_display_engine.test.cpp, that command, the
layout of its parameters and those two fields, in display_active_heads.cpp,
kernel/tests/graphics/nvidia_display_active_heads.test.cpp and
kernel/tests/graphics/nvidia_display_engine.test.cpp,
NV0073_CTRL_SPECIFIC_OR_TYPE_DAC (1, an analog output resource), in
NV0073_CTRL_SPECIFIC_OR_TYPE_DAC (1, an analog output resource), PIOR (3, a
parallel input output resource) and DSI (5, a display serial interface), in
kernel/tests/graphics/nvidia_display_active_heads.test.cpp, and the command
NV0073_CTRL_CMD_SPECIFIC_GET_EDID_V2 (a control of display common reading a
monitor's EDID), the layout of its parameters,
Expand Down Expand Up @@ -3060,7 +3062,9 @@ src/nvidia-modeset/include/nvkms-types.h
an unused value, 16 bits each) and NVEvoLutDataRec (a window's input table,
then from a multiple of 256 bytes a head's output table, each of the
header's entries and a table's), in display_light.h, display_light.cpp and
kernel/tests/graphics/nvidia_display_light.test.cpp
kernel/tests/graphics/nvidia_display_light.test.cpp, and NV_EVO_MAX_ORS,
the most serial links NVIDIA's driver allows on one GPU, 8, in chip.h and
chip.cpp
SPDX-FileCopyrightText: Copyright (c) 2010-2020 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

src/nvidia-modeset/interface/nvkms-api-types.h
Expand Down
12 changes: 12 additions & 0 deletions kernel/drivers/graphics/nvidia/chip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ constexpr chip_info CHIP_TABLE[] = {
.display = {
.head_count = 4,
.window_count = 8,
.serial_link_count = 4,
.display_class = 0xC670,
.core_channel_class = 0xC67D,
.window_channel_class = 0xC67E,
Expand Down Expand Up @@ -75,9 +76,20 @@ static constexpr bool keeps_display_heads_within_max() {
return true;
}

static constexpr bool keeps_serial_links_within_max() {
for (const chip_info& chip : CHIP_TABLE) {
if (chip.display.serial_link_count > SERIAL_LINKS_MAX) {
return false;
}
}

return true;
}

static_assert(keeps_interrupt_leaves_within_max(), "every chip's CPU interrupt tree has at most NVIDIA's 16 leaves");
static_assert(keeps_display_windows_within_max(), "every chip's windows fit the 32-bit mask the firmware reports");
static_assert(keeps_display_heads_within_max(), "every chip's display has at most the 4 heads NVIDIA's driver allows");
static_assert(keeps_serial_links_within_max(), "every chip has at most the 8 serial links NVIDIA's driver allows");

uint16_t decode_chip_id(uint32_t boot0) {
return static_cast<uint16_t>((boot0 >> PMC_BOOT_0_CHIP_ID_SHIFT) & PMC_BOOT_0_CHIP_ID_MASK);
Expand Down
5 changes: 5 additions & 0 deletions kernel/drivers/graphics/nvidia/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ constexpr uint8_t DISPLAY_HEADS_MAX = 4;
// NV_PDISP_CHN_NUM_WIN__SIZE_1, one bit each in the 32-bit mask the firmware reports them in
constexpr uint8_t DISPLAY_WINDOWS_MAX = 32;

// The most serial links (NVIDIA's SORs, the units each driving one DisplayPort, HDMI or DVI connector) NVIDIA's driver
// allows on one GPU, NV_EVO_MAX_ORS
constexpr uint8_t SERIAL_LINKS_MAX = 8;

/**
* The names of a chip's firmware files, which `open_firmware_files` looks up
* in the version's directory, nvidia/<FIRMWARE_VERSION>/ in `fw::DIRECTORY`,
Expand Down Expand Up @@ -83,6 +87,7 @@ struct chip_displayport {
struct chip_display {
uint8_t head_count; // the chip's heads, numbered from 0, at most `DISPLAY_HEADS_MAX`
uint8_t window_count; // the chip's windows, numbered from 0, at most `DISPLAY_WINDOWS_MAX`
uint8_t serial_link_count; // the chip's serial links, numbered from 0, at most `SERIAL_LINKS_MAX`
uint32_t display_class; // NVIDIA's class of the display object, the parent of the display engine's channels
uint32_t core_channel_class; // NVIDIA's class of the core channel, which sets up heads, links and windows' heads

Expand Down
22 changes: 19 additions & 3 deletions kernel/drivers/graphics/nvidia/display_active_heads.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ static int32_t read_shown_display(firmware& fw, rm::handle display_common, uint8
return OK;
}

// Gives the link driving the display id a head shows, or counts the head as showing nothing for a reply naming no link
// with a crossbar, and fails on a refused request or such a reply without one, logging each
// Gives the serial link driving a head's display id, or counts the head as showing nothing for no link with a crossbar,
// failing, logged, on a refused request, on no link without a crossbar and on a link not among the chip's serial links
static int32_t read_head_link(
firmware& fw,
rm::handle display_common,
uint8_t head,
bool has_crossbar,
uint8_t serial_link_count,
active_head& state
) {
rm::output_resource_params params = {};
Expand Down Expand Up @@ -84,6 +85,20 @@ static int32_t read_head_link(
return ERR_BAD_MESSAGE;
}

bool is_serial_link = params.type == rm::OUTPUT_RESOURCE_TYPE_SERIAL && params.index < serial_link_count;
if (!is_serial_link) {
log::error(
"nvidia: display common names link %u of NVIDIA's output resource type %u for head %u's display id 0x%X, "
"not one of the chip's %u serial links",
params.index,
params.type,
head,
state.display_id,
serial_link_count
);
return ERR_BAD_MESSAGE;
}

state.link_index = params.index;
state.link_type = params.type;

Expand All @@ -95,6 +110,7 @@ int32_t read_active_heads(
rm::handle display_common,
uint8_t head_count,
bool has_crossbar,
uint8_t serial_link_count,
active_heads& out
) {
active_heads heads = {};
Expand All @@ -109,7 +125,7 @@ int32_t read_active_heads(
continue;
}

rc = read_head_link(fw, display_common, head, has_crossbar, state);
rc = read_head_link(fw, display_common, head, has_crossbar, serial_link_count, state);
if (rc != OK) {
return rc;
}
Expand Down
17 changes: 12 additions & 5 deletions kernel/drivers/graphics/nvidia/display_active_heads.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,28 +62,35 @@ struct active_heads {
* fails the read, since a mode set (programming a head to drive a monitor)
* must know a head's link to detach the head from it. For a refused link
* request or a display id that names no connector, that module keeps the
* head's display id but records no connector or link for it.
* head's display id but records no connector or link for it. A link reply
* naming a link other than one of the chip's serial links is refused as
* malformed, a rule of the driver's own, since detaching a head writes its
* link's methods, which must not name a link past the chip's serial links.
* @param fw The driver's firmware.
* @param display_common The handle `allocate_display_objects` gave display
* common.
* @param head_count The heads `read_display_heads` left the display engine,
* which must be at most `DISPLAY_HEADS_MAX`.
* @param has_crossbar Whether display common reports a crossbar, as
* `read_display_capabilities` gives it.
* @param serial_link_count The chip's serial links, as the chip table gives
* them.
* @param out Receives on `OK` the heads, each showing nothing or one display
* id through a link, those from `head_count` on showing nothing, and is left
* unchanged on an error.
* id through one of the chip's serial links, those from `head_count` on
* showing nothing, and is left unchanged on an error.
* @return `OK`, what `firmware::control` returns for a request that fails
* other than with `ERR_FIRMWARE` (logged as its doc describes), `ERR_FIRMWARE`
* for a link request the firmware refuses (logged here), or `ERR_BAD_MESSAGE`
* for a head reported showing several display ids or a link reply naming no
* link while display common reports no crossbar (logged here).
* for a head reported showing several display ids, a link reply naming no link
* while display common reports no crossbar, or a link reply naming a link that
* is not one of the chip's serial links (logged here).
*/
int32_t read_active_heads(
firmware& fw,
rm::handle display_common,
uint8_t head_count,
bool has_crossbar,
uint8_t serial_link_count,
active_heads& out
);

Expand Down
9 changes: 8 additions & 1 deletion kernel/drivers/graphics/nvidia/display_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,14 @@ int32_t display_engine::set_up(
);

active_heads active = {};
rc = read_active_heads(m_firmware, m_objects.display_common, heads.count, has_crossbar, active);
rc = read_active_heads(
m_firmware,
m_objects.display_common,
heads.count,
has_crossbar,
display.serial_link_count,
active
);
if (rc != OK) {
return rc;
}
Expand Down
13 changes: 7 additions & 6 deletions kernel/drivers/graphics/nvidia/display_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ class display_engine {
* screen changes, wait for GET to reach PUT, and log one read of PUT and
* GET with the count of methods written. Then read the display id each
* head shows and the link driving that display id with
* `read_active_heads`, which takes whether display common reports a
* crossbar, and log each active head with its display id, its link and the
* `read_active_heads`, which takes `has_crossbar` and the chip's serial
* links, and log each active head with its display id, its link and the
* output `find_shown_output` gives for it, or that the display id names no
* output, then the boot head `find_boot_head` gives and the boot output
* (the output it shows), or that there is none. Then choose the output to
Expand Down Expand Up @@ -200,10 +200,11 @@ class display_engine {
* system memory, connected display ids among the supported ones, heads
* within the chip's, head 0 usable and served, with nonzero masks only for
* the chip's windows, each naming one of the chip's heads outside a
* flexible mapping, at most one display id shown by each head and, without
* a crossbar, a link driving each display id shown. Otherwise the error of
* the first step that fails, logged as that step describes, such as when
* the firmware reports a window the chip lacks, the display engine reaches
* flexible mapping, at most one display id shown by each head, each link
* read for a head one of the chip's serial links and, without a crossbar,
* a link driving each display id shown. Otherwise the error of the first
* step that fails, logged as that step describes, such as when the
* firmware reports a window the chip lacks, the display engine reaches
* push buffers, semaphores and notifiers only in video memory, display
* common's report leaves it no head, the firmware refuses to report the
* supported or connected display ids or it refuses to name the link
Expand Down
5 changes: 3 additions & 2 deletions kernel/drivers/graphics/nvidia/nvidia.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ constexpr int32_t ERR_BAD_MESSAGE = -11; // a message from the GSP's firmware
// or carries a display report that exceeds the chip table's display limits,
// leaves the display engine no head, names several heads for a window that
// may serve only one, names a connected display id that is not supported,
// several display ids reported for one head or no link for a head's display
// id while display common reports no crossbar
// several display ids reported for one head, no link for a head's display
// id while display common reports no crossbar, or a head's link that is not
// one of the chip's serial links
constexpr int32_t ERR_FIRMWARE = -12; // the GSP's firmware reports a failure through a ready message's or reply's
// result or a control's status, or does not take the driver's VGX version,
// as a reply shows by a private result other than 0 or another version
Expand Down
3 changes: 3 additions & 0 deletions kernel/drivers/graphics/nvidia/rm.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,9 @@ struct output_resource_params {
// NVIDIA's NV_INVALID_OR, the `output_resource_params::index` of a display id no output resource drives
constexpr uint32_t NO_OUTPUT_RESOURCE = 0xFFFFFFFF;

// NVIDIA's NV0073_CTRL_SPECIFIC_OR_TYPE_SOR, the `output_resource_params::type` of a serial output resource
constexpr uint32_t OUTPUT_RESOURCE_TYPE_SERIAL = 2;

static_assert(sizeof(output_resource_params) == 56, "NVIDIA's layout of OR_GET_INFO's parameters");

// NVIDIA's NV0073_CTRL_CMD_DFP_GET_INFO, the control to display common that gives a digital display id's facts, which
Expand Down
1 change: 1 addition & 0 deletions kernel/tests/graphics/nvidia_core_channel.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ static constexpr uint8_t TEST_WINDOW = 6;
static constexpr chip_display TEST_ENTRY = {
.head_count = 4,
.window_count = 8,
.serial_link_count = 4,
.display_class = 0,
.core_channel_class = 0xC67E,
.window_channel_class = 0xC67D,
Expand Down
Loading
Loading