Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FPGA Configuration Space
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
FPGA Configuration Space
Commits
3085a159
Commit
3085a159
authored
Jun 08, 2018
by
A. Hahn
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
pcie_wb: added pmc/pci support
parent
99640fa5
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
230 additions
and
108 deletions
+230
-108
pcie_wb.c
pcie-wb/pcie_wb.c
+199
-88
pcie_wb.h
pcie-wb/pcie_wb.h
+31
-20
No files found.
pcie-wb/pcie_wb.c
View file @
3085a159
...
...
@@ -27,7 +27,9 @@
#error "unknown machine byte order (endian)"
#endif
static
unsigned
int
debug
=
0
;
static
unsigned
int
debug
=
0
;
/* module parameter, enable debug prints */
static
unsigned
int
debug_irq
=
0
;
/* module parameter, enable debug prints in irq handler*/
static
unsigned
int
pmcintx
=
0
;
/* module parameter, force INTx interrupt for PCI/PMC card */
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,28)
...
...
@@ -48,8 +50,18 @@ static void compat_pci_clear_master(struct pci_dev *dev)
static
void
pcie_int_enable
(
struct
pcie_wb_dev
*
dev
,
int
on
)
{
int
enable
=
on
&&
!
dev
->
msi
;
iowrite32
((
enable
?
0x20000000UL
:
0
)
+
0x10000000UL
,
dev
->
pci_res
[
0
].
addr
+
CONTROL_REGISTER_HIGH
);
int
enable
;
/* enable/disable interrupts for pmc device */
if
(
dev
->
pci_dev
->
device
==
PMC_WB_DEVICE_ID
){
iowrite32
((
on
?
0x20000000UL
:
0
)
+
0x10000000UL
,
dev
->
pci_res
[
0
].
addr
+
CONTROL_REGISTER_HIGH
);
ioread32
(
dev
->
pci_res
[
0
].
addr
+
CONTROL_REGISTER_HIGH
);
/*dummy read to be sure that write was executed*/
}
/* enable/disable interrupts for pcie device */
else
{
enable
=
on
&&
!
dev
->
msi
;
iowrite32
((
enable
?
0x20000000UL
:
0
)
+
0x10000000UL
,
dev
->
pci_res
[
0
].
addr
+
CONTROL_REGISTER_HIGH
);
}
}
static
void
wb_cycle
(
struct
wishbone
*
wb
,
int
on
)
...
...
@@ -133,15 +145,15 @@ static void wb_write(struct wishbone* wb, wb_addr_t addr, wb_data_t data)
switch
(
dev
->
width
)
{
case
4
:
if
(
unlikely
(
debug
))
printk
(
KERN_
ALERT
PCIE_WB
": iowrite32(0x%x, 0x%x)
\n
"
,
data
,
addr
&
~
3
);
if
(
unlikely
(
debug
))
printk
(
KERN_
DEBUG
PCIE_WB
": iowrite32 A:0x%08x, D:0x%08x
\n
"
,
addr
&
~
3
,
data
);
iowrite32
(
data
,
window
+
(
addr
&
WINDOW_LOW
));
break
;
case
2
:
if
(
unlikely
(
debug
))
printk
(
KERN_
ALERT
PCIE_WB
": iowrite16(0x%x, 0x%x)
\n
"
,
data
>>
dev
->
shift
,
(
addr
&
~
3
)
+
dev
->
low_addr
);
if
(
unlikely
(
debug
))
printk
(
KERN_
DEBUG
PCIE_WB
": iowrite16 A:0x%08x, D:0x%08x
\n
"
,
(
addr
&
~
3
)
+
dev
->
low_addr
,
data
>>
dev
->
shift
);
iowrite16
(
data
>>
dev
->
shift
,
window
+
(
addr
&
WINDOW_LOW
)
+
dev
->
low_addr
);
break
;
case
1
:
if
(
unlikely
(
debug
))
printk
(
KERN_
ALERT
PCIE_WB
": iowrite8(0x%x, 0x%x)
\n
"
,
data
>>
dev
->
shift
,
(
addr
&
~
3
)
+
dev
->
low_addr
);
if
(
unlikely
(
debug
))
printk
(
KERN_
DEBUG
PCIE_WB
": iowrite8 A:0x%08x, D:0x%08x
\n
"
,
(
addr
&
~
3
)
+
dev
->
low_addr
,
data
>>
dev
->
shift
);
iowrite8
(
data
>>
dev
->
shift
,
window
+
(
addr
&
WINDOW_LOW
)
+
dev
->
low_addr
);
break
;
}
...
...
@@ -261,8 +273,22 @@ static const struct wishbone_operations wb_ops = {
static
irqreturn_t
irq_handler
(
int
irq
,
void
*
dev_id
)
{
struct
pcie_wb_dev
*
dev
=
dev_id
;
unsigned
char
*
wb_conf
;
uint32_t
wb_cfg_data
;
/* if card is PMC with IntX interrupts */
/* it is likely that irq line is shared */
if
(
!
(
dev
->
msi
)
&&
(
dev
->
pci_dev
->
device
==
PMC_WB_DEVICE_ID
)){
/* check that pmc card has requested IRQ */
/* if it has not then exit */
wb_conf
=
dev
->
pci_res
[
2
].
addr
;
wb_cfg_data
=
ioread32
(
wb_conf
+
WB_CONF_ISR_REG
);
if
(
!
(
wb_cfg_data
&
WB_CONF_IRQ_STATUS_MASK
)){
return
IRQ_NONE
;
}
}
pcie_int_enable
(
dev
,
0
);
pcie_int_enable
(
dev
,
0
);
/* disable IRQ on Etherbone layer - Etherbone */
wishbone_slave_ready
(
&
dev
->
wb
);
return
IRQ_HANDLED
;
...
...
@@ -275,7 +301,7 @@ static int setup_bar(struct pci_dev* pdev, struct pcie_wb_resource* res, int bar
res
->
size
=
res
->
end
-
res
->
start
+
1
;
if
(
debug
)
printk
(
KERN_
ALERT
PCIE_WB
"/BAR%d 0x%lx - 0x%lx
\n
"
,
bar
,
res
->
start
,
res
->
end
);
printk
(
KERN_
INFO
PCIE_WB
"/BAR%d 0x%lx - 0x%lx
\n
"
,
bar
,
res
->
start
,
res
->
end
);
if
((
pci_resource_flags
(
pdev
,
0
)
&
IORESOURCE_MEM
)
==
0
)
{
printk
(
KERN_ALERT
PCIE_WB
"/BAR%d is not a memory resource
\n
"
,
bar
);
...
...
@@ -311,12 +337,21 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
* reading IRQ
* register char dev
*/
u8
revision
;
struct
pcie_wb_dev
*
dev
;
unsigned
char
*
control
;
unsigned
char
*
wb_conf
;
if
(
unlikely
(
debug
)){
printk
(
KERN_INFO
PCIE_WB
":-----------------------------
\n
"
);
printk
(
KERN_INFO
PCIE_WB
": PCI Device info
\n
"
);
printk
(
KERN_INFO
PCIE_WB
": vendor : %04x
\n
"
,
pdev
->
vendor
);
printk
(
KERN_INFO
PCIE_WB
": device : %04x
\n
"
,
pdev
->
device
);
printk
(
KERN_INFO
PCIE_WB
": PCIe capable : %04x
\n
"
,
pdev
->
pcie_cap
);
printk
(
KERN_INFO
PCIE_WB
": irq number : %d
\n
"
,
pdev
->
irq
);
printk
(
KERN_INFO
PCIE_WB
":-----------------------------
\n
"
);
}
pci_read_config_byte
(
pdev
,
PCI_REVISION_ID
,
&
revision
);
if
(
revision
!=
0x01
)
{
if
(
pdev
->
revision
!=
0x01
)
{
printk
(
KERN_ALERT
PCIE_WB
": revision ID wrong!
\n
"
);
goto
fail_out
;
}
...
...
@@ -342,29 +377,80 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev
->
low_addr
=
0
;
dev
->
width
=
4
;
dev
->
shift
=
0
;
pci_set_drvdata
(
pdev
,
dev
);
/* check which device is being installed: PMC or PCIe and setup bars accordingly */
if
(
pdev
->
device
==
PMC_WB_DEVICE_ID
)
{
printk
(
KERN_INFO
PCIE_WB
": Requesting BARs for PMC Device : %04x:%04x
\n
"
,
pdev
->
vendor
,
pdev
->
device
);
/* BAR1 - etherbone configuration space */
if
(
setup_bar
(
pdev
,
&
dev
->
pci_res
[
0
],
1
)
<
0
)
goto
fail_free
;
/* BAR2 - wishbone */
if
(
setup_bar
(
pdev
,
&
dev
->
pci_res
[
1
],
2
)
<
0
)
goto
fail_bar0
;
/* BAR0 - PCI/WB bridge configuration space */
if
(
setup_bar
(
pdev
,
&
dev
->
pci_res
[
2
],
0
)
<
0
)
goto
fail_bar1
;
}
else
{
printk
(
KERN_INFO
PCIE_WB
": Requesting BARs for PCIe Device : %04x:%04x
\n
"
,
pdev
->
vendor
,
pdev
->
device
);
/* BAR0 - etherbone configuration space */
if
(
setup_bar
(
pdev
,
&
dev
->
pci_res
[
0
],
0
)
<
0
)
goto
fail_free
;
/* BAR1 - wishbone */
if
(
setup_bar
(
pdev
,
&
dev
->
pci_res
[
1
],
1
)
<
0
)
goto
fail_bar0
;
}
/* Initialize device registers */
control
=
dev
->
pci_res
[
0
].
addr
;
iowrite32
(
0
,
control
+
WINDOW_OFFSET_LOW
);
iowrite32
(
0
,
control
+
CONTROL_REGISTER_HIGH
);
/* Configure interrupts*/
/* configure if device is PCIe and wants MSI */
if
(
pdev
->
device
!=
PMC_WB_DEVICE_ID
){
if
(
pdev
->
pcie_cap
&&
dev
->
msi
){
pci_set_master
(
pdev
);
/* enable bus mastering => needed for MSI */
/* enable message signaled interrupts */
if
(
pci_enable_msi
(
pdev
)
!=
0
)
{
/* resort to legacy interrupts
*/
printk
(
KERN_ALERT
PCIE_WB
": c
ould not enable MSI interrupting (using legacy)
\n
"
);
/* resort to legacy interrupts if MSI enable failed
*/
printk
(
KERN_ALERT
PCIE_WB
": C
ould not enable MSI interrupting (using legacy)
\n
"
);
dev
->
msi
=
0
;
pci_clear_master
(
pdev
);
pci_intx
(
pdev
,
1
);
/* enable legacy INTx interrupts for PCIe device*/
printk
(
KERN_INFO
PCIE_WB
": Enabled legacy interrupts for PCIe Device : %04x:%04x
\n
"
,
pdev
->
vendor
,
pdev
->
device
);
}
if
(
dev
->
msi
)
{
else
{
/* disable legacy interrupts when using MSI */
printk
(
KERN_INFO
PCIE_WB
": Enabled MSI, disabling INTx interrupts for PCIe Device : %04x:%04x
\n
"
,
pdev
->
vendor
,
pdev
->
device
);
pci_intx
(
pdev
,
0
);
}
}
}
else
{
/* configure interrupts for pmc device */
wb_conf
=
dev
->
pci_res
[
2
].
addr
;
/* Enable INTx interrupts on PMC device */
if
(
pmcintx
){
iowrite32
(
1
,
wb_conf
+
WB_CONF_ICR_REG
);
/* enable wishbone interrupts to the PCI core */
iowrite32
(
0x10
,
control
+
PMC_IRQ_CONTROL
);
/* enable INTx interrupts to wishbone */
dev
->
msi
=
0
;
pci_intx
(
pdev
,
1
);
/* enable INTx interrupts on PMC device */
printk
(
KERN_INFO
PCIE_WB
": Enabled INTx interrupts for PMC Device : %04x:%04x
\n
"
,
pdev
->
vendor
,
pdev
->
device
);
}
else
{
/* enable MSI */
pci_set_master
(
pdev
);
/* enable bus mastering => needed for MSI */
/* enable message signaled interrupts */
if
(
pci_enable_msi
(
pdev
)
!=
0
)
{
printk
(
KERN_ALERT
PCIE_WB
": Could not enable MSI interrupting on PMC device
\n
"
);
dev
->
msi
=
0
;
pci_clear_master
(
pdev
);
}
else
{
iowrite32
(
0x1
,
control
+
PMC_IRQ_CONTROL
);
/* enable MSI interrupts to wishbone */
}
}
}
if
(
wishbone_register
(
&
dev
->
wb
)
<
0
)
{
printk
(
KERN_ALERT
PCIE_WB
": could not register wishbone bus
\n
"
);
...
...
@@ -376,7 +462,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto
fail_reg
;
}
/* Enable
classic interrupts
*/
/* Enable
interrupts from wishbone
*/
pcie_int_enable
(
dev
,
1
);
return
0
;
...
...
@@ -385,12 +471,12 @@ fail_reg:
wishbone_unregister
(
&
dev
->
wb
);
fail_msi:
if
(
dev
->
msi
)
{
pci_intx
(
pdev
,
1
);
pci_intx
(
pdev
,
0
);
pci_disable_msi
(
pdev
);
}
/*fail_master:*/
pci_clear_master
(
pdev
);
/*fail_bar1:*/
fail_bar1:
destroy_bar
(
&
dev
->
pci_res
[
1
]);
fail_bar0:
destroy_bar
(
&
dev
->
pci_res
[
0
]);
...
...
@@ -406,24 +492,42 @@ static void remove(struct pci_dev *pdev)
{
struct
pcie_wb_dev
*
dev
;
dev
=
pci_get_drvdata
(
pdev
);
if
(
unlikely
(
debug
)){
printk
(
KERN_INFO
PCIE_WB
":-------------------------
\n
"
);
printk
(
KERN_INFO
PCIE_WB
": Removing PCI Device :
\n
"
);
printk
(
KERN_INFO
PCIE_WB
": vendor : %04x
\n
"
,
pdev
->
vendor
);
printk
(
KERN_INFO
PCIE_WB
": device : %04x
\n
"
,
pdev
->
device
);
printk
(
KERN_INFO
PCIE_WB
": PCIe capable : %04x
\n
"
,
pdev
->
pcie_cap
);
printk
(
KERN_INFO
PCIE_WB
": irq number : %d
\n
"
,
pdev
->
irq
);
printk
(
KERN_INFO
PCIE_WB
":-------------------------
\n
"
);
}
dev
=
pci_get_drvdata
(
pdev
);
/* disable/remove interrupts*/
pcie_int_enable
(
dev
,
0
);
free_irq
(
dev
->
pci_dev
->
irq
,
dev
);
wishbone_unregister
(
&
dev
->
wb
);
if
(
dev
->
msi
)
{
pci_intx
(
pdev
,
1
);
if
(
dev
->
msi
){
pci_disable_msi
(
pdev
);
}
pci_clear_master
(
pdev
);
}
else
{
pci_intx
(
pdev
,
0
);
}
if
(
pdev
->
device
==
PMC_WB_DEVICE_ID
){
destroy_bar
(
&
dev
->
pci_res
[
2
]);
}
destroy_bar
(
&
dev
->
pci_res
[
1
]);
destroy_bar
(
&
dev
->
pci_res
[
0
]);
kfree
(
dev
);
printk
(
KERN_INFO
PCIE_WB
": Removed Device %04x:%04x
\n
"
,
pdev
->
vendor
,
pdev
->
device
);
pci_disable_device
(
pdev
);
}
static
struct
pci_device_id
ids
[]
=
{
{
PCI_DEVICE
(
PCIE_WB_VENDOR_ID
,
PCIE_WB_DEVICE_ID
),
},
{
PCI_DEVICE
(
PCIE_WB_VENDOR_ID
,
PMC_WB_DEVICE_ID
),
},
{
0
,
}
};
MODULE_DEVICE_TABLE
(
pci
,
ids
);
...
...
@@ -445,10 +549,17 @@ static void __exit pcie_wb_exit(void)
pci_unregister_driver
(
&
pcie_wb_driver
);
}
MODULE_AUTHOR
(
"Stefan Rauch <s.rauch@gsi.de>"
);
MODULE_AUTHOR
(
"Stefan Rauch <s.rauch@gsi.de>
Dusan Slavinec <dusan.slavinec@cosylab.com>
"
);
MODULE_DESCRIPTION
(
"GSI Altera-Wishbone bridge driver"
);
module_param
(
debug
,
int
,
0644
);
MODULE_PARM_DESC
(
debug
,
"Enable debugging information"
);
module_param
(
debug_irq
,
int
,
0644
);
MODULE_PARM_DESC
(
debug_irq
,
"Enable debugging information in interrupt handler"
);
module_param
(
pmcintx
,
int
,
0644
);
MODULE_PARM_DESC
(
pmcintx
,
"Force INTx interrupt for PMC card"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
PCIE_WB_VERSION
);
...
...
pcie-wb/pcie_wb.h
View file @
3085a159
...
...
@@ -7,7 +7,8 @@
#define PCIE_WB_VERSION "0.1"
#define PCIE_WB_VENDOR_ID 0x10dc
#define PCIE_WB_DEVICE_ID 0x019a
#define PCIE_WB_DEVICE_ID 0x019a
/* PCIe FTRNs (PEXARIA, EXPLODER, AMC, SCU, ...) */
#define PMC_WB_DEVICE_ID 0xc570
/* PCI FTRN (PMC) */
#define CONTROL_REGISTER_HIGH 0
#define CONTROL_REGISTER_LOW 4
...
...
@@ -17,6 +18,7 @@
#define WINDOW_OFFSET_LOW 20
#define SDWB_ADDRESS_HIGH 24
#define SDWB_ADDRESS_LOW 28
#define PMC_IRQ_CONTROL 32
#define MASTER_CTL_HIGH 64
#define MASTER_CTL_LOW 68
...
...
@@ -28,6 +30,15 @@
#define WINDOW_HIGH 0xFFFF0000UL
#define WINDOW_LOW 0x0000FFFCUL
/* PCI core control and status registers in BAR0 */
#define PCI_STATUS_REG 0x04
#define PCI_CONF_IRQ 0x3C
#define WB_CONF_IRQ_STATUS_MASK 0x00000001
#define WB_CONF_INT_ACK_REG 0x1E8
/* PCI core WB interrupt Acknowledge register */
#define WB_CONF_ICR_REG 0x1EC
/* PCI core WB interrupt Control register */
#define WB_CONF_ISR_REG 0x1F0
/* PCI core WB interrupt Status register */
/* One per BAR */
struct
pcie_wb_resource
{
unsigned
long
start
;
/* start addr of BAR */
...
...
@@ -39,7 +50,7 @@ struct pcie_wb_resource {
/* One per physical card */
struct
pcie_wb_dev
{
struct
pci_dev
*
pci_dev
;
struct
pcie_wb_resource
pci_res
[
2
];
struct
pcie_wb_resource
pci_res
[
3
];
int
msi
;
struct
wishbone
wb
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment