Шина USB-Linux, контроллер устройства USB3.0, анализ процесса инициализации драйвера гаджета dwc3 (5)
Шина USB-Linux, контроллер устройства USB3.0, анализ процесса инициализации драйвера гаджета dwc3 (5)

1. Обзор

Блок-схема драйвера USB Device Controller (UDC) показана на рисунке ниже и состоит из трёх частей. Первая часть — это основной уровень драйвера UDC, который реализован в файле driver/usb/gadget/udc/core.c. Этот уровень представляет собой уровень совместимости, который изолирует драйвер функции USB от конкретного драйвера USB-гаджета и абстрагирует его. Интерфейс и структура данных обеспечивают унифицированный и стабильный интерфейс для функционального драйвера USB и в то же время завершают согласование функционального драйвера USB и драйвера USB-гаджета. Вторая часть — это уровень драйвера гаджета, который отвечает за управление работой оборудования и связан с конкретным оборудованием контроллера USB-устройства. Драйвер гаджета dwc3 реализован в файле driver/usb/dwc3/gadget.c. Третья часть — это аппаратное обеспечение контроллера USB-устройства.

Драйвер USB-гаджета описывает аппаратный метод работы контроллера USB-устройства, и разные USB-контроллеры имеют разные реализации. Некоторые USB-контроллеры можно использовать только в качестве контроллеров устройств, например ompa, pxa2 и другие контроллеры USB-устройств, а их драйверы находятся в папке driver/usb/gadget/udc. Некоторые USB-контроллеры можно использовать в качестве хост-контроллеров или контроллеров устройств. Они имеют функции OTG и могут переключаться между двумя режимами, например USB-контроллер dwc3, драйвер которого находится в файле driver/usb/dwc3. Контроллер USB3.0 RK3399 использует USB-контроллер dwc3 и имеет функцию OTG.

2. Режим контроллера

Контроллер USB использует драйвер UDC после переключения в режим устройства, поэтому мы начнем с процесса инициализации контроллера USB-устройства и объясним ключевые структуры данных.

2.1.Инициализация

В дереве устройств установите атрибут dr_mode="otg". При инициализации контроллера dwc3 он перейдет в режим USB_DR_MODE_OTG. В то же время вызовите функции dwc3_host_init и dwc3_gadget_init для инициализации ресурсов, необходимых для хоста. режим и режим устройства Контроллер может впоследствии динамически переключаться между режимом хоста и режимом устройства. Процесс инициализации контроллера dwc3 USB3.0 показан на рисунке ниже, уделяя особое внимание процессу инициализации режима устройства. Основная работа заключается в следующем:

(1) Установите контроллер в режим USB_DR_MODE_OTG.

(2) Инициализируйте ресурсы, необходимые в режиме хоста. Конкретный процесс будет проанализирован при анализе драйвера хоста.

(3) Инициализируйте ресурсы, необходимые для режима устройства.

(a) Получите номер прерывания и выделите память, необходимую для передачи конечной точки 0. Конечная точка 0 используется во время перечисления устройств и должна отвечать на запросы от хоста, поэтому память необходимо выделить заранее.

(b) Установите для набора рабочих функций контроллера устройства dwc3 значение dwc3_gadget_ops, которое включает только аппаратное управление и не требует операций ввода-вывода.

(c) Инициализируйте аппаратную конечную точку. Сначала инициализируйте выходную конечную точку, затем входную конечную точку. Максимальная длина пакета для конечной точки 0 составляет 512 байт, а максимальная длина пакета для других конечных точек — 1024 байта. Операционная функция конечной точки 0 — dwc3_gadget_ep0_ops, а рабочая функция других конечных точек — dwc3_gadget_ep0_ops. Операционная функция конечной точки в основном описывает операции ввода-вывода. Неконечная точка 0 будет связана со связанным списком гаджета.ep_list. Конечная точка 0 поддерживает передачу управления, а другие конечные точки поддерживают изохронную, пакетную передачу и передачу с прерываниями.

(d) Добавьте драйвер udc. Сначала выделите структуру данных usb_udc, затем поместите ее в связанный список udc_list и, наконец, установите статус драйвера udc на USB_STATE_NOTATTACHED.

Структура данных после завершения инициализации показана на рисунке ниже. Самое важное — это контент, связанный с конечной точкой. Конечная точка 0 используется для передачи данных контроллера, например, для перечисления устройств и ответа на запросы настройки, отправленные хостом. Ресурсы необходимо выделить заранее. Конечная точка 0 существенно отличается от других конечных точек, поэтому ее рабочие функции уникальны. Другие конечные точки в основном используются для передачи данных, а функции работы являются общими.

