InfiniBand/RDMA changes for the 3.5 merge window:

- Add ocrdma hardware driver for Emulex IB-over-Ethernet adapters
  - Add generic and mlx4 support for "raw" QPs: allow suitably privileged
    applications to send and receive arbitrary packets directly to/from
    the hardware
  - Add "doorbell drop" handling to the cxgb4 driver
  - A fairly large batch of qib hardware driver changes
  - A few fixes for lockdep-detected issues
  - A few other miscellaneous fixes and cleanups
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABCAAGBQJPumbZAAoJEENa44ZhAt0h8LgP/0fXe7Szm3n6P6UvMAVqkagM
 4PpreH3mpWUFpzqeQE1JPDtgx700R6aPipbHqgIN+k61RWMpLjICGcNx7iwxn1I+
 zqdquGygWgjceLz+BLVlk+iBmJt3vZ3fPRAXc7fdP+jhIarWkNIOy1pXWTUuRvED
 jL8jIaxhCcgAVzm/zNyt6IPxkaHvCz7K9wqmpyU0dsO9OyPdGvWA9+CkGXwmOCPq
 mxSVhWnfGsMkPBsL7EgTC5KP/ox2PKq6rFgysmVVS+rKCpP0L8BEVQyGX3Gf8KA8
 yV+KdTi9ofDnFrv6R7Wz0v7HRUih8GRssakzBu7Y7HLfK1M/QwMG0GUAibXGZObc
 vUXuQ3uRJ/cIzMPXqKeGYwpb5t+TmxyjhWu44OjCUQkNau91+9BSbA69S88KXc49
 aTJiCZlhPuGf4uGMWJJuPLcE2xO2QCZj+8ckL2STYrIip6GWlCH02kJaQmRkuWH2
 UhMOeJDBC4nvh4EQT/WwHpGzyhkavE2ayfo5YemxBJXo+P5Mdbf7WIDRQDLUEeQH
 F8sPoccH4hDiAorN/SkTsm14jVTP7oWW1M40Ont59Nhbgm88MsVkvjoneHnfBvbD
 HjK92soCWnYTAoREfj0G4xUxZgMdOZcezWrX0rx5LJ8Ju9y4zAi3cKGr7lg6hs4X
 syKfN0VjiDRtJ+pxayi3
 =yWfr
 -----END PGP SIGNATURE-----

Merge tag 'rdma-for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband

Pull InfiniBand/RDMA changes from Roland Dreier:
 - Add ocrdma hardware driver for Emulex IB-over-Ethernet adapters
 - Add generic and mlx4 support for "raw" QPs: allow suitably privileged
   applications to send and receive arbitrary packets directly to/from
   the hardware
 - Add "doorbell drop" handling to the cxgb4 driver
 - A fairly large batch of qib hardware driver changes
 - A few fixes for lockdep-detected issues
 - A few other miscellaneous fixes and cleanups

Fix up trivial conflict in drivers/net/ethernet/emulex/benet/be.h.

* tag 'rdma-for-3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/roland/infiniband: (53 commits)
  RDMA/cxgb4: Include vmalloc.h for vmalloc and vfree
  IB/mlx4: Fix mlx4_ib_add() error flow
  IB/core: Fix IB_SA_COMP_MASK macro
  IB/iser: Fix error flow in iser ep connection establishment
  IB/mlx4: Increase the number of vectors (EQs) available for ULPs
  RDMA/cxgb4: Add query_qp support
  RDMA/cxgb4: Remove kfifo usage
  RDMA/cxgb4: Use vmalloc() for debugfs QP dump
  RDMA/cxgb4: DB Drop Recovery for RDMA and LLD queues
  RDMA/cxgb4: Disable interrupts in c4iw_ev_dispatch()
  RDMA/cxgb4: Add DB Overflow Avoidance
  RDMA/cxgb4: Add debugfs RDMA memory stats
  cxgb4: DB Drop Recovery for RDMA and LLD queues
  cxgb4: Common platform specific changes for DB Drop Recovery
  cxgb4: Detect DB FULL events and notify RDMA ULD
  RDMA/cxgb4: Drop peer_abort when no endpoint found
  RDMA/cxgb4: Always wake up waiters in c4iw_peer_abort_intr()
  mlx4_core: Change bitmap allocator to work in round-robin fashion
  RDMA/nes: Don't call event handler if pointer is NULL
  RDMA/nes: Fix for the ORD value of the connecting peer
  ...
This commit is contained in:
Linus Torvalds 2012-05-21 17:54:55 -07:00
commit c23ddf7857
80 changed files with 10546 additions and 447 deletions

View file

