Introduce the matching PCI ath(4) fixup code from ar71xx_pci into

ar724x_pci.c.

* Move out the code which populates the firmware into ar71xx_fixup.c
* Shuffle around the ar724x fixup code to match what the ar71xx fixup
  code does.

I've validated this on an AR7240 with AR9285 on-board NIC. It doesn't
yet load, as the AR9285 EEPROM code needs to be made "flash aware."

TODO:

* Validate that I haven't broken AR71xx
* Test AR9285/AR9287 onboard NICs, complete with EEPROM code changes
* Port over the needed BAR hacks for AR7240, AR7241 and AR7242 from
  Linux OpenWRT.  The current WAR has only been tested on the AR7240
  and I'm not sure the way the BAR register is treated is "right".
  The "fixup" method here is right when setting the BAR for local access -
  ie, the BAR address is either 0xffff (AR7240) or 0x1000ffff (AR7241/AR7242),
  but the ath9k-fixup.c code (Linux OpenWRT) does this when setting the
  initial "fixup" BAR.  It then restores the original BAR.
  I'll have to read the ar724x PCI bus glue to see what other special cases
  await.
This commit is contained in:
Adrian Chadd 2012-04-20 08:26:05 +00:00
parent dca5e0ec50
commit b50d8083ab
5 changed files with 275 additions and 83 deletions

View File

@ -0,0 +1,153 @@
/*-
* Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_ar71xx.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/interrupt.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_extern.h>
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/intr_machdep.h>
#include <machine/pmap.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcib_private.h>
#include "pcib_if.h"
#include <mips/atheros/ar71xxreg.h>
#include <mips/atheros/ar71xx_pci_bus_space.h>
#include <mips/atheros/ar71xx_cpudef.h>
#include <sys/linker.h>
#include <sys/firmware.h>
#include <mips/atheros/ar71xx_fixup.h>
/*
* Take a copy of the EEPROM contents and squirrel it away in a firmware.
* The SPI flash will eventually cease to be memory-mapped, so we need
* to take a copy of this before the SPI driver initialises.
*/
void
ar71xx_pci_slot_create_eeprom_firmware(device_t dev, u_int bus, u_int slot,
u_int func, long int flash_addr, int size)
{
char buf[64];
uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr);
void *eeprom = NULL;
const struct firmware *fw = NULL;
device_printf(dev, "EEPROM firmware: 0x%lx @ %d bytes\n",
flash_addr, size);
eeprom = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
if (! eeprom) {
device_printf(dev,
"%s: malloc failed for '%s', aborting EEPROM\n",
__func__, buf);
return;
}
memcpy(eeprom, cal_data, size);
/*
* Generate a flash EEPROM 'firmware' from the given memory
* region. Since the SPI controller will eventually
* go into port-IO mode instead of memory-mapped IO
* mode, a copy of the EEPROM contents is required.
*/
snprintf(buf, sizeof(buf), "%s.%d.bus.%d.%d.%d.eeprom_firmware",
device_get_name(dev), device_get_unit(dev), bus, slot, func);
fw = firmware_register(buf, eeprom, size, 1, NULL);
if (fw == NULL) {
device_printf(dev, "%s: firmware_register (%s) failed\n",
__func__, buf);
free(eeprom, M_DEVBUF);
return;
}
device_printf(dev, "device EEPROM '%s' registered\n", buf);
}
#if 0
static void
ar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func)
{
long int flash_addr;
char buf[64];
int size;
/*
* Check whether the given slot has a hint to poke.
*/
if (bootverbose)
device_printf(dev, "%s: checking dev %s, %d/%d/%d\n",
__func__, device_get_nameunit(dev), bus, slot, func);
snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr",
bus, slot, func);
if (resource_long_value(device_get_name(dev), device_get_unit(dev),
buf, &flash_addr) == 0) {
snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size",
bus, slot, func);
if (resource_int_value(device_get_name(dev),
device_get_unit(dev), buf, &size) != 0) {
device_printf(dev,
"%s: missing hint '%s', aborting EEPROM\n",
__func__, buf);
return;
}
device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n",
flash_addr, bus, slot, func);
ar71xx_pci_fixup(dev, bus, slot, func, flash_addr, size);
ar71xx_pci_slot_create_eeprom_firmware(dev, bus, slot, func,
flash_addr, size);
}
}
#endif /* 0 */

View File

@ -0,0 +1,36 @@
/*-
* Copyright (c) 2012, Adrian Chadd <adrian@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef __ATHEROS_AR71XX_FIXUP_H__
#define __ATHEROS_AR71XX_FIXUP_H__
extern void ar71xx_pci_slot_create_eeprom_firmware(device_t dev,
u_int bus, u_int slot, u_int func, long int flash_addr, int size);
#endif /* __ATHEROS_AR71XX_FIXUP_H__ */

View File

@ -63,8 +63,7 @@ __FBSDID("$FreeBSD$");
#include <mips/atheros/ar71xx_cpudef.h>
#ifdef AR71XX_ATH_EEPROM
#include <sys/linker.h>
#include <sys/firmware.h>
#include <mips/atheros/ar71xx_fixup.h>
#endif /* AR71XX_ATH_EEPROM */
#undef AR71XX_PCI_DEBUG
@ -288,7 +287,7 @@ ar71xx_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func,
*/
static void
ar71xx_pci_fixup(device_t dev, u_int bus, u_int slot, u_int func,
long flash_addr)
long flash_addr, int len)
{
uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr);
uint32_t reg, val, bar0;
@ -328,67 +327,12 @@ ar71xx_pci_fixup(device_t dev, u_int bus, u_int slot, u_int func,
ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), bar0, 4);
}
/*
* Take a copy of the EEPROM contents and squirrel it away in a firmware.
* The SPI flash will eventually cease to be memory-mapped, so we need
* to take a copy of this before the SPI driver initialises.
*/
static void
ar71xx_pci_slot_create_eeprom_firmware(device_t dev, u_int bus, u_int slot,
u_int func, long int flash_addr)
{
char buf[64];
uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr);
void *eeprom = NULL;
const struct firmware *fw = NULL;
int len;
snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size",
bus, slot, func);
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
buf, &len) != 0) {
device_printf(dev, "%s: missing hint '%s', aborting EEPROM\n",
__func__, buf);
return;
}
device_printf(dev, "EEPROM firmware: 0x%lx @ %d bytes\n",
flash_addr, len);
eeprom = malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
if (! eeprom) {
device_printf(dev,
"%s: malloc failed for '%s', aborting EEPROM\n",
__func__, buf);
return;
}
memcpy(eeprom, cal_data, len);
/*
* Generate a flash EEPROM 'firmware' from the given memory
* region. Since the SPI controller will eventually
* go into port-IO mode instead of memory-mapped IO
* mode, a copy of the EEPROM contents is required.
*/
snprintf(buf, sizeof(buf), "%s.%d.bus.%d.%d.%d.eeprom_firmware",
device_get_name(dev), device_get_unit(dev), bus, slot, func);
fw = firmware_register(buf, eeprom, len, 1, NULL);
if (fw == NULL) {
device_printf(dev, "%s: firmware_register (%s) failed\n",
__func__, buf);
free(eeprom, M_DEVBUF);
return;
}
device_printf(dev, "device EEPROM '%s' registered\n", buf);
}
static void
ar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func)
{
long int flash_addr;
char buf[32];
char buf[64];
int size;
/*
* Check whether the given slot has a hint to poke.
@ -396,16 +340,28 @@ ar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func)
if (bootverbose)
device_printf(dev, "%s: checking dev %s, %d/%d/%d\n",
__func__, device_get_nameunit(dev), bus, slot, func);
snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr",
bus, slot, func);
if (resource_long_value(device_get_name(dev), device_get_unit(dev),
buf, &flash_addr) == 0) {
snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size",
bus, slot, func);
if (resource_int_value(device_get_name(dev),
device_get_unit(dev), buf, &size) != 0) {
device_printf(dev,
"%s: missing hint '%s', aborting EEPROM\n",
__func__, buf);
return;
}
device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n",
flash_addr, bus, slot, func);
ar71xx_pci_fixup(dev, bus, slot, func, flash_addr);
ar71xx_pci_fixup(dev, bus, slot, func, flash_addr, size);
ar71xx_pci_slot_create_eeprom_firmware(dev, bus, slot, func,
flash_addr);
flash_addr, size);
}
}
#endif /* AR71XX_ATH_EEPROM */

View File

@ -29,6 +29,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_ar71xx.h"
#include <sys/param.h>
#include <sys/systm.h>
@ -61,6 +63,10 @@ __FBSDID("$FreeBSD$");
#include <mips/atheros/ar71xx_cpudef.h>
#ifdef AR71XX_ATH_EEPROM
#include <mips/atheros/ar71xx_fixup.h>
#endif /* AR71XX_ATH_EEPROM */
#undef AR724X_PCI_DEBUG
#ifdef AR724X_PCI_DEBUG
#define dprintf printf
@ -243,27 +249,21 @@ ar724x_pci_setup(device_t dev)
return (0);
}
#ifdef AR71XX_ATH_EEPROM
#define AR5416_EEPROM_MAGIC 0xa55a
/*
* XXX - This should not be here ! And this looks like Atheros (if_ath) only.
*/
static void
ar724x_load_eeprom_data(device_t dev)
ar724x_pci_fixup(device_t dev, long flash_addr, int len)
{
uint32_t bar0, hint, reg, val;
uint16_t *data = NULL;
uint32_t bar0, reg, val;
uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr);
/* Search for a hint of eeprom data offset */
if (resource_int_value(device_get_name(dev),
device_get_unit(dev), "eepromdata", &hint) != 0)
return;
device_printf(dev, "Loading the eeprom fixup data from %#x\n", hint);
data = (uint16_t *)MIPS_PHYS_TO_KSEG1(hint);
if (*data != AR5416_EEPROM_MAGIC) {
device_printf(dev, "Invalid calibration data from %#x\n", hint);
if (cal_data[0] != AR5416_EEPROM_MAGIC) {
device_printf(dev, "%s: Invalid calibration data from 0x%x\n",
__func__, (uintptr_t) flash_addr);
return;
}
@ -275,11 +275,14 @@ ar724x_load_eeprom_data(device_t dev)
ar724x_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND, val, 2);
/* set pointer to first reg address */
data += 3;
while (*data != 0xffff) {
reg = *data++;
val = *data++;
val |= (*data++) << 16;
cal_data += 3;
while (*cal_data != 0xffff) {
reg = *cal_data++;
val = *cal_data++;
val |= (*cal_data++) << 16;
if (bootverbose)
printf(" 0x%08x=0x%04x\n", reg, val);
/* Write eeprom fixup data to device memory */
ATH_WRITE_REG(AR71XX_PCI_MEM_BASE + reg, val);
@ -293,9 +296,51 @@ ar724x_load_eeprom_data(device_t dev)
/* Write the saved bar(0) address */
ar724x_pci_write_config(dev, 0, 0, 0, PCIR_BAR(0), bar0, 4);
}
#undef AR5416_EEPROM_MAGIC
/*
* XXX This is (mostly) duplicated with ar71xx_pci.c.
* It should at some point be fixed.
*/
static void
ar724x_pci_slot_fixup(device_t dev)
{
long int flash_addr;
char buf[64];
int size;
/*
* Check whether the given slot has a hint to poke.
*/
if (bootverbose)
device_printf(dev, "%s: checking dev %s, %d/%d/%d\n",
__func__, device_get_nameunit(dev), 0, 0, 0);
snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr",
0, 0, 0);
if (resource_long_value(device_get_name(dev), device_get_unit(dev),
buf, &flash_addr) == 0) {
snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size",
0, 0, 0);
if (resource_int_value(device_get_name(dev),
device_get_unit(dev), buf, &size) != 0) {
device_printf(dev,
"%s: missing hint '%s', aborting EEPROM\n",
__func__, buf);
return;
}
device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n",
flash_addr, 0, 0, 0);
ar724x_pci_fixup(dev, flash_addr, size);
ar71xx_pci_slot_create_eeprom_firmware(dev, 0, 0, 0,
flash_addr, size);
}
}
#endif /* AR71XX_ATH_EEPROM */
static int
ar724x_pci_probe(device_t dev)
{
@ -357,8 +402,9 @@ ar724x_pci_attach(device_t dev)
if (ar724x_pci_setup(dev))
return (ENXIO);
/* XXX - Load eeprom fixup data */
ar724x_load_eeprom_data(dev);
#ifdef AR71XX_ATH_EEPROM
ar724x_pci_slot_fixup(dev);
#endif /* AR71XX_ATH_EEPROM */
/* Fixup internal PCI bridge */
ar724x_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND,

View File

@ -21,5 +21,6 @@ mips/atheros/ar71xx_setup.c standard
mips/atheros/ar71xx_chip.c standard
mips/atheros/ar724x_chip.c standard
mips/atheros/ar91xx_chip.c standard
mips/atheros/ar71xx_fixup.c optional ar71xx_ath_eeprom
dev/hwpmc/hwpmc_mips24k.c optional hwpmc