Solución al error ‘Forced PIO by use_pio module parameter’ en Driver B43 (Broadcom)

Era el mes de Septiembre del año 2009 cuando empecé mi andadura por el mundo GNU/Linux, y la distribución escogida obviamente fue Ubuntu «Karmic Koala». Por ese entonces, una de las más fáciles de instalar y utilizar para usuarios sin conocimientos previos. Claro que al cabo de unos meses ya deseada dar el salto a otra/s distro/s, y mi empecinamiento estaba dirigido a dos distribuciones en particular: Debian «Lenny» y Fedora.

Lo de «empecinamiento» se debe a que ninguna de las dos me la hizo fácil, en aquel momento, hacer funcionar el driver b43 (Broadcom) fue realmente un verdadero dolor de cabeza. Ambas distribuciones tenían políticas férreas con respecto a software privativo, y este driver en particular no estaba tan maduro en esos años.

Aquellos que usan una tarjeta de red Broadcom 4312 (14e4:4315) sabrán a lo que me refiero: el problemático «DMA error». Bajo esas circunstancias solo me quedaba la opción de hacer muchas pruebas y compilaciones para poder ver resultados positivos. Los primeros avances resultaron satisfactorios en Debian, aunque, al reiniciar el sistema el driver volvía a fallar. Esta situación mejoró cuando Debian recaló en el kernel 2.6.32-trunk, anteriormente 2.6.26.

Desde entonces he podido disfrutar de un Debian funcional a lo largo de estos diez años. En la actualidad, el fantasma del pasado parece haber vuelto a mi Debian «Buster». Si bien el contexto del error es diferente, sigue relacionado con el acceso DMA. Antes de continuar voy a exponer algunos conceptos básicos para lograr un mejor entendimiento de la situación.

DMA

El acceso directo a memoria (DMA, del inglés direct memory access) permite a cierto tipo de componentes de una computadora acceder a la memoria del sistema para leer o escribir independientemente de la unidad central de procesamiento (CPU) principal. Muchos sistemas hardware utilizan DMA, incluyendo controladores de unidades de disco, tarjetas gráficas y tarjetas de sonido. DMA es una característica esencial en todos los ordenadores modernos, ya que permite a dispositivos de diferentes velocidades comunicarse sin someter a la CPU a una carga masiva de interrupciones.

—Wikipedia

IOMMU

Una unidad de gestión de memoria de entrada y salida (input–output memory management unit, acrónimo IOMMU) es una unidad de gestión de memoria (MMU) que conecta un bus de E/S con capacidad de acceso directo a memoria (compatible con DMA) a la memoria principal. Al igual que una MMU tradicional, que traduce direcciones virtuales visibles de CPU a direcciones físicas, IOMMU correlaciona direcciones virtuales visibles de dispositivo (también llamadas direcciones de dispositivo o direcciones de E/S en este contexto) a direcciones físicas. Algunas unidades también brindan protección de memoria contra dispositivos defectuosos o maliciosos.

—Wikipedia

Modo PIO

A diferencia de DMA, en el modo PIO las transferencias de datos a la memoria RAM se realizan a través de la CPU, básicamente, esta última actúa como intermediario momentáneo entre el dispositivo y la memoria física. La utilización de este método suele ralentizar el sistema, incluso hasta dejarlo colapsado. La mayoría de los dispositivos modernos utilizan el modo DMA, UDMA y IOMMU.

En mi caso particular, la tarjeta de red no soporta acceso directo a memoria, el driver simplemente devolvía un mensaje de error/restart y la red inalámbrica quedaba en pleno funcionamiento. Esto ha venido sucediendo en todas las versiones de Debian, excepto la actual: «Buster». También es posible que el controlador no se lleve bien con el kernel 4.19.0-5-amd64 propiamente dicho.

Los síntomas

Empecé a sospechar de que algo no estaba bien al ver un comportamiento errático en el indicador de red (nm-applet), la intensidad de la señal variaba constantemente, y las peticiones de red en muchos casos tardaban demasiado en resolverse. Probé reiniciar el sistema para ver si se corregía este comportamiento, pero al contrario de lo que podría suponer, la red inalámbrica ya no se conectaría más —amenos que volviera a encender el portátil—.

Cuando tenemos esta clase de problemas con nuestro sistema, el primer lugar para recavar información, es en la salida del comando: sudo dmesg. Este nos dará con certeza un punto de partida para tratar en lo posible de encontrar una solución. En mi caso devolvió lo siguiente:

b43-phy0 ERROR: Fatal DMA error: 0x00000400, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
b43-phy0 ERROR: This device does not support DMA on your system. It will now be switched to PIO.
b43-phy0: Controller RESET (DMA error) ...	