@ -51,6 +51,8 @@
#define FW_VERSION_MINOR 1
#define FW_VERSION_MICRO 0
#define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__)
enum {
MAX_NPORTS = 4, /* max # of ports */
SERNUM_LEN = 24, /* Serial # length */
@ -64,6 +66,15 @@ enum {
MEM_MC
};
enum {
MEMWIN0_APERTURE = 65536,
MEMWIN0_BASE = 0x30000,
MEMWIN1_APERTURE = 32768,
MEMWIN1_BASE = 0x28000,
MEMWIN2_APERTURE = 2048,
MEMWIN2_BASE = 0x1b800,
};
enum dev_master {
MASTER_CANT,
MASTER_MAY,
@ -403,6 +414,9 @@ struct sge_txq {
struct tx_sw_desc *sdesc; /* address of SW Tx descriptor ring */
struct sge_qstat *stat; /* queue status entry */
dma_addr_t phys_addr; /* physical address of the ring */
spinlock_t db_lock;
int db_disabled;
unsigned short db_pidx;
};
struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */
@ -475,6 +489,7 @@ struct adapter {
void __iomem *regs;
struct pci_dev *pdev;
struct device *pdev_dev;
unsigned int mbox;
unsigned int fn;
unsigned int flags;
@ -504,6 +519,8 @@ struct adapter {
void **tid_release_head;
spinlock_t tid_release_lock;
struct work_struct tid_release_task;
struct work_struct db_full_task;
struct work_struct db_drop_task;
bool tid_release_task_busy;
struct dentry *debugfs_root;
@ -605,6 +622,7 @@ irqreturn_t t4_sge_intr_msix(int irq, void *cookie);
void t4_sge_init(struct adapter *adap);
void t4_sge_start(struct adapter *adap);
void t4_sge_stop(struct adapter *adap);
extern int dbfifo_int_thresh;
#define for_each_port(adapter, iter) \
for (iter = 0; iter < (adapter)->params.nports; ++iter)
@ -719,4 +737,9 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
unsigned int vf, unsigned int eqid);
int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
void t4_db_full(struct adapter *adapter);
void t4_db_dropped(struct adapter *adapter);
int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len);
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
u32 addr, u32 val);
#endif /* __CXGB4_H__ */

View file

@ -148,15 +148,6 @@ static unsigned int pfvfres_pmask(struct adapter *adapter,
}
#endif
enum {
MEMWIN0_APERTURE = 65536,
MEMWIN0_BASE = 0x30000,
MEMWIN1_APERTURE = 32768,
MEMWIN1_BASE = 0x28000,
MEMWIN2_APERTURE = 2048,
MEMWIN2_BASE = 0x1b800,
};
enum {
MAX_TXQ_ENTRIES = 16384,
MAX_CTRL_TXQ_ENTRIES = 1024,
@ -371,6 +362,15 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
uhash | mhash, sleep);
}
int dbfifo_int_thresh = 10; /* 10 == 640 entry threshold */
module_param(dbfifo_int_thresh, int, 0644);
MODULE_PARM_DESC(dbfifo_int_thresh, "doorbell fifo interrupt threshold");
int dbfifo_drain_delay = 1000; /* usecs to sleep while draining the dbfifo */
module_param(dbfifo_drain_delay, int, 0644);
MODULE_PARM_DESC(dbfifo_drain_delay,
"usecs to sleep while draining the dbfifo");
/*
* Set Rx properties of a port, such as promiscruity, address filters, and MTU.
* If @mtu is -1 it is left unchanged.
@ -389,6 +389,8 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
return ret;
}
static struct workqueue_struct *workq;
/**
* link_start - enable a port
* @dev: the port to enable
@ -2196,7 +2198,7 @@ static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
adap->tid_release_head = (void **)((uintptr_t)p | chan);
if (!adap->tid_release_task_busy) {
adap->tid_release_task_busy = true;
schedule_work(&adap->tid_release_task);
queue_work(workq, &adap->tid_release_task);
}
spin_unlock_bh(&adap->tid_release_lock);
}
@ -2366,6 +2368,16 @@ unsigned int cxgb4_port_chan(const struct net_device *dev)
}
EXPORT_SYMBOL(cxgb4_port_chan);
unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo)
{
struct adapter *adap = netdev2adap(dev);
u32 v;
v = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
return lpfifo ? G_LP_COUNT(v) : G_HP_COUNT(v);
}
EXPORT_SYMBOL(cxgb4_dbfifo_count);
/**
* cxgb4_port_viid - get the VI id of a port
* @dev: the net device for the port
@ -2413,6 +2425,59 @@ void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask,
}
EXPORT_SYMBOL(cxgb4_iscsi_init);
int cxgb4_flush_eq_cache(struct net_device *dev)
{
struct adapter *adap = netdev2adap(dev);
int ret;
ret = t4_fwaddrspace_write(adap, adap->mbox,
0xe1000000 + A_SGE_CTXT_CMD, 0x20000000);
return ret;
}
EXPORT_SYMBOL(cxgb4_flush_eq_cache);
static int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx)
{
u32 addr = t4_read_reg(adap, A_SGE_DBQ_CTXT_BADDR) + 24 * qid + 8;
__be64 indices;
int ret;
ret = t4_mem_win_read_len(adap, addr, (__be32 *)&indices, 8);
if (!ret) {
indices = be64_to_cpu(indices);
*cidx = (indices >> 25) & 0xffff;
*pidx = (indices >> 9) & 0xffff;
}
return ret;
}
int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx,
u16 size)
{
struct adapter *adap = netdev2adap(dev);
u16 hw_pidx, hw_cidx;
int ret;
ret = read_eq_indices(adap, qid, &hw_pidx, &hw_cidx);
if (ret)
goto out;
if (pidx != hw_pidx) {
u16 delta;
if (pidx >= hw_pidx)
delta = pidx - hw_pidx;
else
delta = size - hw_pidx + pidx;
wmb();
t4_write_reg(adap, MYPF_REG(A_SGE_PF_KDOORBELL),
V_QID(qid) | V_PIDX(delta));
}
out:
return ret;
}
EXPORT_SYMBOL(cxgb4_sync_txq_pidx);
static struct pci_driver cxgb4_driver;
static void check_neigh_update(struct neighbour *neigh)
@ -2446,6 +2511,144 @@ static struct notifier_block cxgb4_netevent_nb = {
.notifier_call = netevent_cb
};
static void drain_db_fifo(struct adapter *adap, int usecs)
{
u32 v;
do {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(usecs_to_jiffies(usecs));
v = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
if (G_LP_COUNT(v) == 0 && G_HP_COUNT(v) == 0)
break;
} while (1);
}
static void disable_txq_db(struct sge_txq *q)
{
spin_lock_irq(&q->db_lock);
q->db_disabled = 1;
spin_unlock_irq(&q->db_lock);
}
static void enable_txq_db(struct sge_txq *q)
{
spin_lock_irq(&q->db_lock);
q->db_disabled = 0;
spin_unlock_irq(&q->db_lock);
}
static void disable_dbs(struct adapter *adap)
{
int i;
for_each_ethrxq(&adap->sge, i)
disable_txq_db(&adap->sge.ethtxq[i].q);
for_each_ofldrxq(&adap->sge, i)
disable_txq_db(&adap->sge.ofldtxq[i].q);
for_each_port(adap, i)
disable_txq_db(&adap->sge.ctrlq[i].q);
}
static void enable_dbs(struct adapter *adap)
{
int i;
for_each_ethrxq(&adap->sge, i)
enable_txq_db(&adap->sge.ethtxq[i].q);
for_each_ofldrxq(&adap->sge, i)
enable_txq_db(&adap->sge.ofldtxq[i].q);
for_each_port(adap, i)
enable_txq_db(&adap->sge.ctrlq[i].q);
}
static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
{
u16 hw_pidx, hw_cidx;
int ret;
spin_lock_bh(&q->db_lock);
ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx);
if (ret)
goto out;
if (q->db_pidx != hw_pidx) {
u16 delta;
if (q->db_pidx >= hw_pidx)
delta = q->db_pidx - hw_pidx;
else
delta = q->size - hw_pidx + q->db_pidx;
wmb();
t4_write_reg(adap, MYPF_REG(A_SGE_PF_KDOORBELL),
V_QID(q->cntxt_id) | V_PIDX(delta));
}
out:
q->db_disabled = 0;
spin_unlock_bh(&q->db_lock);
if (ret)
CH_WARN(adap, "DB drop recovery failed.\n");
}
static void recover_all_queues(struct adapter *adap)
{
int i;
for_each_ethrxq(&adap->sge, i)
sync_txq_pidx(adap, &adap->sge.ethtxq[i].q);
for_each_ofldrxq(&adap->sge, i)
sync_txq_pidx(adap, &adap->sge.ofldtxq[i].q);
for_each_port(adap, i)
sync_txq_pidx(adap, &adap->sge.ctrlq[i].q);
}
static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
{
mutex_lock(&uld_mutex);
if (adap->uld_handle[CXGB4_ULD_RDMA])
ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA],
cmd);
mutex_unlock(&uld_mutex);
}
static void process_db_full(struct work_struct *work)
{
struct adapter *adap;
adap = container_of(work, struct adapter, db_full_task);
notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
drain_db_fifo(adap, dbfifo_drain_delay);
t4_set_reg_field(adap, A_SGE_INT_ENABLE3,
F_DBFIFO_HP_INT | F_DBFIFO_LP_INT,
F_DBFIFO_HP_INT | F_DBFIFO_LP_INT);
notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
}
static void process_db_drop(struct work_struct *work)
{
struct adapter *adap;
adap = container_of(work, struct adapter, db_drop_task);
t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_DROPPED_DB, 0);
disable_dbs(adap);
notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP);
drain_db_fifo(adap, 1);
recover_all_queues(adap);
enable_dbs(adap);
}
void t4_db_full(struct adapter *adap)
{
t4_set_reg_field(adap, A_SGE_INT_ENABLE3,
F_DBFIFO_HP_INT | F_DBFIFO_LP_INT, 0);
queue_work(workq, &adap->db_full_task);
}
void t4_db_dropped(struct adapter *adap)
{
queue_work(workq, &adap->db_drop_task);
}
static void uld_attach(struct adapter *adap, unsigned int uld)
{
void *handle;
@ -2479,6 +2682,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS);
lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL);
lli.fw_vers = adap->params.fw_vers;
lli.dbfifo_int_thresh = dbfifo_int_thresh;
handle = ulds[uld].add(&lli);
if (IS_ERR(handle)) {
@ -2649,6 +2853,8 @@ static void cxgb_down(struct adapter *adapter)
{
t4_intr_disable(adapter);
cancel_work_sync(&adapter->tid_release_task);
cancel_work_sync(&adapter->db_full_task);
cancel_work_sync(&adapter->db_drop_task);
adapter->tid_release_task_busy = false;
adapter->tid_release_head = NULL;
@ -3593,6 +3799,7 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->pdev = pdev;
adapter->pdev_dev = &pdev->dev;
adapter->mbox = func;
adapter->fn = func;
adapter->msg_enable = dflt_msg_enable;
memset(adapter->chan_map, 0xff, sizeof(adapter->chan_map));
@ -3601,6 +3808,8 @@ static int __devinit init_one(struct pci_dev *pdev,
spin_lock_init(&adapter->tid_release_lock);
INIT_WORK(&adapter->tid_release_task, process_tid_release_list);
INIT_WORK(&adapter->db_full_task, process_db_full);
INIT_WORK(&adapter->db_drop_task, process_db_drop);
err = t4_prep_adapter(adapter);
if (err)
@ -3788,6 +3997,10 @@ static int __init cxgb4_init_module(void)
{
int ret;
workq = create_singlethread_workqueue("cxgb4");
if (!workq)
return -ENOMEM;
/* Debugfs support is optional, just warn if this fails */
cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
if (!cxgb4_debugfs_root)
@ -3803,6 +4016,8 @@ static void __exit cxgb4_cleanup_module(void)
{
pci_unregister_driver(&cxgb4_driver);
debugfs_remove(cxgb4_debugfs_root); /* NULL ok */
flush_workqueue(workq);
destroy_workqueue(workq);
}
module_init(cxgb4_init_module);

View file

@ -163,6 +163,12 @@ enum cxgb4_state {
CXGB4_STATE_DETACH
};
enum cxgb4_control {
CXGB4_CONTROL_DB_FULL,
CXGB4_CONTROL_DB_EMPTY,
CXGB4_CONTROL_DB_DROP,
};
struct pci_dev;
struct l2t_data;
struct net_device;
@ -212,6 +218,7 @@ struct cxgb4_lld_info {
unsigned short ucq_density; /* # of user CQs/page */
void __iomem *gts_reg; /* address of GTS register */
void __iomem *db_reg; /* address of kernel doorbell */
int dbfifo_int_thresh; /* doorbell fifo int threshold */
};
struct cxgb4_uld_info {
@ -220,11 +227,13 @@ struct cxgb4_uld_info {
int (*rx_handler)(void *handle, const __be64 *rsp,
const struct pkt_gl *gl);
int (*state_change)(void *handle, enum cxgb4_state new_state);
int (*control)(void *handle, enum cxgb4_control control, ...);
};
int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p);
int cxgb4_unregister_uld(enum cxgb4_uld type);
int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb);
unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo);
unsigned int cxgb4_port_chan(const struct net_device *dev);
unsigned int cxgb4_port_viid(const struct net_device *dev);
unsigned int cxgb4_port_idx(const struct net_device *dev);
@ -236,4 +245,6 @@ void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask,
const unsigned int *pgsz_order);
struct sk_buff *cxgb4_pktgl_to_skb(const struct pkt_gl *gl,
unsigned int skb_len, unsigned int pull_len);
int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, u16 size);
int cxgb4_flush_eq_cache(struct net_device *dev);
#endif /* !__CXGB4_OFLD_H */

View file

@ -767,8 +767,13 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q,
static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
{
wmb(); /* write descriptors before telling HW */
t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
QID(q->cntxt_id) | PIDX(n));
spin_lock(&q->db_lock);
if (!q->db_disabled) {
t4_write_reg(adap, MYPF_REG(A_SGE_PF_KDOORBELL),
V_QID(q->cntxt_id) | V_PIDX(n));
}
q->db_pidx = q->pidx;
spin_unlock(&q->db_lock);
}
/**
@ -2081,6 +2086,7 @@ static void init_txq(struct adapter *adap, struct sge_txq *q, unsigned int id)
q->stops = q->restarts = 0;
q->stat = (void *)&q->desc[q->size];
q->cntxt_id = id;
spin_lock_init(&q->db_lock);
adap->sge.egr_map[id - adap->sge.egr_start] = q;
}
@ -2415,6 +2421,18 @@ void t4_sge_init(struct adapter *adap)
RXPKTCPLMODE |
(STAT_LEN == 128 ? EGRSTATUSPAGESIZE : 0));
/*
* Set up to drop DOORBELL writes when the DOORBELL FIFO overflows
* and generate an interrupt when this occurs so we can recover.
*/
t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS,
V_HP_INT_THRESH(M_HP_INT_THRESH) |
V_LP_INT_THRESH(M_LP_INT_THRESH),
V_HP_INT_THRESH(dbfifo_int_thresh) |
V_LP_INT_THRESH(dbfifo_int_thresh));
t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_ENABLE_DROP,
F_ENABLE_DROP);
for (i = v = 0; i < 32; i += 4)
v |= (PAGE_SHIFT - 10) << i;
t4_write_reg(adap, SGE_HOST_PAGE_SIZE, v);

View file

@ -868,11 +868,14 @@ int t4_restart_aneg(struct adapter *adap, unsigned int mbox, unsigned int port)
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
typedef void (*int_handler_t)(struct adapter *adap);
struct intr_info {
unsigned int mask; /* bits to check in interrupt status */
const char *msg; /* message to print or NULL */
short stat_idx; /* stat counter to increment or -1 */
unsigned short fatal; /* whether the condition reported is fatal */
int_handler_t int_handler; /* platform-specific int handler */
};
/**
@ -905,6 +908,8 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
} else if (acts->msg && printk_ratelimit())
dev_warn(adapter->pdev_dev, "%s (0x%x)\n", acts->msg,
status & acts->mask);
if (acts->int_handler)
acts->int_handler(adapter);
mask |= acts->mask;
}
status &= mask;
@ -1013,7 +1018,9 @@ static void sge_intr_handler(struct adapter *adapter)
{ ERR_INVALID_CIDX_INC,
"SGE GTS CIDX increment too large", -1, 0 },
{ ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 },
{ ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 },
{ F_DBFIFO_LP_INT, NULL, -1, 0, t4_db_full },
{ F_DBFIFO_HP_INT, NULL, -1, 0, t4_db_full },
{ F_ERR_DROPPED_DB, NULL, -1, 0, t4_db_dropped },
{ ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0,
"SGE IQID > 1023 received CPL for FL", -1, 0 },
{ ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1,
@ -1034,10 +1041,10 @@ static void sge_intr_handler(struct adapter *adapter)
};
v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) |
((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32);
((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32);
if (v) {
dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n",
(unsigned long long)v);
(unsigned long long)v);
t4_write_reg(adapter, SGE_INT_CAUSE1, v);
t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32);
}
@ -1513,6 +1520,7 @@ void t4_intr_enable(struct adapter *adapter)
ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 |
ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO |
ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR |
F_DBFIFO_HP_INT | F_DBFIFO_LP_INT |
EGRESS_SIZE_ERR);
t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK);
t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf);
@ -1986,6 +1994,54 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
(var).retval_len16 = htonl(FW_LEN16(var)); \
} while (0)
int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
u32 addr, u32 val)
{
struct fw_ldst_cmd c;
memset(&c, 0, sizeof(c));
c.op_to_addrspace = htonl(V_FW_CMD_OP(FW_LDST_CMD) | F_FW_CMD_REQUEST |
F_FW_CMD_WRITE |
V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_FIRMWARE));
c.cycles_to_len16 = htonl(FW_LEN16(c));
c.u.addrval.addr = htonl(addr);
c.u.addrval.val = htonl(val);
return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
/*
* t4_mem_win_read_len - read memory through PCIE memory window
* @adap: the adapter
* @addr: address of first byte requested aligned on 32b.
* @data: len bytes to hold the data read
* @len: amount of data to read from window. Must be <=
* MEMWIN0_APERATURE after adjusting for 16B alignment
* requirements of the the memory window.
*
* Read len bytes of data from MC starting at @addr.
*/
int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len)
{
int i;
int off;
/*
* Align on a 16B boundary.
*/
off = addr & 15;
if ((addr & 3) || (len + off) > MEMWIN0_APERTURE)
return -EINVAL;
t4_write_reg(adap, A_PCIE_MEM_ACCESS_OFFSET, addr & ~15);
t4_read_reg(adap, A_PCIE_MEM_ACCESS_OFFSET);
for (i = 0; i < len; i += 4)
*data++ = t4_read_reg(adap, (MEMWIN0_BASE + off + i));
return 0;
}
/**
* t4_mdio_rd - read a PHY register through MDIO
* @adap: the adapter

View file

@ -190,6 +190,59 @@
#define SGE_DEBUG_DATA_LOW 0x10d4
#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4
#define S_LP_INT_THRESH 12
#define V_LP_INT_THRESH(x) ((x) << S_LP_INT_THRESH)
#define S_HP_INT_THRESH 28
#define V_HP_INT_THRESH(x) ((x) << S_HP_INT_THRESH)
#define A_SGE_DBFIFO_STATUS 0x10a4
#define S_ENABLE_DROP 13
#define V_ENABLE_DROP(x) ((x) << S_ENABLE_DROP)
#define F_ENABLE_DROP V_ENABLE_DROP(1U)
#define A_SGE_DOORBELL_CONTROL 0x10a8
#define A_SGE_CTXT_CMD 0x11fc
#define A_SGE_DBQ_CTXT_BADDR 0x1084
#define A_SGE_PF_KDOORBELL 0x0
#define S_QID 15
#define V_QID(x) ((x) << S_QID)
#define S_PIDX 0
#define V_PIDX(x) ((x) << S_PIDX)
#define M_LP_COUNT 0x7ffU
#define S_LP_COUNT 0
#define G_LP_COUNT(x) (((x) >> S_LP_COUNT) & M_LP_COUNT)
#define M_HP_COUNT 0x7ffU
#define S_HP_COUNT 16
#define G_HP_COUNT(x) (((x) >> S_HP_COUNT) & M_HP_COUNT)
#define A_SGE_INT_ENABLE3 0x1040
#define S_DBFIFO_HP_INT 8
#define V_DBFIFO_HP_INT(x) ((x) << S_DBFIFO_HP_INT)
#define F_DBFIFO_HP_INT V_DBFIFO_HP_INT(1U)
#define S_DBFIFO_LP_INT 7
#define V_DBFIFO_LP_INT(x) ((x) << S_DBFIFO_LP_INT)
#define F_DBFIFO_LP_INT V_DBFIFO_LP_INT(1U)
#define S_DROPPED_DB 0
#define V_DROPPED_DB(x) ((x) << S_DROPPED_DB)
#define F_DROPPED_DB V_DROPPED_DB(1U)
#define S_ERR_DROPPED_DB 18
#define V_ERR_DROPPED_DB(x) ((x) << S_ERR_DROPPED_DB)
#define F_ERR_DROPPED_DB V_ERR_DROPPED_DB(1U)
#define A_PCIE_MEM_ACCESS_OFFSET 0x306c
#define M_HP_INT_THRESH 0xfU
#define M_LP_INT_THRESH 0xfU
#define PCIE_PF_CLI 0x44
#define PCIE_INT_CAUSE 0x3004
#define UNXSPLCPLERR 0x20000000U

View file

@ -1620,4 +1620,19 @@ struct fw_hdr {
#define FW_HDR_FW_VER_MINOR_GET(x) (((x) >> 16) & 0xff)
#define FW_HDR_FW_VER_MICRO_GET(x) (((x) >> 8) & 0xff)
#define FW_HDR_FW_VER_BUILD_GET(x) (((x) >> 0) & 0xff)
#define S_FW_CMD_OP 24
#define V_FW_CMD_OP(x) ((x) << S_FW_CMD_OP)
#define S_FW_CMD_REQUEST 23
#define V_FW_CMD_REQUEST(x) ((x) << S_FW_CMD_REQUEST)
#define F_FW_CMD_REQUEST V_FW_CMD_REQUEST(1U)
#define S_FW_CMD_WRITE 21
#define V_FW_CMD_WRITE(x) ((x) << S_FW_CMD_WRITE)
#define F_FW_CMD_WRITE V_FW_CMD_WRITE(1U)
#define S_FW_LDST_CMD_ADDRSPACE 0
#define V_FW_LDST_CMD_ADDRSPACE(x) ((x) << S_FW_LDST_CMD_ADDRSPACE)
#endif /* _T4FW_INTERFACE_H_ */

View file

@ -4,4 +4,4 @@
obj-$(CONFIG_BE2NET) += be2net.o
be2net-y := be_main.o be_cmds.o be_ethtool.o
be2net-y := be_main.o be_cmds.o be_ethtool.o be_roce.o

View file

@ -32,6 +32,7 @@
#include <linux/u64_stats_sync.h>
#include "be_hw.h"
#include "be_roce.h"
#define DRV_VER "4.2.220u"
#define DRV_NAME "be2net"
@ -102,7 +103,8 @@ static inline char *nic_name(struct pci_dev *pdev)
#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */
#define MAX_TX_QS 8
#define MAX_MSIX_VECTORS MAX_RSS_QS
#define MAX_ROCE_EQS 5
#define MAX_MSIX_VECTORS (MAX_RSS_QS + MAX_ROCE_EQS) /* RSS qs + RoCE */
#define BE_TX_BUDGET 256
#define BE_NAPI_WEIGHT 64
#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
@ -405,6 +407,17 @@ struct be_adapter {
u32 tx_fc; /* Tx flow control */
bool stats_cmd_sent;
u8 generation; /* BladeEngine ASIC generation */
u32 if_type;
struct {
u8 __iomem *base; /* Door Bell */
u32 size;
u32 total_size;
u64 io_addr;
} roce_db;
u32 num_msix_roce_vec;
struct ocrdma_dev *ocrdma_dev;
struct list_head entry;
u32 flash_status;
struct completion flash_compl;
@ -441,6 +454,10 @@ struct be_adapter {
#define lancer_chip(adapter) ((adapter->pdev->device == OC_DEVICE_ID3) || \
(adapter->pdev->device == OC_DEVICE_ID4))
#define be_roce_supported(adapter) ((adapter->if_type == SLI_INTF_TYPE_3 || \
adapter->sli_family == SKYHAWK_SLI_FAMILY) && \
(adapter->function_mode & RDMA_ENABLED))
extern const struct ethtool_ops be_ethtool_ops;
#define msix_enabled(adapter) (adapter->num_msix_vec > 0)
@ -597,6 +614,12 @@ static inline bool be_is_wol_excluded(struct be_adapter *adapter)
}
}
static inline bool be_type_2_3(struct be_adapter *adapter)
{
return (adapter->if_type == SLI_INTF_TYPE_2 ||
adapter->if_type == SLI_INTF_TYPE_3) ? true : false;
}
extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
extern void be_link_status_update(struct be_adapter *adapter, u8 link_status);
@ -606,4 +629,16 @@ extern bool be_is_wol_supported(struct be_adapter *adapter);
extern bool be_pause_supported(struct be_adapter *adapter);
extern u32 be_get_fw_log_level(struct be_adapter *adapter);
/*
* internal function to initialize-cleanup roce device.
*/
extern void be_roce_dev_add(struct be_adapter *);
extern void be_roce_dev_remove(struct be_adapter *);
/*
* internal function to open-close roce device during ifup-ifdown.
*/
extern void be_roce_dev_open(struct be_adapter *);
extern void be_roce_dev_close(struct be_adapter *);
#endif /* BE_H */

View file

@ -15,6 +15,7 @@
* Costa Mesa, CA 92626
*/
#include <linux/module.h>
#include "be.h"
#include "be_cmds.h"
@ -2646,3 +2647,41 @@ err:
spin_unlock_bh(&adapter->mcc_lock);
return status;
}
int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
int wrb_payload_size, u16 *cmd_status, u16 *ext_status)
{
struct be_adapter *adapter = netdev_priv(netdev_handle);
struct be_mcc_wrb *wrb;
struct be_cmd_req_hdr *hdr = (struct be_cmd_req_hdr *) wrb_payload;
struct be_cmd_req_hdr *req;
struct be_cmd_resp_hdr *resp;
int status;
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter);
if (!wrb) {
status = -EBUSY;
goto err;
}
req = embedded_payload(wrb);
resp = embedded_payload(wrb);
be_wrb_cmd_hdr_prepare(req, hdr->subsystem,
hdr->opcode, wrb_payload_size, wrb, NULL);
memcpy(req, wrb_payload, wrb_payload_size);
be_dws_cpu_to_le(req, wrb_payload_size);
status = be_mcc_notify_wait(adapter);
if (cmd_status)
*cmd_status = (status & 0xffff);
if (ext_status)
*ext_status = 0;
memcpy(wrb_payload, resp, sizeof(*resp) + resp->response_length);
be_dws_le_to_cpu(wrb_payload, sizeof(*resp) + resp->response_length);
err:
spin_unlock_bh(&adapter->mcc_lock);
return status;
}
EXPORT_SYMBOL(be_roce_mcc_cmd);

View file

@ -1062,6 +1062,7 @@ struct be_cmd_resp_modify_eq_delay {
/* The HW can come up in either of the following multi-channel modes
* based on the skew/IPL.
*/
#define RDMA_ENABLED 0x4
#define FLEX10_MODE 0x400
#define VNIC_MODE 0x20000
#define UMC_ENABLED 0x1000000

View file

@ -100,11 +100,13 @@
#define SLI_INTF_REV_SHIFT 4
#define SLI_INTF_FT_MASK 0x00000001
#define SLI_INTF_TYPE_2 2
#define SLI_INTF_TYPE_3 3
/* SLI family */
#define BE_SLI_FAMILY 0x0
#define LANCER_A0_SLI_FAMILY 0xA
#define SKYHAWK_SLI_FAMILY 0x2
/********* ISR0 Register offset **********/
#define CEV_ISR0_OFFSET 0xC18

View file

@ -2151,10 +2151,17 @@ static uint be_num_rss_want(struct be_adapter *adapter)
static void be_msix_enable(struct be_adapter *adapter)
{
#define BE_MIN_MSIX_VECTORS 1
int i, status, num_vec;
int i, status, num_vec, num_roce_vec = 0;
/* If RSS queues are not used, need a vec for default RX Q */
num_vec = min(be_num_rss_want(adapter), num_online_cpus());
if (be_roce_supported(adapter)) {
num_roce_vec = min_t(u32, MAX_ROCE_MSIX_VECTORS,
(num_online_cpus() + 1));
num_roce_vec = min(num_roce_vec, MAX_ROCE_EQS);
num_vec += num_roce_vec;
num_vec = min(num_vec, MAX_MSIX_VECTORS);
}
num_vec = max(num_vec, BE_MIN_MSIX_VECTORS);
for (i = 0; i < num_vec; i++)
@ -2171,7 +2178,17 @@ static void be_msix_enable(struct be_adapter *adapter)
}
return;
done:
adapter->num_msix_vec = num_vec;
if (be_roce_supported(adapter)) {
if (num_vec > num_roce_vec) {
adapter->num_msix_vec = num_vec - num_roce_vec;
adapter->num_msix_roce_vec =
num_vec - adapter->num_msix_vec;
} else {
adapter->num_msix_vec = num_vec;
adapter->num_msix_roce_vec = 0;
}
} else
adapter->num_msix_vec = num_vec;
return;
}
@ -2283,6 +2300,8 @@ static int be_close(struct net_device *netdev)
struct be_eq_obj *eqo;
int i;
be_roce_dev_close(adapter);
be_async_mcc_disable(adapter);
if (!lancer_chip(adapter))
@ -2391,6 +2410,7 @@ static int be_open(struct net_device *netdev)
if (!status)
be_link_status_update(adapter, link_status);
be_roce_dev_open(adapter);
return 0;
err:
be_close(adapter->netdev);
@ -3232,6 +3252,24 @@ static void be_unmap_pci_bars(struct be_adapter *adapter)
iounmap(adapter->csr);
if (adapter->db)
iounmap(adapter->db);
if (adapter->roce_db.base)
pci_iounmap(adapter->pdev, adapter->roce_db.base);
}
static int lancer_roce_map_pci_bars(struct be_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
u8 __iomem *addr;
addr = pci_iomap(pdev, 2, 0);
if (addr == NULL)
return -ENOMEM;
adapter->roce_db.base = addr;
adapter->roce_db.io_addr = pci_resource_start(pdev, 2);
adapter->roce_db.size = 8192;
adapter->roce_db.total_size = pci_resource_len(pdev, 2);
return 0;
}
static int be_map_pci_bars(struct be_adapter *adapter)
@ -3240,11 +3278,18 @@ static int be_map_pci_bars(struct be_adapter *adapter)
int db_reg;
if (lancer_chip(adapter)) {
addr = ioremap_nocache(pci_resource_start(adapter->pdev, 0),
pci_resource_len(adapter->pdev, 0));
if (addr == NULL)
return -ENOMEM;
adapter->db = addr;
if (be_type_2_3(adapter)) {
addr = ioremap_nocache(
pci_resource_start(adapter->pdev, 0),
pci_resource_len(adapter->pdev, 0));
if (addr == NULL)
return -ENOMEM;
adapter->db = addr;
}
if (adapter->if_type == SLI_INTF_TYPE_3) {
if (lancer_roce_map_pci_bars(adapter))
goto pci_map_err;
}
return 0;
}
@ -3269,14 +3314,19 @@ static int be_map_pci_bars(struct be_adapter *adapter)
if (addr == NULL)
goto pci_map_err;
adapter->db = addr;
if (adapter->sli_family == SKYHAWK_SLI_FAMILY) {
adapter->roce_db.size = 4096;
adapter->roce_db.io_addr =
pci_resource_start(adapter->pdev, db_reg);
adapter->roce_db.total_size =
pci_resource_len(adapter->pdev, db_reg);
}
return 0;
pci_map_err:
be_unmap_pci_bars(adapter);
return -ENOMEM;
}
static void be_ctrl_cleanup(struct be_adapter *adapter)
{
struct be_dma_mem *mem = &adapter->mbox_mem_alloced;
@ -3382,6 +3432,8 @@ static void __devexit be_remove(struct pci_dev *pdev)
if (!adapter)
return;
be_roce_dev_remove(adapter);
unregister_netdev(adapter->netdev);
be_clear(adapter);
@ -3495,17 +3547,27 @@ static int be_dev_type_check(struct be_adapter *adapter)
break;
case BE_DEVICE_ID2:
case OC_DEVICE_ID2:
case OC_DEVICE_ID5:
adapter->generation = BE_GEN3;
break;
case OC_DEVICE_ID3:
case OC_DEVICE_ID4:
pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
adapter->if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
SLI_INTF_IF_TYPE_SHIFT;
if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
SLI_INTF_IF_TYPE_SHIFT;
if (((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) ||
if_type != 0x02) {
!be_type_2_3(adapter)) {
dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
return -EINVAL;
}
adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>
SLI_INTF_FAMILY_SHIFT);
adapter->generation = BE_GEN3;
break;
case OC_DEVICE_ID5:
pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
if ((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) {
dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
return -EINVAL;
}
@ -3774,6 +3836,8 @@ static int __devinit be_probe(struct pci_dev *pdev,
if (status != 0)
goto unsetup;
be_roce_dev_add(adapter);
dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev),
adapter->port_num);

View file

@ -0,0 +1,182 @@
/*
* Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
* linux-drivers@emulex.com
*
* Emulex
* 3333 Susan Street
* Costa Mesa, CA 92626
*/
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include "be.h"
#include "be_cmds.h"
static struct ocrdma_driver *ocrdma_drv;
static LIST_HEAD(be_adapter_list);
static DEFINE_MUTEX(be_adapter_list_lock);
static void _be_roce_dev_add(struct be_adapter *adapter)
{
struct be_dev_info dev_info;
int i, num_vec;
struct pci_dev *pdev = adapter->pdev;
if (!ocrdma_drv)
return;
if (pdev->device == OC_DEVICE_ID5) {
/* only msix is supported on these devices */
if (!msix_enabled(adapter))
return;
/* DPP region address and length */
dev_info.dpp_unmapped_addr = pci_resource_start(pdev, 2);
dev_info.dpp_unmapped_len = pci_resource_len(pdev, 2);
} else {
dev_info.dpp_unmapped_addr = 0;
dev_info.dpp_unmapped_len = 0;
}
dev_info.pdev = adapter->pdev;
if (adapter->sli_family == SKYHAWK_SLI_FAMILY)
dev_info.db = adapter->db;
else
dev_info.db = adapter->roce_db.base;
dev_info.unmapped_db = adapter->roce_db.io_addr;
dev_info.db_page_size = adapter->roce_db.size;
dev_info.db_total_size = adapter->roce_db.total_size;
dev_info.netdev = adapter->netdev;
memcpy(dev_info.mac_addr, adapter->netdev->dev_addr, ETH_ALEN);
dev_info.dev_family = adapter->sli_family;
if (msix_enabled(adapter)) {
/* provide all the vectors, so that EQ creation response
* can decide which one to use.
*/
num_vec = adapter->num_msix_vec + adapter->num_msix_roce_vec;
dev_info.intr_mode = BE_INTERRUPT_MODE_MSIX;
dev_info.msix.num_vectors = min(num_vec, MAX_ROCE_MSIX_VECTORS);
/* provide start index of the vector,
* so in case of linear usage,
* it can use the base as starting point.
*/
dev_info.msix.start_vector = adapter->num_evt_qs;
for (i = 0; i < dev_info.msix.num_vectors; i++) {
dev_info.msix.vector_list[i] =
adapter->msix_entries[i].vector;
}
} else {
dev_info.msix.num_vectors = 0;
dev_info.intr_mode = BE_INTERRUPT_MODE_INTX;
}
adapter->ocrdma_dev = ocrdma_drv->add(&dev_info);
}
void be_roce_dev_add(struct be_adapter *adapter)
{
if (be_roce_supported(adapter)) {
INIT_LIST_HEAD(&adapter->entry);
mutex_lock(&be_adapter_list_lock);
list_add_tail(&adapter->entry, &be_adapter_list);
/* invoke add() routine of roce driver only if
* valid driver registered with add method and add() is not yet
* invoked on a given adapter.
*/
_be_roce_dev_add(adapter);
mutex_unlock(&be_adapter_list_lock);
}
}
void _be_roce_dev_remove(struct be_adapter *adapter)
{
if (ocrdma_drv && ocrdma_drv->remove && adapter->ocrdma_dev)
ocrdma_drv->remove(adapter->ocrdma_dev);
adapter->ocrdma_dev = NULL;
}
void be_roce_dev_remove(struct be_adapter *adapter)
{
if (be_roce_supported(adapter)) {
mutex_lock(&be_adapter_list_lock);
_be_roce_dev_remove(adapter);
list_del(&adapter->entry);
mutex_unlock(&be_adapter_list_lock);
}
}
void _be_roce_dev_open(struct be_adapter *adapter)
{
if (ocrdma_drv && adapter->ocrdma_dev &&
ocrdma_drv->state_change_handler)
ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 0);
}
void be_roce_dev_open(struct be_adapter *adapter)
{
if (be_roce_supported(adapter)) {
mutex_lock(&be_adapter_list_lock);
_be_roce_dev_open(adapter);
mutex_unlock(&be_adapter_list_lock);
}
}
void _be_roce_dev_close(struct be_adapter *adapter)
{
if (ocrdma_drv && adapter->ocrdma_dev &&
ocrdma_drv->state_change_handler)
ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 1);
}
void be_roce_dev_close(struct be_adapter *adapter)
{
if (be_roce_supported(adapter)) {
mutex_lock(&be_adapter_list_lock);
_be_roce_dev_close(adapter);
mutex_unlock(&be_adapter_list_lock);
}
}
int be_roce_register_driver(struct ocrdma_driver *drv)
{
struct be_adapter *dev;
mutex_lock(&be_adapter_list_lock);
if (ocrdma_drv) {
mutex_unlock(&be_adapter_list_lock);
return -EINVAL;
}
ocrdma_drv = drv;
list_for_each_entry(dev, &be_adapter_list, entry) {
struct net_device *netdev;
_be_roce_dev_add(dev);
netdev = dev->netdev;
if (netif_running(netdev) && netif_oper_up(netdev))
_be_roce_dev_open(dev);
}
mutex_unlock(&be_adapter_list_lock);
return 0;
}
EXPORT_SYMBOL(be_roce_register_driver);
void be_roce_unregister_driver(struct ocrdma_driver *drv)
{
struct be_adapter *dev;
mutex_lock(&be_adapter_list_lock);
list_for_each_entry(dev, &be_adapter_list, entry) {
if (dev->ocrdma_dev)
_be_roce_dev_remove(dev);
}
ocrdma_drv = NULL;
mutex_unlock(&be_adapter_list_lock);
}
EXPORT_SYMBOL(be_roce_unregister_driver);

View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
* linux-drivers@emulex.com
*
* Emulex
* 3333 Susan Street
* Costa Mesa, CA 92626
*/
#ifndef BE_ROCE_H
#define BE_ROCE_H
#include <linux/pci.h>
#include <linux/netdevice.h>
struct ocrdma_dev;
enum be_interrupt_mode {
BE_INTERRUPT_MODE_MSIX = 0,
BE_INTERRUPT_MODE_INTX = 1,
BE_INTERRUPT_MODE_MSI = 2,
};
#define MAX_ROCE_MSIX_VECTORS 16
struct be_dev_info {
u8 __iomem *db;
u64 unmapped_db;
u32 db_page_size;
u32 db_total_size;
u64 dpp_unmapped_addr;
u32 dpp_unmapped_len;
struct pci_dev *pdev;
struct net_device *netdev;
u8 mac_addr[ETH_ALEN];
u32 dev_family;
enum be_interrupt_mode intr_mode;
struct {
int num_vectors;
int start_vector;
u32 vector_list[MAX_ROCE_MSIX_VECTORS];
} msix;
};
/* ocrdma driver register's the callback functions with nic driver. */
struct ocrdma_driver {
unsigned char name[32];
struct ocrdma_dev *(*add) (struct be_dev_info *dev_info);
void (*remove) (struct ocrdma_dev *);
void (*state_change_handler) (struct ocrdma_dev *, u32 new_state);
};
enum {
BE_DEV_UP = 0,
BE_DEV_DOWN = 1
};
/* APIs for RoCE driver to register callback handlers,
* which will be invoked when device is added, removed, ifup, ifdown
*/
int be_roce_register_driver(struct ocrdma_driver *drv);
void be_roce_unregister_driver(struct ocrdma_driver *drv);
/* API for RoCE driver to issue mailbox commands */
int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
int wrb_payload_size, u16 *cmd_status, u16 *ext_status);
#endif /* BE_ROCE_H */

View file

@ -124,9 +124,6 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt)
spin_lock(&bitmap->lock);
bitmap_clear(bitmap->table, obj, cnt);
bitmap->last = min(bitmap->last, obj);
bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top)
& bitmap->mask;
bitmap->avail += cnt;
spin_unlock(&bitmap->lock);
}

View file

@ -118,6 +118,20 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
mlx4_dbg(dev, " %s\n", fname[i]);
}
static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
{
static const char * const fname[] = {
[0] = "RSS support",
[1] = "RSS Toeplitz Hash Function support",
[2] = "RSS XOR Hash Function support"
};
int i;
for (i = 0; i < ARRAY_SIZE(fname); ++i)
if (fname[i] && (flags & (1LL << i)))
mlx4_dbg(dev, " %s\n", fname[i]);
}
int mlx4_MOD_STAT_CFG(struct mlx4_dev *dev, struct mlx4_mod_stat_cfg *cfg)
{
struct mlx4_cmd_mailbox *mailbox;
@ -346,6 +360,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_MAX_REQ_QP_OFFSET 0x29
#define QUERY_DEV_CAP_MAX_RES_QP_OFFSET 0x2b
#define QUERY_DEV_CAP_MAX_GSO_OFFSET 0x2d
#define QUERY_DEV_CAP_RSS_OFFSET 0x2e
#define QUERY_DEV_CAP_MAX_RDMA_OFFSET 0x2f
#define QUERY_DEV_CAP_RSZ_SRQ_OFFSET 0x33
#define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35
@ -390,6 +405,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98
#define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0
dev_cap->flags2 = 0;
mailbox = mlx4_alloc_cmd_mailbox(dev);
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
@ -439,6 +455,17 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
else
dev_cap->max_gso_sz = 1 << field;
MLX4_GET(field, outbox, QUERY_DEV_CAP_RSS_OFFSET);
if (field & 0x20)
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_XOR;
if (field & 0x10)
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS_TOP;
field &= 0xf;
if (field) {
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RSS;
dev_cap->max_rss_tbl_sz = 1 << field;
} else
dev_cap->max_rss_tbl_sz = 0;
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_RDMA_OFFSET);
dev_cap->max_rdma_global = 1 << (field & 0x3f);
MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET);
@ -632,8 +659,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->max_rq_desc_sz, dev_cap->max_rq_sg);
mlx4_dbg(dev, "Max GSO size: %d\n", dev_cap->max_gso_sz);
mlx4_dbg(dev, "Max counters: %d\n", dev_cap->max_counters);
mlx4_dbg(dev, "Max RSS Table size: %d\n", dev_cap->max_rss_tbl_sz);
dump_dev_cap_flags(dev, dev_cap->flags);
dump_dev_cap_flags2(dev, dev_cap->flags2);
out:
mlx4_free_cmd_mailbox(dev, mailbox);

View file

@ -79,6 +79,7 @@ struct mlx4_dev_cap {
u64 trans_code[MLX4_MAX_PORTS + 1];
u16 stat_rate_support;
u64 flags;
u64 flags2;
int reserved_uars;
int uar_size;
int min_page_sz;
@ -110,6 +111,7 @@ struct mlx4_dev_cap {
u32 reserved_lkey;
u64 max_icm_sz;
int max_gso_sz;
int max_rss_tbl_sz;
u8 supported_port_types[MLX4_MAX_PORTS + 1];
u8 suggested_type[MLX4_MAX_PORTS + 1];
u8 default_sense[MLX4_MAX_PORTS + 1];

View file

@ -272,10 +272,12 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev->caps.max_msg_sz = dev_cap->max_msg_sz;
dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1);
dev->caps.flags = dev_cap->flags;
dev->caps.flags2 = dev_cap->flags2;
dev->caps.bmme_flags = dev_cap->bmme_flags;
dev->caps.reserved_lkey = dev_cap->reserved_lkey;
dev->caps.stat_rate_support = dev_cap->stat_rate_support;
dev->caps.max_gso_sz = dev_cap->max_gso_sz;
dev->caps.max_rss_tbl_sz = dev_cap->max_rss_tbl_sz;
/* Sense port always allowed on supported devices for ConnectX1 and 2 */
if (dev->pdev->device != 0x1003)