/*
* Microsemi Switchtec(tm) PCIe Management Driver
* Copyright (c) 2017, Microsemi Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/switchtec.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/ntb.h>
MODULE_DESCRIPTION("Microsemi Switchtec(tm) NTB Driver");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Microsemi Corporation");
static ulong max_mw_size = SZ_2M;
module_param(max_mw_size, ulong, 0644);
MODULE_PARM_DESC(max_mw_size,
"Max memory window size reported to the upper layer");
static bool use_lut_mws;
module_param(use_lut_mws, bool, 0644);
MODULE_PARM_DESC(use_lut_mws,
"Enable the use of the LUT based memory windows");
#ifndef ioread64
#ifdef readq
#define ioread64 readq
#else
#define ioread64 _ioread64
static inline u64 _ioread64(void __iomem *mmio)
{
u64 low, high;
low = ioread32(mmio);
high = ioread32(mmio + sizeof(u32));
return low | (high << 32);
}
#endif
#endif
#ifndef iowrite64
#ifdef writeq
#define iowrite64 writeq
#else
#define iowrite64 _iowrite64
static inline void _iowrite64(u64 val, void __iomem *mmio)
{
iowrite32(val, mmio);
iowrite32(val >> 32, mmio + sizeof(u32));
}
#endif
#endif
#define SWITCHTEC_NTB_MAGIC 0x45CC0001
#define MAX_MWS 128
struct shared_mw {
u32 magic;
u32 link_sta;
u32 partition_id;
u64 mw_sizes[MAX_MWS];
u32 spad[128];
};
#define MAX_DIRECT_MW ARRAY_SIZE(((struct ntb_ctrl_regs *)(0))->bar_entry)
#define LUT_SIZE SZ_64K
struct switchtec_ntb {
struct ntb_dev ntb;
struct switchtec_dev *stdev;
int self_partition;
int peer_partition;
int doorbell_irq;
int message_irq;
struct ntb_info_regs __iomem *mmio_ntb;
struct ntb_ctrl_regs __iomem *mmio_ctrl;
struct ntb_dbmsg_regs __iomem *mmio_dbmsg;
struct ntb_ctrl_regs __iomem *mmio_self_ctrl;
struct ntb_ctrl_regs __iomem *mmio_peer_ctrl;
struct ntb_dbmsg_regs __iomem *mmio_self_dbmsg;
struct shared_mw *self_shared;
struct shared_mw __iomem *peer_shared;
dma_addr_t self_shared_dma;
u64 db_mask;
u64 db_valid_mask;
int db_shift;
int db_peer_shift;
/* synchronize rmw access of db_mask and hw reg */
spinlock_t db_mask_lock;
int nr_direct_mw;
int nr_lut_mw;
int direct_mw_to_bar[MAX_DIRECT_MW];
int peer_nr_direct_mw;
int peer_nr_lut_mw;
int peer_direct_mw_to_bar[MAX_DIRECT_MW];
bool link_is_up;
enum ntb_speed link_speed;
enum ntb_width link_width;
};
static struct switchtec_ntb *ntb_sndev(struct ntb_dev *ntb)
{
return container_of(ntb, struct switchtec_ntb, ntb);
}
static int switchtec_ntb_part_op(struct switchtec_ntb *sndev,
struct ntb_ctrl_regs __iomem *ctl,
u32 op, int wait_status)
{
static const char * const op_text[] = {
[NTB_CTRL_PART_OP_LOCK] = "lock",
[NTB_CTRL_PART_OP_CFG] = "configure",
[NTB_CTRL_PART_OP_RESET] = "reset",
};
int i;
u32 ps;
int status;
switch (op) {
case NTB_CTRL_PART_OP_LOCK:
status = NTB_CTRL_PART_STATUS_LOCKING;
break;
case NTB_CTRL_PART_OP_CFG:
status = NTB_CTRL_PART_STATUS_CONFIGURING;
break;
case NTB_CTRL_PART_OP_RESET:
status = NTB_CTRL_PART_STATUS_RESETTING;
break;
default:
return -EINVAL;
}
iowrite32(op, &ctl->partition_op);
for (i =