Al no soportar DMA cambia al modo de transferencias PIO (Programed Input/Output). Unas lineas más abajo:

b43-phy0 warning: Forced PIO by use_pio module parameter. This should not be needed and will result in lower performance.
b43-phy0: Controller restarted

fuerza el modo PIO mediante el uso del módulo pio y se reinicia, sin embargo, la red inalámbrica a pesar de esta directiva nunca se conecta.

Observando el código fuente del kernel en el archivo: drivers/net/wireless/broadcom/b43/main.c, se puede ver que PIO está deshabilitado por omisión.

static int b43_modparam_pio = 0;
module_param_named(pio, b43_modparam_pio, int, 0644);
MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");

más abajo:

if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK))) {
		b43err(dev->wl,
			"Fatal DMA error: 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
			dma_reason[0], dma_reason[1],
			dma_reason[2], dma_reason[3],
			dma_reason[4], dma_reason[5]);
		b43err(dev->wl, "This device does not support DMA "
			       "on your system. It will now be switched to PIO.\n");
		/* Fall back to PIO transfers if we get fatal DMA errors! */
		dev->use_pio = true;
		b43_controller_restart(dev, "DMA error");
		return;

Lo que puedo interpretar en esas lineas es lo que sucede más arriba: En caso de «DMA error» recurrir a transferencias PIO y reiniciar el controlador. Obviamente funciona en el encendido del portátil —la red se conecta en primera instancia—, en el reinicio del sistema es cuando deja de funcionar por alguna razón.

Existen al menos dos soluciones para solventar este error:

  • Habilitar modo PIO en el módulo b43.
  • Deshabilitar IOMMU en el kernel.

Habilitar modo PIO en el arranque por omisión

Cuando se indica que habilitemos cierto parámetro en algún módulo de nuestro sistema, y no tenemos bien en claro como hacerlo, lo más indicado es recurrir al comando: sudo modinfo <módulo>. Aparte de otra información,  obtendremos la lista de parámetros que soporta, y su estado por defecto (enable/disable).

Salida de sudo modinfo b43:

parm:           bad_frames_preempt:enable(1) / disable(0) Bad Frames Preemption (int)
parm:           fwpostfix:Postfix for the .fw files to load. (string)
parm:           hwpctl:Enable hardware-side power control (default off) (int)
parm:           nohwcrypt:Disable hardware encryption. (int)
parm:           hwtkip:Enable hardware tkip. (int)
parm:           qos:Enable QOS support (default on) (int)
parm:           btcoex:Enable Bluetooth coexistence (default on) (int)
parm:           verbose:Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug (int)
parm:           pio:Use PIO accesses by default: 0=DMA, 1=PIO (int)
parm:           allhwsupport:Enable support for all hardware (even it if overlaps with the brcmsmac driver) (int)

El que me interesa es pio y para habilitarlo de forma permanente se debe editar el archivo /etc/modprobe.d/b43.conf. Si no existe se deberá crear: sudo touch /etc/modprobe.d/b43.conf.

Editamos el archivo con la siguiente linea:

options b43 pio=1

otra forma de hacerlo:

sudo touch /etc/modprobe.d/b43.conf
echo "options b43 pio=1" | sudo tee -a /etc/modprobe.d/b43.conf
También se aconseja deshabilitar el parámetro qos el cual como se ve en las lineas más arriba está habilitado por defecto. De hecho este último paso parece ser más importante, la red se conecta al recargar el módulo como describo más adelante, incluso sin el parámetro pio=1.

Configuración final en: /etc/modprobe.d/b43.conf:

options b43 pio=1 qos=0

Deshabilitar IOMMU en el Kernel

Esta información la encontré en la lista de Debian, no entiendo cuál es la implicancia de IOMMU con la tarjeta de red, una posibilidad, es que estuviera intentando mapear direcciones DMA. Sin embargo, es una tecnología relativamente nueva, y se encuentra en ordenadores de última generación. Mi portátil es del 2009, lejos está de usar IOMMU. Lo único seguro es que la sola inhabilitación del mismo soluciona el error.

Para este caso hay que editar el fichero: /etc/default/grub

agregando la linea intel_iommu=off a la opción GRUB_CMDLINE_LINUX_DEFAULT:

GRUB_DEFAULT=0
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=off quiet"
GRUB_CMDLINE_LINUX=""

luego de salvar los cambios ejecutamos: sudo update-grub para actualizar el gestor de arranque.

Nota: Si por el contrario se tratara de una cpu AMD el parámetro sería: amd_iommu=off.

En el próximo encendido o reinicio del sistema se aplicarán los cambios que se hayan hecho. También es posible recargar el módulo b43 con dichos parámetros (pio/qos) sin necesidad de reiniciar el sistema:

sudo rmmod b43
sudo modprobe b43 pio=1 qos=0

Conclusión

Aunque se podrían aplicar ambas opciones al mismo tiempo, la segunda opción (IOMMU) es la que más me ha convencido. La red inalámbrica se conecta en cada reinicio, de hecho, se obtiene mejor resultado que con la opción del parámetro pio —suele fallar—. En cuanto al rendimiento del driver b43 aún tengo mis dudas, haré otras pruebas para un futuro artículo.


Fuente:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927078
https://en.wikipedia.org/wiki/Direct_memory_access
https://en.wikipedia.org/wiki/Input–output_memory_management_unit
https://wiki.debian.org/bcm43xx
https://wiki.archlinux.org/index.php/Broadcom_wireless
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/?h=v4.19.79

¿Te resultó interesante? Compártelo ...



Percaff_TI99

Publicado por Percaff_TI99

http://gutl.jovenclub.cu/ » Forma parte de GUTL desde el 10 agosto, 2013. Amante de la ciencia y tecnología en general. Usuario de GNU/Linux desde hace varios años.

Este artículo tiene 5 comentarios

  1. Percaff_TI99:

    En la entrada de Pablo titulada: «Experiencia con Dell Inspiron 5575 Ryzen 5 y Debian Buster GNU/Linux», dejé un breve comentario sobre los problemas que nos ha dado Debian 10 en el uso de Alarife 4 relacionado con el empleo de bibliotecas Qt que, hasta la versión 9.11 de Debian, funcionan sin problema alguno. Ahora leo tu entrada y confirmo el juicio que vertí en la precitada entrada sobre los problemas que, después de la versión 6 (Squeeze), ha venido presentando la distribución.

    Por cierto, leí días atrás que estaban considerando dar la opción de iniciar el sistema eligiendo entre Systemd o Sys Vinit, según el gusto del usuario y en ello ha influido, sin duda alguna, el fork Devuan.

    • Hola Delio:

      Tienes razón en ello, para mi también squeeze y wheezy (en mi caso personal) fueron el pico máximo no solo de estabilidad, sino de gestión de recursos. Ahora por momentos tengo que vaciar la cache desde la consola. Soy consiente que las librerías actuales requieren más recursos, sin embargo hace un tiempo atrás leí un artículo de un desarrollador -creo que colabora con el kernel- y está decepcionado por lo mal que Linux está gestionando la memoria, literalmente explicó que llega a colapsar la ram de 4GB abriendo algunas pestañas en Firefox.

      En cuanto a las librerías Qt podría tratarse de un desbordamiento de buffer, posiblemente sus colegas (Matos) puedan detectar el problema con GDB. Aunque pienso que el programa de ustedes está bien, sospecho que se trata de un problema de Debian. Me explico: a raíz de otro artículo (más defectos en Debian) hace unos días atrás intenté utilizar la herramienta «qtiplot» y se cierra en cuanto quiero generar un plot, u otra opción.

      Ojalá se concrete lo de sysvinit, el usuario tiene derecho a optar por otra alternativa. Además era mucho más fácil de configurar procesos. SystemD tiene demasiada injerencia en todo el sistema.

      Saludos.

      • Soy uno de los que sufre con el patatus que sufre el sistema usando Chrome o Mozilla… Estoy limitado a 4 GB ram y desde que arranco el sistema ya tengo una consola abierta para matar procesos y hacer magia para no tener que reiniciar.

        Te agradeceria un post explicando como vaciar la cache…

        Eso lo tenia automatizado hace unos años con un script, pero en alguna reinstalacion lo perdí y nunca mas logre que me funcionara correctamente de nuevo.

        • Hola Pablo:

          Yo tenía un script en /usr/local/bin:

          —————————————————————
          #!/bin/sh

          sync; echo 3 > /proc/sys/vm/drop_caches
          —————————————————————

          Había creado una tarea en crontab pero nunca sabes cuando necesitas que se ejecute realmente: demasiado pronto y viceversa.

          Acá en GUTL hay otras maneras interesantes de hacerlo (https://gutl.jovenclub.cu/?s=drop_cache&x=0&y=0).

          Ahora simplemente ejecuto (root): sync; echo 3 > /proc/sys/vm/drop_caches y cuando tengo que volver a hacerlo utilizo desde la consola Control-r para búsqueda hacia atrás: no alcanzo a escribir «sync» o «echo» que ya me tira el comando.

          (reverse-i-search)`ec’: sync; echo 3 > /proc/sys/vm/drop_caches

          Intentaré hacer un script que monitorice la ram y aplique el comando cuando sea conveniente.

          Saludos.

Los comentarios están cerrados.