2.2.Переключение режима

В дереве устройств настройте USB-контроллер dwc3 в периферийный режим. При запуске системы USB-контроллер будет переведен в режим устройства, и будут инициализированы ресурсы, связанные с гаджетом. Если он настроен в режиме otg, только ресурсы, связанные с гаджетом. будет инициализирован. Контроллер dwc3 не будет переведен в режим устройства. В это время контроллер dwc3 находится в режиме otg и его необходимо переключить в режим устройства (только в режиме otg его можно переключить на хост или устройство).

Язык кода:javascript
копировать
// Переключиться в режим otg
echo 0 > /sys/devices/platform/usb0/dwc3_mode
echo otg > /sys/devices/platform/usb0/dwc3_mode
// Переключиться в режим хоста
echo 1 > /sys/devices/platform/usb0/dwc3_mode
echo host > /sys/devices/platform/usb0/dwc3_mode
// Переключиться в режим устройства
echo 2 > /sys/devices/platform/usb0/dwc3_mode
echo peripheral > /sys/devices/platform/usb0/dwc3_mode

Вышеупомянутое переключение режима завершается планированием рабочей очереди otg_work, и рабочая очередь вызывает функцию dwc3_rockchip_otg_extcon_evt_work для переключения.

Язык кода:javascript
копировать
[drivers\usb\dwc3\dwc3-rockchip.c]
struct dwc3_rockchip {
    ......
	struct work_struct	otg_work;
    ......
};
static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work)
{
	if (rockchip->force_mode ? dwc->dr_mode == USB_DR_MODE_PERIPHERAL :
	    extcon_get_cable_state_(edev, EXTCON_USB)) {
        ......
		spin_lock_irqsave(&dwc->lock, flags);
		// режим устройства
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
		spin_unlock_irqrestore(&dwc->lock, flags);
	} else if (rockchip->force_mode ? dwc->dr_mode == USB_DR_MODE_HOST :
		   extcon_get_cable_state_(edev, EXTCON_USB_HOST)) {
        ......
		spin_lock_irqsave(&dwc->lock, flags);
		// режим хоста
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
		spin_unlock_irqrestore(&dwc->lock, flags);
        ......
	} else {
        ......
	}
    ......
}

3. Ключевые структуры данных

3.1.Конечная точка

struct usb_ep — это общая структура данных, используемая ядром Linux для описания конечных точек контроллера USB-устройства. ops — это операционная функция, соответствующая конечной точке, в основном используемая для описания операций ввода-вывода. ep_list — это узел связанного списка конечной точки, который обычно связан со связанным списком ep_list usb_gadget. maxpacket описывает максимальную длину пакета конечной точки, которая настраивается дескриптором конечной точки (программным обеспечением). Например, в USB3.0 максимальная длина пакета для массовой передачи равна 512, а максимальная длина пакета для isoc — 1024. maxpacket_limit описывает максимальную длину пакета, которую может обработать оборудование конечной точки. Например, в USB3.0 конечная точка 0 может обрабатывать максимум 512 байт, а другие конечные точки могут обрабатывать максимум 1024 байта. USB3.0 поддерживает пакетную передачу нескольких пакетов данных в течение 125 микросекунд. Максимальное значение устанавливается параметром maxburst. Диапазон 0–15 означает передачу 1 пакета, а 15 означает, что может быть передано 16 пакетов. может быть только 0. . Каждая конечная точка имеет свой адрес, описываемый с помощью addr. desc указывает на дескриптор конечной точки. Если вы используете USB3.0, вам также необходимо установить дескриптор comp_desc.

struct usb_ep обычно не используется напрямую, а встраивается в большую структуру данных. В контроллере dwc3 он встроен в структуру struct dwc3_ep. pending_list и start_list используются для хранения структуры данных запроса ввода-вывода struct usb_request. Первый хранит ожидающие запросы ввода-вывода, которые еще не могут быть обработаны, а второй хранит запросы ввода-вывода, которые уже начали обрабатываться. trb_pool — это массив, состоящий из trb, который автоматически обрабатывается аппаратным обеспечением. Он хранит адрес, длину и флаг буфера передачи. Неконечная точка 0 выделяет 256 trb, а trb_pool_dma сохраняет физический адрес trb_pool. trb_enqueue и trb_dequeue — это используемые и неиспользуемые индексы массива trb_pool. selected_requests указывает количество выделенных запросов ввода-вывода.

Язык кода:javascript
копировать
[include/linux/usb/gadget.h]
struct usb_ep {  // USBрежим устройства Конечная точка общаяструктура данных
	const char		*name;         // имя
	const struct usb_ep_ops	*ops;  // Операционная функция, соответствующая этой конечной точке
	struct list_head	ep_list;   // Узел связанного списка конечной точки
	struct usb_ep_caps	caps;      // Типы транспорта, поддерживаемые конечной точкой
	bool			claimed;
	bool			enabled;       // Включена ли конечная точка
	unsigned		maxpacket:16;  // Максимальная длина пакета, настраиваемая дескриптором конечной точки
	unsigned		maxpacket_limit:16;  // Максимальная длина пакета, которую может обработать оборудование конечной точки.
	unsigned		max_streams:16;      // Максимальное количество потоков, диапазон 0–16.
	unsigned		mult:2; // multiplier, 'mult' value for SS Isoc EPs
	// Максимальный пакет, поддерживаемый конечной точкой, диапазон 0–15, USB3.0 поддерживает эту опцию.
	unsigned		maxburst:5;  
	u8			address;         // Адрес конечной точки, используемый для различения разных конечных точек.
	const struct usb_endpoint_descriptor	*desc;       // дескриптор конечной точки
	const struct usb_ss_ep_comp_descriptor	*comp_desc;  // Дескриптор сопряжения USB3.0
};
[drivers/usb/dwc3/core.h]
struct dwc3_ep {  // dwc3 USB-контроллеррежим устройстваконечная точкаструктура данных
	struct usb_ep		endpoint;      // Общая структура конечной точки устройства данных
	struct list_head	pending_list;  // ожидающий ввода-вывода requests
	struct list_head	started_list;  // начал ИО requests
	spinlock_t		lock;              // спин-блокировка
	void __iomem		*regs;         // Базовый адрес регистра этой конечной точки
	struct dwc3_trb		*trb_pool;     // Массив trb этой конечной точки, используемый для передачи данных DMA.
	dma_addr_t		trb_pool_dma;      // физический адрес этой конечной точки в массиве trb
	const struct usb_ss_ep_comp_descriptor *comp_desc;  // Дескриптор сопряжения USB3.0
	struct dwc3		*dwc;   // направленный dwc3 ctrl
	u32			saved_state;
	unsigned		flags;  // Флаг этой конечной точки определяется макросом, начинающимся с DWC3_EP.
#define DWC3_EP_ENABLED		(1 << 0)
#define DWC3_EP_STALL		(1 << 1)
#define DWC3_EP_WEDGE		(1 << 2)
#define DWC3_EP_BUSY		(1 << 4)
#define DWC3_EP_PENDING_REQUEST	(1 << 5)
#define DWC3_EP_MISSED_ISOC	(1 << 6)
#define DWC3_EP0_DIR_IN		(1 << 31)
	u8			trb_enqueue;  // индекс очереди массива trb
	u8			trb_dequeue;  // Индекс удаления из очереди массива trb
	u8			number;       // endpoint number (1 - 15)
	// set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
	u8			type;
	u8			resource_index;
	u32			allocated_requests;  // Уже выделено IO requests
	u32			queued_requests;     // IO поставлен в очередь на передачу количество запросов
	// the interval on which the ISOC transfer is started
	u32			interval;
	// a human readable name e.g. ep1out-bulk
	char			name[20];
	unsigned		direction:1; // true for TX, false for RX
	unsigned		stream_capable:1;
};

struct usb_ep_ops описывает функцию работы конечной точки, в основном связанную с операциями ввода-вывода. Эти функции тесно связаны с аппаратным обеспечением. Контроллер USB-устройства должен реализовывать эти функции, а реализации функций конечной точки 0 и неконечной точки 0 также несовместимы. Enable включает конечную точку, Disable отключает конечную точку, alloc_request выделяет структуру данных запроса ввода-вывода usb_request, free_request освобождает запрос ввода-вывода, очередь добавляет запрос ввода-вывода в очередь, dequeue удаляет запрос ввода-вывода из очереди и fifo_status получает статус fifo, fifo_flush обновляет fifo.

Язык кода:javascript
копировать
[include/linux/usb/gadget.h]
struct usb_ep_ops {
	int (*enable) (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc);
	int (*disable) (struct usb_ep *ep);
	struct usb_request *(*alloc_request) (struct usb_ep *ep, gfp_t gfp_flags);
	void (*free_request) (struct usb_ep *ep, struct usb_request *req);
	int (*queue) (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags);
	int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
	int (*set_halt) (struct usb_ep *ep, int value);
	int (*set_wedge) (struct usb_ep *ep);
	int (*fifo_status) (struct usb_ep *ep);
	void (*fifo_flush) (struct usb_ep *ep);
};

3.2.Запрос USB-ввода-вывода

Запросы ввода-вывода USB описываются с помощью структуры usb_request. Драйвер functon инкапсулирует данные в форму usb_request, а затем отправляет их драйверу udc. Драйвер udc затем преобразует их в trb и, наконец, передает trb. Конечная точка USB-контроллера, и конечная точка будет работать автоматически. Эта структура представляет собой общую структуру данных. Базовый драйвер обычно не использует ее напрямую, а встраивает в другую структуру. buf хранит данные, которые необходимо передать, length хранит длину данных, dma хранит физический адрес buf, sg — это адрес агрегированной записи таблицы передачи DMA, num_sgs указывает количество скаттерлистов, Complete — обратный вызов функция после завершения передачи usb_request и не может перейти в спящий режим с помощью контроллера dwc3 Вызывается нижняя часть (поток прерывания), context — параметр полной функции обратного вызова, status указывает на результат передачи, 0 — на то, что передача завершена, отрицательное число — на то, что передача не удалась, а ошибка -ESHUTDOWN Код указывает, что причина сбоя передачи заключается в отключении устройства. При открытии соединения или закрытии конечной точки драйвером фактическое значение указывает количество переданных байт.

Структура dwc3_request — это структура данных, используемая драйвером устройства контроллера dwc3 для описания запросов ввода-вывода, а структура данных usb_request общего запроса ввода-вывода встроена внутрь.

Язык кода:javascript
копировать
[include/linux/usb/gadget.h]
struct usb_request {        // Используется для описания Запроса. ввода-вывода
	void			*buf;   // Буфер для отправки или получения данных
	unsigned		length; // Длина данных буфера
	dma_addr_t		dma;    // Физический адрес buf
	struct scatterlist	*sg; // a scatterlist for SG-capable controllers
	unsigned		num_sgs; // number of SG entries
	unsigned		num_mapped_sgs; // number of SG entries mapped to DMA
	// The stream id, when USB3.0 bulk streams are being used
	unsigned		stream_id:16;
	/* If true, hints that no completion irq is needed.
       Helpful sometimes with deep request queues that are handled
	   directly by DMA controllers. */
	unsigned		no_interrupt:1;
	/* If true, when writing data, makes the last packet be "short"
		by adding a zero length packet as needed; */
	unsigned		zero:1;
	/* When reading data, makes short packets be
	   treated as errors (queue stops advancing till cleanup). */
	unsigned		short_not_ok:1;
	/* Function called when request completes, so this request and
	   its buffer may be re-used.  The function will always be called with
       interrupts disabled, and it must not sleep.
       Reads terminate with a short packet, or when the buffer fills,
       whichever comes first.  When writes terminate, some data bytes
       will usually still be in flight (often in a hardware fifo).
       Errors (for reads or writes) stop the queue from advancing
       until the completion function returns, so that any transfers
	   invalidated by the error may first be dequeued. */
	void	(*complete)(struct usb_ep *ep, struct usb_request *req);
	void	*context;          // Полные параметры функции обратного вызова
	struct list_head	list;  // For use by the gadget driver.
	/* Reports completion code, zero or a negative errno.
       Normally, faults block the transfer queue from advancing until
	   the completion callback returns.
       Code "-ESHUTDOWN" indicates completion caused by device disconnect,
       or when the driver disabled the endpoint. */
	int			status;
	/* Reports bytes transferred to/from the buffer.  For reads (OUT
       transfers) this may be less than the requested length.  If the
       short_not_ok flag is set, short reads are treated as errors
       even when status otherwise indicates successful completion.
       Note that for writes (IN transfers) some data bytes may still
       reside in a device-side FIFO when the request is reported as
	   complete. */
	unsigned		actual;
};
[drivers/usb/dwc3/core.h]
struct dwc3_request {  // Описать передачу ввода-вывода контроллера dwc3.
	struct usb_request	request;  // Универсальный Запрос ввода-вывода
	struct list_head	list;     // Список очереди запросов
	struct dwc3_ep		*dep;     // Конечная точка, которой принадлежит этот запрос
	u8			first_trb_index;  // index to first trb used by this request
	u8			epnum;            // Номер конечной точки, соответствующий запросу
	struct dwc3_trb		*trb;     // Адрес trb, которому он принадлежит
	dma_addr_t		trb_dma;      // DMA-адрес trb, которому он принадлежит
	unsigned		direction:1;  // IN or OUT direction flag
	unsigned		mapped:1;     // true when request has been dma-mapped
	unsigned		started:1;    // true when request has been queued to HW
};

3.3.TRB

TRB (блок запроса на передачу) Блок запроса на передачу — это аппаратный формат, который автоматически обрабатывается оборудованием конечной точки. bpl и bph — это младшие 32 бита и верхние 32 бита адреса DMA 64-битного буфера соответственно, размер — это длина буфера, на которую приходится 23 бита, а остальные — управляющие биты. Драйвер устройства контроллера dwc3 свяжет dwc3_request и dwc3_trb, установит каждый бит в TRB, а затем запишет адрес DMA TRB в контроллер. Наконец, включите передачу, и контроллер автоматически передаст TRB в конечную точку. данные в буфере, указанном TRB.

Язык кода:javascript
копировать
[drivers/usb/dwc3/core.h]
struct dwc3_trb {
	u32		bpl;  // Буфер нижних 32 адресов DW0-3
	u32		bph;  // Старший адрес буфера 32 DW4-7
	u32		size; // Длина буфера[23:0] DW8-B
	u32		ctrl; // управляющий бит DWC-F
} __packed;

Подробное битовое поле TRB показано на рисунке ниже, его общий размер составляет 16 байт. Настройки программного обеспечения синей зоны, настройки программного обеспечения зеленой зоны, обновления оборудования. Подробности смотрите в таблице ниже.

область

область

иллюстрировать

Как получить доступ к оборудованию

BPTRL

Buffer Pointer Low

Младшие 32 бита 64-битного буферного адреса DMA

R_W

BPTRH

Buffer Pointer High

Старшие 32 бита 64-битного буферного адреса DMA

R_W

BUFSIZ

Buffer Size

Размер буфера, диапазон 0-(16 МБ - 1 байт), аппаратное обеспечение уменьшит эту область после завершения передачи.

R_W

PCM1

Packet Count M1

Входная конечная точка изохронной передачи USB2.0 поддерживает передачу нескольких пакетов данных в одном микрокадре. Эта область предназначена для установки количества пакетов данных, передаваемых в одном микрокадре. Это значение необходимо установить при подготовке первого trb. USB2.0 может передавать 3 пакета данных в течение 125 микросекунд.

R_W

TRBSTS

TRB Status

Статус передачи, установленный аппаратно 0-Успех 1-MissedIsoc2-SetupPending4-TransferInProgress4-ZLP_PENDING

R_W

HWO

Hardware Owner of Descriptor

Когда программное обеспечение готовит TRB, ему присваивается значение 1, что указывает на то, что TRB принадлежит контроллеру. Программное обеспечение не может изменить этот TRB до тех пор, пока бит не будет очищен аппаратным обеспечением.

R_W

LST

Last TRB

Идентифицирует последний TRB. Обычно один TRB не может передавать все данные, например очень длинный дескриптор конфигурации. В этом случае TRB необходимо организовать в связанный список, а позиция CHN должна быть установлена ​​в 1. Последний TRB. необходимо установить CHN на 0, LST установить на 1

R

CHN

Chain Buffers

Обычно один TRB не может передавать все данные. Для CHN необходимо установить значение 1, а TRB организованы в связанный список. Контроллер будет рассматривать эти TRB как транзакцию для передачи. Для последнего TRB необходимо установить значение 0 и LST. до 0. 1

R

TRBCTL

TRB Control

Укажите тип TRB1-Control-Data-2+/Bulk/Interrupt2-Control-Setup3-Control-Status-24-Control-Status-35-Control-Data6-Isochronous-First7-Isochronous8-Link TRB, Normal-ZLP ( Массовый вход)

R

ISP/IMI

Interrupt on Short Packet / Interrupt on Missed ISOC

ISP-Когда выходная конечная точка получает короткий пакет и CSP=1 и LST=0, контроллер генерирует событие XferInProgress. Для конечной точки ISOC, если этот бит равен 1 и время передачи ISOC истекает, контроллер генерирует событие. Событие XferInProgress. (Передача ISOC ориентирована на производительность в реальном времени и чувствительна к требованиям времени. Когда сторона устройства ep_queues пакет данных, она должна нести номер микрокадра ожидаемых данных для отправки. Если срок действия номера микрокадра истек, то , текущий номер микрокадра больше заданного номера микрокадра, произойдет событие Missed Isoc и пакет будет отброшен)

R

IOC

Interrupt on Complete

Когда IOC=1, контроллер сгенерирует XferInProgress?

R

Ссылки

  1. Rockchip RK3399TRM V1.3 Part1
  2. Rockchip RK3399TRM V1.3 Part2
  3. Исходный код ядра Linux версии 4.4.179
boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose