bb5e3b2f129cc39517b925419c22f69a378ec023eh/*
d3d50737e566cade9a08d73d2af95105ac7cd960Rafael Vanoni * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
bb5e3b2f129cc39517b925419c22f69a378ec023eh * Use is subject to license terms.
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh/*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * Copyright (c) 2004, 2005
bb5e3b2f129cc39517b925419c22f69a378ec023eh * Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
bb5e3b2f129cc39517b925419c22f69a378ec023eh *
bb5e3b2f129cc39517b925419c22f69a378ec023eh * Redistribution and use in source and binary forms, with or without
bb5e3b2f129cc39517b925419c22f69a378ec023eh * modification, are permitted provided that the following conditions
bb5e3b2f129cc39517b925419c22f69a378ec023eh * are met:
bb5e3b2f129cc39517b925419c22f69a378ec023eh * 1. Redistributions of source code must retain the above copyright
bb5e3b2f129cc39517b925419c22f69a378ec023eh * notice unmodified, this list of conditions, and the following
bb5e3b2f129cc39517b925419c22f69a378ec023eh * disclaimer.
bb5e3b2f129cc39517b925419c22f69a378ec023eh * 2. Redistributions in binary form must reproduce the above copyright
bb5e3b2f129cc39517b925419c22f69a378ec023eh * notice, this list of conditions and the following disclaimer in the
bb5e3b2f129cc39517b925419c22f69a378ec023eh * documentation and/or other materials provided with the distribution.
bb5e3b2f129cc39517b925419c22f69a378ec023eh *
bb5e3b2f129cc39517b925419c22f69a378ec023eh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
bb5e3b2f129cc39517b925419c22f69a378ec023eh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
bb5e3b2f129cc39517b925419c22f69a378ec023eh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
bb5e3b2f129cc39517b925419c22f69a378ec023eh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
bb5e3b2f129cc39517b925419c22f69a378ec023eh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
bb5e3b2f129cc39517b925419c22f69a378ec023eh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
bb5e3b2f129cc39517b925419c22f69a378ec023eh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
bb5e3b2f129cc39517b925419c22f69a378ec023eh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
bb5e3b2f129cc39517b925419c22f69a378ec023eh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
bb5e3b2f129cc39517b925419c22f69a378ec023eh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
bb5e3b2f129cc39517b925419c22f69a378ec023eh * SUCH DAMAGE.
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh/*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * Intel Wireless PRO/2200 mini-PCI adapter driver
bb5e3b2f129cc39517b925419c22f69a378ec023eh * ipw2200_hw.c is used t handle hardware operations and firmware operations.
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include <sys/types.h>
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include <sys/byteorder.h>
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include <sys/ddi.h>
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include <sys/sunddi.h>
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include <sys/note.h>
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include <sys/stream.h>
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include <sys/strsun.h>
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include "ipw2200.h"
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include "ipw2200_impl.h"
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh/*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * Hardware related operations
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_EEPROM_SHIFT_D (2)
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_EEPROM_SHIFT_Q (4)
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_EEPROM_C (1 << 0)
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_EEPROM_S (1 << 1)
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_EEPROM_D (1 << IPW2200_EEPROM_SHIFT_D)
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_EEPROM_Q (1 << IPW2200_EEPROM_SHIFT_Q)
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehuint8_t
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_csr_get8(struct ipw2200_softc *sc, uint32_t off)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (ddi_get8(sc->sc_ioh, (uint8_t *)(sc->sc_regs + off)));
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehuint16_t
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_csr_get16(struct ipw2200_softc *sc, uint32_t off)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
922d2c76afbee21520ffa2088c4e60dcb80d3945eh return (ddi_get16(sc->sc_ioh,
922d2c76afbee21520ffa2088c4e60dcb80d3945eh (uint16_t *)((uintptr_t)sc->sc_regs + off)));
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehuint32_t
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_csr_get32(struct ipw2200_softc *sc, uint32_t off)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
922d2c76afbee21520ffa2088c4e60dcb80d3945eh return (ddi_get32(sc->sc_ioh,
922d2c76afbee21520ffa2088c4e60dcb80d3945eh (uint32_t *)((uintptr_t)sc->sc_regs + off)));
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehvoid
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_csr_getbuf32(struct ipw2200_softc *sc, uint32_t off,
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t *buf, size_t cnt)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
922d2c76afbee21520ffa2088c4e60dcb80d3945eh ddi_rep_get32(sc->sc_ioh, buf,
922d2c76afbee21520ffa2088c4e60dcb80d3945eh (uint32_t *)((uintptr_t)sc->sc_regs + off),
922d2c76afbee21520ffa2088c4e60dcb80d3945eh cnt, DDI_DEV_AUTOINCR);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehvoid
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_csr_put8(struct ipw2200_softc *sc, uint32_t off,
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint8_t val)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh ddi_put8(sc->sc_ioh, (uint8_t *)(sc->sc_regs + off), val);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehvoid
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_csr_put16(struct ipw2200_softc *sc, uint32_t off,
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint16_t val)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
922d2c76afbee21520ffa2088c4e60dcb80d3945eh ddi_put16(sc->sc_ioh,
922d2c76afbee21520ffa2088c4e60dcb80d3945eh (uint16_t *)((uintptr_t)sc->sc_regs + off), val);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehvoid
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_csr_put32(struct ipw2200_softc *sc, uint32_t off,
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t val)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
922d2c76afbee21520ffa2088c4e60dcb80d3945eh ddi_put32(sc->sc_ioh,
922d2c76afbee21520ffa2088c4e60dcb80d3945eh (uint32_t *)((uintptr_t)sc->sc_regs + off), val);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehuint8_t
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_imem_get8(struct ipw2200_softc *sc, uint32_t addr)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr);
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (ipw2200_csr_get8(sc, IPW2200_CSR_INDIRECT_DATA));
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehuint16_t
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_imem_get16(struct ipw2200_softc *sc,
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t addr)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr);
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (ipw2200_csr_get16(sc, IPW2200_CSR_INDIRECT_DATA));
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehuint32_t
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_imem_get32(struct ipw2200_softc *sc, uint32_t addr)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr);
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (ipw2200_csr_get32(sc, IPW2200_CSR_INDIRECT_DATA));
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehvoid
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_imem_put8(struct ipw2200_softc *sc, uint32_t addr, uint8_t val)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put8(sc, IPW2200_CSR_INDIRECT_DATA, val);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehvoid
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_imem_put16(struct ipw2200_softc *sc, uint32_t addr,
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint16_t val)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put16(sc, IPW2200_CSR_INDIRECT_DATA, val);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehvoid
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_imem_put32(struct ipw2200_softc *sc, uint32_t addr,
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t val)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_ADDR, addr);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_INDIRECT_DATA, val);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehvoid
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_rom_control(struct ipw2200_softc *sc, uint32_t val)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put32(sc, IPW2200_IMEM_EEPROM_CTL, val);
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(IPW2200_EEPROM_DELAY);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehuint16_t
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_rom_get16(struct ipw2200_softc *sc, uint8_t addr)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t tmp;
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint16_t val;
bb5e3b2f129cc39517b925419c22f69a378ec023eh int n;
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * According to i2c bus protocol
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh /* clock */
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, 0);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_C);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S);
bb5e3b2f129cc39517b925419c22f69a378ec023eh /* start bit */
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_D);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_D |
922d2c76afbee21520ffa2088c4e60dcb80d3945eh IPW2200_EEPROM_C);
bb5e3b2f129cc39517b925419c22f69a378ec023eh /* read opcode */
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_D);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_D |
922d2c76afbee21520ffa2088c4e60dcb80d3945eh IPW2200_EEPROM_C);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_C);
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * address, totally 8 bits, defined by hardware, push from MSB to LSB
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh for (n = 7; n >= 0; n--) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S |
922d2c76afbee21520ffa2088c4e60dcb80d3945eh (((addr >> n) & 1) << IPW2200_EEPROM_SHIFT_D));
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S |
922d2c76afbee21520ffa2088c4e60dcb80d3945eh (((addr >> n) & 1) << IPW2200_EEPROM_SHIFT_D) |
922d2c76afbee21520ffa2088c4e60dcb80d3945eh IPW2200_EEPROM_C);
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * data, totally 16 bits, defined by hardware, push from MSB to LSB
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh val = 0;
bb5e3b2f129cc39517b925419c22f69a378ec023eh for (n = 15; n >= 0; n--) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S | IPW2200_EEPROM_C);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S);
bb5e3b2f129cc39517b925419c22f69a378ec023eh tmp = ipw2200_imem_get32(sc, IPW2200_IMEM_EEPROM_CTL);
bb5e3b2f129cc39517b925419c22f69a378ec023eh val |= ((tmp & IPW2200_EEPROM_Q) >> IPW2200_EEPROM_SHIFT_Q)
bb5e3b2f129cc39517b925419c22f69a378ec023eh << n;
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, 0);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh /* clear chip select and clock */
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_S);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, 0);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_rom_control(sc, IPW2200_EEPROM_C);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (BE_16(val));
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh/*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * Firmware related operations
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_FW_MAJOR_VERSION (2)
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_FW_MINOR_VERSION (4)
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_FW_MAJOR(x)((x) & 0xff)
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define IPW2200_FW_MINOR(x)(((x) & 0xff) >> 8)
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh/*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * These firwares were issued by Intel as binaries which need to be
bb5e3b2f129cc39517b925419c22f69a378ec023eh * loaded to hardware when card is initiated, or when fatal error
bb5e3b2f129cc39517b925419c22f69a378ec023eh * happened, or when the chip need be reset.
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023ehstatic uint8_t ipw2200_boot_bin [] = {
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include "fw-ipw2200/ipw-2.4-boot.hex"
bb5e3b2f129cc39517b925419c22f69a378ec023eh};
bb5e3b2f129cc39517b925419c22f69a378ec023ehstatic uint8_t ipw2200_ucode_bin [] = {
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include "fw-ipw2200/ipw-2.4-bss_ucode.hex"
bb5e3b2f129cc39517b925419c22f69a378ec023eh};
bb5e3b2f129cc39517b925419c22f69a378ec023ehstatic uint8_t ipw2200_fw_bin [] = {
bb5e3b2f129cc39517b925419c22f69a378ec023eh#include "fw-ipw2200/ipw-2.4-bss.hex"
bb5e3b2f129cc39517b925419c22f69a378ec023eh};
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh#pragma pack(1)
bb5e3b2f129cc39517b925419c22f69a378ec023ehstruct header {
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t version;
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t mode;
bb5e3b2f129cc39517b925419c22f69a378ec023eh};
bb5e3b2f129cc39517b925419c22f69a378ec023eh#pragma pack()
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehint
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_cache_firmware(struct ipw2200_softc *sc)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_cache_firmware(): enter\n"));
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh /* boot code */
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_fw.boot_base = ipw2200_boot_bin + sizeof (struct header);
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_fw.boot_size =
922d2c76afbee21520ffa2088c4e60dcb80d3945eh sizeof (ipw2200_boot_bin) - sizeof (struct header);
bb5e3b2f129cc39517b925419c22f69a378ec023eh /* ucode */
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_fw.uc_base = ipw2200_ucode_bin + sizeof (struct header);
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_fw.uc_size = sizeof (ipw2200_ucode_bin) - sizeof (struct header);
bb5e3b2f129cc39517b925419c22f69a378ec023eh /* firmware */
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_fw.fw_base = ipw2200_fw_bin + sizeof (struct header);
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_fw.fw_size = sizeof (ipw2200_fw_bin) - sizeof (struct header);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_flags |= IPW2200_FLAG_FW_CACHED;
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_cache_firmware(): boot=%u,uc=%u,fw=%u\n",
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_fw.boot_size, sc->sc_fw.uc_size, sc->sc_fw.fw_size));
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_cache_firmware(): exit\n"));
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (DDI_SUCCESS);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh/*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * If user-land firmware loading is supported, this routine will
bb5e3b2f129cc39517b925419c22f69a378ec023eh * free kernel memory, when sc->sc_fw.bin_base & sc->sc_fw.bin_size
bb5e3b2f129cc39517b925419c22f69a378ec023eh * are not empty
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023ehint
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_free_firmware(struct ipw2200_softc *sc)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_flags &= ~IPW2200_FLAG_FW_CACHED;
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (DDI_SUCCESS);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh/*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * the following routines load code onto ipw2200 hardware
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023ehint
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_load_uc(struct ipw2200_softc *sc, uint8_t *buf, size_t size)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh int ntries, i;
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint16_t *w;
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_RST,
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_RST_STOP_MASTER | ipw2200_csr_get32(sc, IPW2200_CSR_RST));
bb5e3b2f129cc39517b925419c22f69a378ec023eh for (ntries = 0; ntries < 5; ntries++) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (ipw2200_csr_get32(sc, IPW2200_CSR_RST) &
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_RST_MASTER_DISABLED)
bb5e3b2f129cc39517b925419c22f69a378ec023eh break;
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(10);
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (ntries == 5) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_WARN((sc->sc_dip, CE_CONT,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_load_uc(): timeout waiting for master"));
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (DDI_FAILURE);
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put32(sc, 0x3000e0, 0x80000000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(5000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_RST,
bb5e3b2f129cc39517b925419c22f69a378ec023eh ~IPW2200_RST_PRINCETON_RESET &
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_get32(sc, IPW2200_CSR_RST));
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(5000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put32(sc, 0x3000e0, 0);
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(1000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put32(sc, IPW2200_IMEM_EVENT_CTL, 1);
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(1000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put32(sc, IPW2200_IMEM_EVENT_CTL, 0);
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(1000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put8(sc, 0x200000, 0x00);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put8(sc, 0x200000, 0x40);
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(1000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
922d2c76afbee21520ffa2088c4e60dcb80d3945eh for (w = (uint16_t *)(uintptr_t)buf; size > 0; w++, size -= 2)
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put16(sc, 0x200010, LE_16(*w));
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put8(sc, 0x200000, 0x00);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put8(sc, 0x200000, 0x80);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * try many times to wait the upload is ready, 2000times
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh for (ntries = 0; ntries < 2000; ntries++) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint8_t val;
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh val = ipw2200_imem_get8(sc, 0x200000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (val & 1)
bb5e3b2f129cc39517b925419c22f69a378ec023eh break;
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(1000); /* wait for a while */
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (ntries == 2000) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_WARN((sc->sc_dip, CE_WARN,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_load_uc(): timeout waiting for ucode init.\n"));
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (DDI_FAILURE);
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh for (i = 0; i < 7; i++)
bb5e3b2f129cc39517b925419c22f69a378ec023eh (void) ipw2200_imem_get32(sc, 0x200004);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put8(sc, 0x200000, 0x00);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (DDI_SUCCESS);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define MAX_DR_NUM (64)
bb5e3b2f129cc39517b925419c22f69a378ec023eh#define MAX_DR_SIZE (4096)
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehint
bb5e3b2f129cc39517b925419c22f69a378ec023ehipw2200_load_fw(struct ipw2200_softc *sc, uint8_t *buf, size_t size)
bb5e3b2f129cc39517b925419c22f69a378ec023eh{
bb5e3b2f129cc39517b925419c22f69a378ec023eh struct dma_region dr[MAX_DR_NUM]; /* maximal, 64 * 4KB = 256KB */
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint8_t *p, *end, *v;
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t mlen;
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t src, dst, ctl, len, sum, off;
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t sentinel;
bb5e3b2f129cc39517b925419c22f69a378ec023eh int ntries, err, cnt, i;
d3d50737e566cade9a08d73d2af95105ac7cd960Rafael Vanoni clock_t clk = drv_usectohz(5000000); /* 5 second */
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put32(sc, 0x3000a0, 0x27000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh p = buf;
bb5e3b2f129cc39517b925419c22f69a378ec023eh end = p + size;
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh cnt = 0;
bb5e3b2f129cc39517b925419c22f69a378ec023eh err = ipw2200_dma_region_alloc(sc, &dr[cnt], MAX_DR_SIZE, DDI_DMA_READ,
bb5e3b2f129cc39517b925419c22f69a378ec023eh DDI_DMA_STREAMING);
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (err != DDI_SUCCESS)
bb5e3b2f129cc39517b925419c22f69a378ec023eh goto fail0;
bb5e3b2f129cc39517b925419c22f69a378ec023eh off = 0;
bb5e3b2f129cc39517b925419c22f69a378ec023eh src = dr[cnt].dr_pbase;
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_ADDR, 0x27000);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh while (p < end) {
922d2c76afbee21520ffa2088c4e60dcb80d3945eh dst = LE_32(*((uint32_t *)(uintptr_t)p)); p += 4;
922d2c76afbee21520ffa2088c4e60dcb80d3945eh len = LE_32(*((uint32_t *)(uintptr_t)p)); p += 4;
bb5e3b2f129cc39517b925419c22f69a378ec023eh v = p;
bb5e3b2f129cc39517b925419c22f69a378ec023eh p += len;
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_load_fw(): dst=0x%x,len=%u\n", dst, len));
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh while (len > 0) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * if no DMA region is available, allocate a new one
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (off == dr[cnt].dr_size) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh cnt++;
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (cnt >= MAX_DR_NUM) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_WARN((sc->sc_dip, CE_WARN,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_load_fw(): "
bb5e3b2f129cc39517b925419c22f69a378ec023eh "maximum %d DRs is reached\n",
bb5e3b2f129cc39517b925419c22f69a378ec023eh cnt));
bb5e3b2f129cc39517b925419c22f69a378ec023eh cnt--; /* only free alloced DMA */
bb5e3b2f129cc39517b925419c22f69a378ec023eh goto fail1;
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh err = ipw2200_dma_region_alloc(sc, &dr[cnt],
bb5e3b2f129cc39517b925419c22f69a378ec023eh MAX_DR_SIZE, DDI_DMA_WRITE,
bb5e3b2f129cc39517b925419c22f69a378ec023eh DDI_DMA_STREAMING);
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (err != DDI_SUCCESS) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh cnt--; /* only free alloced DMA */
bb5e3b2f129cc39517b925419c22f69a378ec023eh goto fail1;
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh off = 0;
bb5e3b2f129cc39517b925419c22f69a378ec023eh src = dr[cnt].dr_pbase;
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh mlen = min(IPW2200_CB_MAXDATALEN, len);
bb5e3b2f129cc39517b925419c22f69a378ec023eh mlen = min(mlen, dr[cnt].dr_size - off);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh (void) memcpy(dr[cnt].dr_base + off, v, mlen);
bb5e3b2f129cc39517b925419c22f69a378ec023eh (void) ddi_dma_sync(dr[cnt].dr_hnd, off, mlen,
bb5e3b2f129cc39517b925419c22f69a378ec023eh DDI_DMA_SYNC_FORDEV);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ctl = IPW2200_CB_DEFAULT_CTL | mlen;
bb5e3b2f129cc39517b925419c22f69a378ec023eh sum = ctl ^ src ^ dst;
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * write a command
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, ctl);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, src);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, dst);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, sum);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh off += mlen;
bb5e3b2f129cc39517b925419c22f69a378ec023eh src += mlen;
bb5e3b2f129cc39517b925419c22f69a378ec023eh dst += mlen;
bb5e3b2f129cc39517b925419c22f69a378ec023eh v += mlen;
bb5e3b2f129cc39517b925419c22f69a378ec023eh len -= mlen;
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh sentinel = ipw2200_csr_get32(sc, IPW2200_CSR_AUTOINC_ADDR);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_AUTOINC_DATA, 0);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_DBG(IPW2200_DBG_FW, (sc->sc_dip, CE_CONT,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_load_fw(): sentinel=%x\n", sentinel));
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_RST,
bb5e3b2f129cc39517b925419c22f69a378ec023eh ~(IPW2200_RST_MASTER_DISABLED | IPW2200_RST_STOP_MASTER)
bb5e3b2f129cc39517b925419c22f69a378ec023eh & ipw2200_csr_get32(sc, IPW2200_CSR_RST));
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put32(sc, 0x3000a4, 0x540100);
bb5e3b2f129cc39517b925419c22f69a378ec023eh for (ntries = 0; ntries < 400; ntries++) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh uint32_t val;
bb5e3b2f129cc39517b925419c22f69a378ec023eh val = ipw2200_imem_get32(sc, 0x3000d0);
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (val >= sentinel)
bb5e3b2f129cc39517b925419c22f69a378ec023eh break;
bb5e3b2f129cc39517b925419c22f69a378ec023eh drv_usecwait(100);
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (ntries == 400) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_WARN((sc->sc_dip, CE_WARN,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_load_fw(): timeout processing command blocks\n"));
bb5e3b2f129cc39517b925419c22f69a378ec023eh goto fail1;
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh mutex_enter(&sc->sc_ilock);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_imem_put32(sc, 0x3000a4, 0x540c00);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * enable all interrupts
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_INTR_MASK, IPW2200_INTR_MASK_ALL);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * tell the adapter to initialize the firmware,
bb5e3b2f129cc39517b925419c22f69a378ec023eh * just simply set it to 0
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_RST, 0);
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_csr_put32(sc, IPW2200_CSR_CTL,
922d2c76afbee21520ffa2088c4e60dcb80d3945eh ipw2200_csr_get32(sc, IPW2200_CSR_CTL) |
922d2c76afbee21520ffa2088c4e60dcb80d3945eh IPW2200_CTL_ALLOW_STANDBY);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * wait for interrupt to notify fw initialization is done
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
bb5e3b2f129cc39517b925419c22f69a378ec023eh sc->sc_fw_ok = 0;
bb5e3b2f129cc39517b925419c22f69a378ec023eh while (!sc->sc_fw_ok) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh /*
bb5e3b2f129cc39517b925419c22f69a378ec023eh * There is an enhancement! we just change from 1s to 5s
bb5e3b2f129cc39517b925419c22f69a378ec023eh */
d3d50737e566cade9a08d73d2af95105ac7cd960Rafael Vanoni if (cv_reltimedwait(&sc->sc_fw_cond, &sc->sc_ilock, clk,
d3d50737e566cade9a08d73d2af95105ac7cd960Rafael Vanoni TR_CLOCK_TICK) < 0)
bb5e3b2f129cc39517b925419c22f69a378ec023eh break;
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh mutex_exit(&sc->sc_ilock);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh if (!sc->sc_fw_ok) {
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_WARN((sc->sc_dip, CE_WARN,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_load_fw(): firmware(%u) load failed!", size));
bb5e3b2f129cc39517b925419c22f69a378ec023eh goto fail1;
bb5e3b2f129cc39517b925419c22f69a378ec023eh }
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh for (i = 0; i <= cnt; i++)
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_dma_region_free(&dr[i]);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (DDI_SUCCESS);
bb5e3b2f129cc39517b925419c22f69a378ec023eh
bb5e3b2f129cc39517b925419c22f69a378ec023ehfail1:
bb5e3b2f129cc39517b925419c22f69a378ec023eh IPW2200_WARN((sc->sc_dip, CE_WARN,
bb5e3b2f129cc39517b925419c22f69a378ec023eh "ipw2200_load_fw(): DMA allocation failed, cnt=%d\n", cnt));
bb5e3b2f129cc39517b925419c22f69a378ec023eh for (i = 0; i <= cnt; i++)
bb5e3b2f129cc39517b925419c22f69a378ec023eh ipw2200_dma_region_free(&dr[i]);
bb5e3b2f129cc39517b925419c22f69a378ec023ehfail0:
bb5e3b2f129cc39517b925419c22f69a378ec023eh return (DDI_FAILURE);
bb5e3b2f129cc39517b925419c22f69a378ec023eh}