Конвертация Linux-драйверов устройств для работы на архитектуре Power

Архитектура Power относится к типу big-endian (обратный порядок байтов)
 

Используйте архитектурно-независимые функции преобразования (cpu_to_*, *_to_cpu и др.), описанные в файле include/linux/byteorder/generic.h.

 

             Доступ к устройству

 

Для отображаемых в память операций ввода-вывода используйте макросы read[bwlq] и write[bwlq]. Эти макросы совершают следующие действия:

 – Выполняют (при необходимости) перестановку байтов.

 – Преобразуют адрес, возвращаемый ядром, в реальный физический адрес, который может использоваться драйвером.

 – Выполняют проверку на ошибки EEH.

 – Предоставляют соответствующие барьеры.

Если перестановка байтов не требуется, вызывают функции raw_readl и raw_writel, не использующие барьеры.

При программировании буфера кадров используют функции fb_readX и fb_writeX.

Функции readl и writel обращаются к памяти PCI блоками по 32 бита. PCI по определению имеет прямой порядок байтов, поэтому на архитектуре Power требуется перестановка.

 

               Адресация по шине

 

– Прочтите файлы ../Documentation/IO-mapping.txt и ../Documentation/DMA-mapping.txt в исходных кодах.

– В PowerPC применяется линейная адресация; проблемы с HIGHMEM отсутствуют. При правильном отображении памяти любой участок памяти может быть использован для DMA.

 

ioremap

Функция ioremap выполняет последовательность зависящих от платформы операций для обеспечения доступа центрального процессора к памяти шины при помощи функций readb/readw/readl/writeb/writew/writel и других вспомогательных функций MMIO. Обратите внимание, что возможность использования возвращаемого адреса в качестве виртуального адреса напрямую зависит от оборудования.

 

PCI

 – На компьютерах с большим объемом памяти (более 2 ГБ) адресное пространство превышает четырехгигабайтное ограничение 32-битных адресов. PCI-мосты в таких системах имеют таблицу страниц для трансляции 32-битных виртуальных адресов в 64-битные физические адреса, в которых каждая запись включает в себя биты разрешения чтения/записи. Записи в таблице называются TCE (translation control entries, записи управления трансляцией). Разрешения на чтение/запись устанавливаются оборудованием шины, поэтому важно указывать корректные флаги (PCI_DMA_FROMDEVICE, PCI_DMA_TODEVICE и т.д.). Обратите внимание, что при указании некорректного флага произойдет событие системы EEH (системы улучшенной обработки ошибок).

 – Вызовы pci_alloc_consistent, pci_map_single, pci_map_sg могут применяться для создания записей управления трансляцией (TCE). Пространство TCE ограничено, поэтому необходимо следить за правильностью использования вызовов pci_free_consistent, pci_unmap_single и pci_unmap_sg.

 – Для доступа к устройству используйте макросы read[bwlq] и write[bwlq] (см. выше раздел Доступ к устройству), чтобы адрес, предоставляемый драйверу ядром, был соответствующим образом изменен.

 
             Работа с кэшем

 

На архитектурах Power осуществляется синхронизация кэша. Однако инструкции store из регистров не синхронизируются до тех пор, пока они не попадут в кэш.

Последовательность ожидающих выполнения инструкций store создает очередь на чтение данных из кэша. По мере поступления, строки кэша в L1 отдаются соответствующим инструкциям store без учета их места в очереди. Для очистки очереди используйте инструкции lwsync или sync (см. раздел Синхронизация инструкций). Макросы write[bwlq] вызывают sync после записи. Если буфер настроен на прием данных от устройства по DMA, то после записи последнего байта и до уведомления адаптера о событии следует вызвать функцию lwsync.

Процедуры спин-блокировки вызывают lwsync в начале разблокировки.

 

            Синхронизация инструкций

sync

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

 

lwsync

Создает барьер памяти для кэшированных инструкций load и store на выполняющем их процессоре. Это упрощенная инструкция sync, предназначенная для использования в блокировках и семафорах, когда нет необходимости в синхронизации некэшированного доступа. Доступна только на Power4 и выше — на более старых системах она будет действовать как инструкция sync. Предоставляет ту же функцию упорядочения, что и sync, за исключением того, что функция load, вызванная инструкцией, следующей за lwsync, может выполняться до store, вызванной инструкцией, предшествующей lwsync; кроме того, упорядочение не распространяется на обращения к памяти ввода-вывода (ввод-вывод с отображением в память, memory-mapped I/O).

 

isync

Заставляет процессор отклонить все упреждающие (и, возможно, спекулятивно выполненные) инструкции и повторно выбрать инструкции, следующие за isync. Применяется в блокирующем коде (например, __check_lock), чтобы после входа в критический участок инструкции load не обращались к данным до получения блокировки (из-за агрессивного внеочередного спекулятивного выполнения инструкций процессором).

 

eieio

Создает барьер памяти для некэшированных инструкций load и store, а также генерирует транзакцию по системной шине, микросхемы интерфейса шины также соблюдали этот барьер. Записи в одну и ту же область ввода-вывода (например, регистр базового адреса PCI-адаптера) не переупорядочиваются. Предоставляет такую же функцию упорядочения, как и инструкция sync, за исключением того, что упорядочение применяется только к обращениям к памяти ввода-вывода.

 

           Архитектурно-независимые барьеры памяти

 

В 64-битных процессорах PowerPC вызовы mb() и wmb() генерируют sync, а вызов rmb() генерирует lwsync. Реализацию этих вызовов смотрите в файле include/asm-ppc64/system.h.

 

Ниже приведен пример вызовов rmb() и wmb() из файла drivers/net/pcnet32.c:

 

Листинг 1. Вызовы rmb() и wmb() из файла drivers/net/pcnet32.c

/* Проверка статуса дескрипторов */

    for (x=0; x<numbuffs; x++) {

        ticks = 0;

 

            /* Так как будет производиться чтение из кэшированной памяти,

            вызвать барьер памяти на чтение */

        rmb();

 

        while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {

            spin_unlock_irqrestore(&lp->lock, flags);

            mdelay(1);

            spin_lock_irqsave(&lp->lock, flags);

            rmb();          /* Read Memory Barrier */

            ticks++;

        }

        if (ticks == 200) {

            if (netif_msg_hw(lp))

                printk(%s: Desc %d failed to reset!\\n,dev->name,x);

            break;

        }

    }

 

    lp->a.write_csr(ioaddr, 0, 0x0004);         /* Установка бита STOP */

 

    /* Перед сравнением данных вызвать барьер памяти на запись,

    чтобы гарантировать завершение всех операций записи */

    wmb();

 

    if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {

            printk(KERN_DEBUG %s: RX loopback packets:\\n, dev->name);

 

            for (x=0; x<numbuffs; x++) {

                printk(KERN_DEBUG %s: Packet %d:\\n, dev->name, x);

                skb = lp->rx_skbuff[x];

                for (i=0; i<size; i++) {

                        printk(%02x , *(skb->data+i));

                }

                printk(\\n);

            }

    }

 

 

 

             Улучшенная обработка ошибок (Enhanced Error Handling – EEH)

 

Улучшенная обработка ошибок ввода-вывода (EEH) — это стратегия устранения ошибок, возникающих в шине PCI. Она реализуется микросхемой EADS за счет того, что каждый слот PCI может иметь собственную шину PCI. Следовательно, каждое устройство в случае ошибки может быть изолировано, и устранение ошибки не повлияет на работу других устройств в системе. Без EEH компьютеры серии pSeries в случае ошибки шины PCI (вызванной шиной или устройством на шине) выполняли бы контрольный останов. Микросхема EADS предоставляет возможность заморозить устройство в случае ошибки ввода-вывода и избежать контрольного останова. Производится попытка сброса устройства и после трех неудачных попыток устройство отмечается как неработоспособное.

 

В случае обнаружения ошибки шины PCI/PCIX (помимо обычных сигналов об ошибках PCI/PCIX), слот переводится в замороженное состояние. Устройство не получает доступа к шине. Попытки записи в устройство отклоняются, а при попытках чтения все возвращаемые биты равны единице. Когда драйвер (или ядро) замечает, что все биты результата операции чтения равны единице, он проверяет слот на наличие ошибки шины. Эта проверка производится в макросах read[bwlq]. При обнаружении ошибки шины устройство отключается при помощи системы горячего отключения (hotplug) и через три секунды подключается снова. Рекомендуется, чтобы горячее отключение занимало менее трех секунд. Заметим, что операция чтения, при которой была обнаружена ошибка шины, не обязательно является причиной этой ошибки.

 

Устройства выводят в журнал данные о неудавшихся транзакциях в шине, слоте и т.д. Эти сведения сохраняются в журнале /var/log/messages как события RTAS.

 

Листинг 2. Пример вывода RTAS

Mar 23 <!–?xml:namespace prefix = st1 ns = urn:schemas-microsoft-com:office:smarttags /?–>22:53:57 bhs kernel: RTAS: 253 ——– RTAS event begin ——–

Mar 23 22:53:57 bhs kernel: RTAS 0: 064400e0 00000264 a6008e00 00000000

………………………………………………………………………

Mar 23 22:53:57 bhs kernel: RTAS 38: 21050002 00000604 c3300157

Mar 23 22:53:57 bhs kernel: RTAS: 253 ——– RTAS event end ———-

 

 

*Не все системы с архитектурой Power поддерживают EEH.

           

            Горячая замена PCI-устройств

 

Новые модели компьютеров PowerPC поддерживают горячую замену устройств PCI/PCIX. Используйте новую конфигурацию драйвера PCI (см. файл <версия_ядра>/Documentation/power/pci.txtfile).

 

Далее описано применение команд горячей замены (hotplug).

 

Подача питания на каждый слот управляется через sysfs. Каждый слот имеет отдельный каталог в /sys/bus/pci/slots, в котором, помимо прочего, есть файл power.

 – Для отключения питания слота введите команду echo 0 > power.

 – Для включения введите echo 1 > power.

 

К сожалению, поиск нужного подкаталога в каталоге /sys/bus/pci/slots затруднен. Имена подкаталогов основаны на нумерации устройств шины, которая осуществляется прошивкой и с трудом поддается расшифровке. Несколько рекомендаций:

Если вам известен код местонахождения AIX, в каждом каталоге есть файл phy_location, содержащий код местонахождения каждого слота. В файле adapter отражается наличие устройства в данном слоте. Кроме того, при помощи файла attention можно зажечь/погасить светодиод каждого слота или включить его мигание:

 – echo 0 > attention — отключить светодиод

 – echo 1 > attention — включить светодиод

 – echo 2 > attention — включить мигание светодиода

 

 

           Горячая замена USB-устройств

 

Сведения о горячей замене USB-устройств можно найти в файле ../Documentation/usb/hotplug.txt в исходных кода ядра.

 

           Отладка

 

Для получения информации по поводу отладки драйверов, обратитесь к следующим ресурсам:

 – printk – обязательно разберитесь с KERN_INFO, KERN_ERR и другими фильтрами сообщений syslog.

 – kdb – обратитесь на домашнюю страницу KDB, отладчика ядра Linux (http://oss.sgi.com/projects/kdb/).

 – lkcd – обратитесь на домашнюю страницу проекта LKCD (http://lkcd.sourceforge.net/).

 – работа с kprobes описана в статье Kernel debugging with Kprobes (Отладка ядра с помощью Kprobes, http://www.ibm.com/developerworks/linux/library/l-kprobes.html?S_TACT=105AGX99&S_CMP=CP)

 – Методы трассировки описаны в статье Linux Trace Toolkit (набор инструментов трассировки для Linux, http://www.opersys.com/LTT/index.html).

 – Обработка исключений описывается в статье Kernel-Level Exception Handing (Обработка исключений на уровне ядра, http://www.linuxjournal.com/article/2135.).

 

Советы

 – Не используйте CLI/STI, пользуйтесь спин-блокировкамии.

 – Компилируйте с ключом оптимизации -O2.

 – Переменные, которые могут изменять свое значение без предупреждений, обязательно отмечайте как volatile.

 – При необходимости используйте макросы likely и unlikely, чтобы помочь компилятору выполнять предсказание ветвления.

 – Чтобы позволить 32-битным приложениям вызывать ioctl в 64-битных ядрах Linux, необходимо предоставить функции трансляции. Если функции трансляции не зарегистрированы, вызывающая функция получит код ошибки EINVAL.

 Смотрите описание функций register_ioctl32_conversion и unregister_ioctl32_conversion в файле fs/compat.c

 -См. примеры в файле fs/compat_ioctl.c.

Добавить комментарий