Skip to content

Commit

Permalink
IB/qib: Use request_firmware() to load SD7220 firmware
Browse files Browse the repository at this point in the history
Extract the microcode for the QLogic QLE7220 series IB HCA and use the
kernel microcode request facility to load the microcode.  This
supports Debian Linux's requirements to separate microcode which
doesn't have open source code available from the device driver.

Signed-off-by: Ben Hutchings <[email protected]>
Signed-off-by: Roland Dreier <[email protected]>
  • Loading branch information
bwhacks authored and Roland Dreier committed Jul 8, 2010
1 parent e467e10 commit ecd4b48
Show file tree
Hide file tree
Showing 7 changed files with 600 additions and 1,100 deletions.
2 changes: 1 addition & 1 deletion drivers/infiniband/hw/qib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ib_qib-y := qib_cq.o qib_diag.o qib_dma.o qib_driver.o qib_eeprom.o \
qib_qp.o qib_qsfp.o qib_rc.o qib_ruc.o qib_sdma.o qib_srq.o \
qib_sysfs.o qib_twsi.o qib_tx.o qib_uc.o qib_ud.o \
qib_user_pages.o qib_user_sdma.o qib_verbs_mcast.o qib_iba7220.o \
qib_sd7220.o qib_sd7220_img.o qib_iba7322.o qib_verbs.o
qib_sd7220.o qib_iba7322.o qib_verbs.o

# 6120 has no fallback if no MSI interrupts, others can do INTx
ib_qib-$(CONFIG_PCI_MSI) += qib_iba6120.o
Expand Down
7 changes: 0 additions & 7 deletions drivers/infiniband/hw/qib/qib_7220.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,10 +109,6 @@ struct qib_chippport_specific {
*/
int qib_sd7220_presets(struct qib_devdata *dd);
int qib_sd7220_init(struct qib_devdata *dd);
int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum, u8 *img,
int len, int offset);
int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum, const u8 *img,
int len, int offset);
void qib_sd7220_clr_ibpar(struct qib_devdata *);
/*
* Below used for sdnum parameter, selecting one of the two sections
Expand All @@ -121,9 +117,6 @@ void qib_sd7220_clr_ibpar(struct qib_devdata *);
*/
#define IB_7220_SERDES 2

int qib_sd7220_ib_load(struct qib_devdata *dd);
int qib_sd7220_ib_vfy(struct qib_devdata *dd);

static inline u32 qib_read_kreg32(const struct qib_devdata *dd,
const u16 regno)
{
Expand Down
56 changes: 45 additions & 11 deletions drivers/infiniband/hw/qib/qib_sd7220.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
* Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
* All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
Expand Down Expand Up @@ -37,10 +38,14 @@

#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/firmware.h>

#include "qib.h"
#include "qib_7220.h"

#define SD7220_FW_NAME "qlogic/sd7220.fw"
MODULE_FIRMWARE(SD7220_FW_NAME);

/*
* Same as in qib_iba7220.c, but just the registers needed here.
* Could move whole set to qib_7220.h, but decided better to keep
Expand Down Expand Up @@ -102,6 +107,10 @@ static int qib_internal_presets(struct qib_devdata *dd);
/* Tweak the register (CMUCTRL5) that contains the TRIMSELF controls */
static int qib_sd_trimself(struct qib_devdata *dd, int val);
static int epb_access(struct qib_devdata *dd, int sdnum, int claim);
static int qib_sd7220_ib_load(struct qib_devdata *dd,
const struct firmware *fw);
static int qib_sd7220_ib_vfy(struct qib_devdata *dd,
const struct firmware *fw);

/*
* Below keeps track of whether the "once per power-on" initialization has
Expand All @@ -110,10 +119,13 @@ static int epb_access(struct qib_devdata *dd, int sdnum, int claim);
* state of the reset "pin", is no longer valid. Instead, we check for the
* actual uC code having been loaded.
*/
static int qib_ibsd_ucode_loaded(struct qib_pportdata *ppd)
static int qib_ibsd_ucode_loaded(struct qib_pportdata *ppd,
const struct firmware *fw)
{
struct qib_devdata *dd = ppd->dd;
if (!dd->cspec->serdes_first_init_done && (qib_sd7220_ib_vfy(dd) > 0))

if (!dd->cspec->serdes_first_init_done &&
qib_sd7220_ib_vfy(dd, fw) > 0)
dd->cspec->serdes_first_init_done = 1;
return dd->cspec->serdes_first_init_done;
}
Expand Down Expand Up @@ -377,6 +389,7 @@ static void qib_sd_trimdone_monitor(struct qib_devdata *dd,
*/
int qib_sd7220_init(struct qib_devdata *dd)
{
const struct firmware *fw;
int ret = 1; /* default to failure */
int first_reset, was_reset;

Expand All @@ -387,8 +400,15 @@ int qib_sd7220_init(struct qib_devdata *dd)
qib_ibsd_reset(dd, 1);
qib_sd_trimdone_monitor(dd, "Driver-reload");
}

ret = request_firmware(&fw, SD7220_FW_NAME, &dd->pcidev->dev);
if (ret) {
qib_dev_err(dd, "Failed to load IB SERDES image\n");
goto done;
}

/* Substitute our deduced value for was_reset */
ret = qib_ibsd_ucode_loaded(dd->pport);
ret = qib_ibsd_ucode_loaded(dd->pport, fw);
if (ret < 0)
goto bail;

Expand Down Expand Up @@ -437,13 +457,13 @@ int qib_sd7220_init(struct qib_devdata *dd)
int vfy;
int trim_done;

ret = qib_sd7220_ib_load(dd);
ret = qib_sd7220_ib_load(dd, fw);
if (ret < 0) {
qib_dev_err(dd, "Failed to load IB SERDES image\n");
goto bail;
} else {
/* Loaded image, try to verify */
vfy = qib_sd7220_ib_vfy(dd);
vfy = qib_sd7220_ib_vfy(dd, fw);
if (vfy != ret) {
qib_dev_err(dd, "SERDES PRAM VFY failed\n");
goto bail;
Expand Down Expand Up @@ -506,6 +526,8 @@ int qib_sd7220_init(struct qib_devdata *dd)
done:
/* start relock timer regardless, but start at 1 second */
set_7220_relock_poll(dd, -1);

release_firmware(fw);
return ret;
}

Expand Down Expand Up @@ -829,8 +851,8 @@ static int qib_sd7220_ram_xfer(struct qib_devdata *dd, int sdnum, u32 loc,

#define PROG_CHUNK 64

int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum,
u8 *img, int len, int offset)
static int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum,
const u8 *img, int len, int offset)
{
int cnt, sofar, req;

Expand All @@ -840,7 +862,7 @@ int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum,
if (req > PROG_CHUNK)
req = PROG_CHUNK;
cnt = qib_sd7220_ram_xfer(dd, sdnum, offset + sofar,
img + sofar, req, 0);
(u8 *)img + sofar, req, 0);
if (cnt < req) {
sofar = -1;
break;
Expand All @@ -853,8 +875,8 @@ int qib_sd7220_prog_ld(struct qib_devdata *dd, int sdnum,
#define VFY_CHUNK 64
#define SD_PRAM_ERROR_LIMIT 42

int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum,
const u8 *img, int len, int offset)
static int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum,
const u8 *img, int len, int offset)
{
int cnt, sofar, req, idx, errors;
unsigned char readback[VFY_CHUNK];
Expand All @@ -881,6 +903,18 @@ int qib_sd7220_prog_vfy(struct qib_devdata *dd, int sdnum,
return errors ? -errors : sofar;
}

static int
qib_sd7220_ib_load(struct qib_devdata *dd, const struct firmware *fw)
{
return qib_sd7220_prog_ld(dd, IB_7220_SERDES, fw->data, fw->size, 0);
}

static int
qib_sd7220_ib_vfy(struct qib_devdata *dd, const struct firmware *fw)
{
return qib_sd7220_prog_vfy(dd, IB_7220_SERDES, fw->data, fw->size, 0);
}

/*
* IRQ not set up at this point in init, so we poll.
*/
Expand Down
Loading

0 comments on commit ecd4b48

Please sign in to comment.