Commit 7019dabd authored by Wesley W. Terpstra's avatar Wesley W. Terpstra

wishbone: support config-space-based MSI claiming

parent ce4f5155
...@@ -345,6 +345,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -345,6 +345,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->msi = 1; dev->msi = 1;
dev->wb.wops = &wb_ops; dev->wb.wops = &wb_ops;
dev->wb.parent = &pdev->dev; dev->wb.parent = &pdev->dev;
dev->wb.mask = 0xffff;
mutex_init(&dev->mutex); mutex_init(&dev->mutex);
dev->window_offset = 0; dev->window_offset = 0;
dev->low_addr = 0; dev->low_addr = 0;
......
...@@ -268,6 +268,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -268,6 +268,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev->pci_dev = pdev; dev->pci_dev = pdev;
dev->wb.wops = &wb_ops; dev->wb.wops = &wb_ops;
dev->wb.parent = &pdev->dev; dev->wb.parent = &pdev->dev;
dev->wb.mask = 0; // not MSI capable
dev->msi = 1; dev->msi = 1;
mutex_init(&dev->mutex); mutex_init(&dev->mutex);
dev->window_offset = 0; dev->window_offset = 0;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "wishbone.h" #include "wishbone.h"
/* Module parameters */ /* Module parameters */
static unsigned int max_devices = WISHONE_MAX_DEVICES; static unsigned int max_devices = WISHBONE_MAX_DEVICES;
/* Module globals */ /* Module globals */
static LIST_HEAD(wishbone_list); /* Sorted by ascending minor number */ static LIST_HEAD(wishbone_list); /* Sorted by ascending minor number */
...@@ -109,6 +109,49 @@ static inline void eb_from_cpu(unsigned char* x, wb_data_t dat) ...@@ -109,6 +109,49 @@ static inline void eb_from_cpu(unsigned char* x, wb_data_t dat)
} }
} }
static void claim_msi(struct etherbone_master_context* context)
{
unsigned i;
struct wishbone *wb = context->wishbone;
if (context->msi_index != -1) return;
mutex_lock(&wb->mutex);
for (i = 0; i < WISHBONE_MAX_MSI_OPEN; ++i) {
if (!wb->msi_map[i]) {
context->msi_index = i;
wb->msi_map[i] = context;
break;
}
}
mutex_unlock(&wb->mutex);
}
static wb_data_t handle_read_cfg(struct etherbone_master_context* context, wb_addr_t addr)
{
struct wishbone *wb = context->wishbone;
wb_data_t wide = (wb->mask/WISHBONE_MAX_MSI_OPEN)+1;
switch (addr) {
case 32: return 0; // request high
case 36: return 0; // request low
case 40: return 0; // granted high
case 44: return context->msi_index != -1; // granted low
case 48: return 0; // low high
case 52: return wide*(context->msi_index+0)-0; // low low
case 56: return 0; // high high
case 60: return wide*(context->msi_index+1)-1; // high low
default: return wb->wops->read_cfg(wb, addr);
}
}
static void handle_write_cfg(struct etherbone_master_context* context, wb_addr_t addr, wb_data_t data)
{
switch (addr) {
case 36: if (data == 1) claim_msi(context); break;
default: break;
}
}
static void etherbone_master_process(struct etherbone_master_context* context) static void etherbone_master_process(struct etherbone_master_context* context)
{ {
struct wishbone *wb; struct wishbone *wb;
...@@ -176,6 +219,7 @@ static void etherbone_master_process(struct etherbone_master_context* context) ...@@ -176,6 +219,7 @@ static void etherbone_master_process(struct etherbone_master_context* context)
if (wca) { if (wca) {
for (j = wcount; j > 0; --j) { for (j = wcount; j > 0; --j) {
handle_write_cfg(context, base_address, eb_to_cpu(buf+i));
eb_from_cpu(buf+i, 0); eb_from_cpu(buf+i, 0);
i = RING_INDEX(i + sizeof(wb_data_t)); i = RING_INDEX(i + sizeof(wb_data_t));
} }
...@@ -205,7 +249,7 @@ static void etherbone_master_process(struct etherbone_master_context* context) ...@@ -205,7 +249,7 @@ static void etherbone_master_process(struct etherbone_master_context* context)
if (rca) { if (rca) {
for (j = rcount; j > 0; --j) { for (j = rcount; j > 0; --j) {
eb_from_cpu(buf+i, wops->read_cfg(wb, eb_to_cpu(buf+i))); eb_from_cpu(buf+i, handle_read_cfg(context, eb_to_cpu(buf+i)));
i = RING_INDEX(i + sizeof(wb_data_t)); i = RING_INDEX(i + sizeof(wb_data_t));
} }
} else { } else {
...@@ -242,6 +286,8 @@ static int char_master_open(struct inode *inode, struct file *filep) ...@@ -242,6 +286,8 @@ static int char_master_open(struct inode *inode, struct file *filep)
context->sent = 0; context->sent = 0;
context->processed = 0; context->processed = 0;
context->received = 0; context->received = 0;
context->msi_unread = 0;
context->msi_index = -1;
filep->private_data = context; filep->private_data = context;
...@@ -251,10 +297,18 @@ static int char_master_open(struct inode *inode, struct file *filep) ...@@ -251,10 +297,18 @@ static int char_master_open(struct inode *inode, struct file *filep)
static int char_master_release(struct inode *inode, struct file *filep) static int char_master_release(struct inode *inode, struct file *filep)
{ {
struct etherbone_master_context *context = filep->private_data; struct etherbone_master_context *context = filep->private_data;
struct wishbone *wb = context->wishbone;
/* Did the bad user forget to drop the cycle line? */ /* Did the bad user forget to drop the cycle line? */
if (context->state == cycle) { if (context->state == cycle) {
context->wishbone->wops->cycle(context->wishbone, 0); wb->wops->cycle(wb, 0);
}
/* Unhook any MSI access */
if (context->msi_index != -1) {
mutex_lock(&wb->mutex);
wb->msi_map[context->msi_index] = 0;
mutex_unlock(&wb->mutex);
} }
kfree(context); kfree(context);
...@@ -381,9 +435,13 @@ static const struct file_operations etherbone_master_fops = { ...@@ -381,9 +435,13 @@ static const struct file_operations etherbone_master_fops = {
int wishbone_register(struct wishbone* wb) int wishbone_register(struct wishbone* wb)
{ {
struct list_head *list_pos; struct list_head *list_pos;
unsigned int devoff; unsigned int devoff, i;
INIT_LIST_HEAD(&wb->list); INIT_LIST_HEAD(&wb->list);
mutex_init(&wb->mutex);
for (i = 0; i < WISHBONE_MAX_MSI_OPEN; ++i) {
wb->msi_map[i] = 0;
}
mutex_lock(&wishbone_mutex); mutex_lock(&wishbone_mutex);
......
...@@ -6,7 +6,8 @@ ...@@ -6,7 +6,8 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#define WISHBONE_VERSION "0.1" #define WISHBONE_VERSION "0.1"
#define WISHONE_MAX_DEVICES 32 /* default only */ #define WISHBONE_MAX_DEVICES 32 /* default only */
#define WISHBONE_MAX_MSI_OPEN 16 /* fixed */
#define ETHERBONE_BCA 0x80 #define ETHERBONE_BCA 0x80
#define ETHERBONE_RCA 0x40 #define ETHERBONE_RCA 0x40
...@@ -55,12 +56,17 @@ struct wishbone ...@@ -55,12 +56,17 @@ struct wishbone
{ {
const struct wishbone_operations* wops; const struct wishbone_operations* wops;
struct device *parent; struct device *parent;
wb_addr_t mask;
/* internal (guarded by global mutex--register/unregister): */ /* internal (guarded by global mutex--register/unregister): */
struct list_head list; struct list_head list;
dev_t master_dev; dev_t master_dev;
struct cdev master_cdev; struct cdev master_cdev;
struct device *master_device; struct device *master_device;
/* internal (EB-MSI mapping for this hardware) */
struct mutex mutex;
struct etherbone_master_context *msi_map[WISHBONE_MAX_MSI_OPEN];
}; };
#define RING_SIZE 8192 #define RING_SIZE 8192
...@@ -79,6 +85,11 @@ struct etherbone_master_context ...@@ -79,6 +85,11 @@ struct etherbone_master_context
unsigned int sent, processed, received; /* sent <= processed <= received */ unsigned int sent, processed, received; /* sent <= processed <= received */
unsigned char buf[RING_SIZE]; /* Ring buffer */ unsigned char buf[RING_SIZE]; /* Ring buffer */
/* MSI record data */
unsigned char msi[sizeof(wb_data_t)*6];
int msi_unread;
int msi_index;
}; };
#define RING_READ_LEN(ctx) RING_POS((ctx)->processed - (ctx)->sent) #define RING_READ_LEN(ctx) RING_POS((ctx)->processed - (ctx)->sent)
......
...@@ -453,6 +453,7 @@ static int vme_probe(struct device *pdev, unsigned int ndev) ...@@ -453,6 +453,7 @@ static int vme_probe(struct device *pdev, unsigned int ndev)
mutex_init(&dev->mutex); mutex_init(&dev->mutex);
dev->wb.wops = &wb_ops; dev->wb.wops = &wb_ops;
dev->wb.parent = pdev; dev->wb.parent = pdev;
dev->wb.mask = 0xffff;
dev->window_offset = 0; dev->window_offset = 0;
/* Map CR/CSR space */ /* Map CR/CSR space */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment