Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
ce65fb43
Commit
ce65fb43
authored
May 06, 2003
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/gregkh/linux/i2c-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
b0f79d02
59f73759
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
357 additions
and
99 deletions
+357
-99
drivers/acpi/acpi_ksyms.c
drivers/acpi/acpi_ksyms.c
+1
-0
drivers/hotplug/Kconfig
drivers/hotplug/Kconfig
+1
-1
drivers/hotplug/acpiphp_glue.c
drivers/hotplug/acpiphp_glue.c
+5
-1
drivers/hotplug/cpqphp.h
drivers/hotplug/cpqphp.h
+197
-10
drivers/hotplug/cpqphp_core.c
drivers/hotplug/cpqphp_core.c
+53
-4
drivers/hotplug/cpqphp_ctrl.c
drivers/hotplug/cpqphp_ctrl.c
+81
-67
drivers/hotplug/cpqphp_pci.c
drivers/hotplug/cpqphp_pci.c
+11
-10
drivers/hotplug/ibmphp_core.c
drivers/hotplug/ibmphp_core.c
+8
-6
No files found.
drivers/acpi/acpi_ksyms.c
View file @
ce65fb43
...
@@ -80,6 +80,7 @@ EXPORT_SYMBOL(acpi_get_current_resources);
...
@@ -80,6 +80,7 @@ EXPORT_SYMBOL(acpi_get_current_resources);
EXPORT_SYMBOL
(
acpi_get_possible_resources
);
EXPORT_SYMBOL
(
acpi_get_possible_resources
);
EXPORT_SYMBOL
(
acpi_walk_resources
);
EXPORT_SYMBOL
(
acpi_walk_resources
);
EXPORT_SYMBOL
(
acpi_set_current_resources
);
EXPORT_SYMBOL
(
acpi_set_current_resources
);
EXPORT_SYMBOL
(
acpi_resource_to_address64
);
EXPORT_SYMBOL
(
acpi_enable_event
);
EXPORT_SYMBOL
(
acpi_enable_event
);
EXPORT_SYMBOL
(
acpi_disable_event
);
EXPORT_SYMBOL
(
acpi_disable_event
);
EXPORT_SYMBOL
(
acpi_clear_event
);
EXPORT_SYMBOL
(
acpi_clear_event
);
...
...
drivers/hotplug/Kconfig
View file @
ce65fb43
...
@@ -61,7 +61,7 @@ config HOTPLUG_PCI_IBM
...
@@ -61,7 +61,7 @@ config HOTPLUG_PCI_IBM
config HOTPLUG_PCI_ACPI
config HOTPLUG_PCI_ACPI
tristate "ACPI PCI Hotplug driver"
tristate "ACPI PCI Hotplug driver"
depends on ACPI && HOTPLUG_PCI
depends on ACPI
_BUS
&& HOTPLUG_PCI
help
help
Say Y here if you have a system that supports PCI Hotplug using
Say Y here if you have a system that supports PCI Hotplug using
ACPI.
ACPI.
...
...
drivers/hotplug/acpiphp_glue.c
View file @
ce65fb43
...
@@ -806,6 +806,7 @@ static int enable_device (struct acpiphp_slot *slot)
...
@@ -806,6 +806,7 @@ static int enable_device (struct acpiphp_slot *slot)
struct
list_head
*
l
;
struct
list_head
*
l
;
struct
acpiphp_func
*
func
;
struct
acpiphp_func
*
func
;
int
retval
=
0
;
int
retval
=
0
;
int
num
;
if
(
slot
->
flags
&
SLOT_ENABLED
)
if
(
slot
->
flags
&
SLOT_ENABLED
)
goto
err_exit
;
goto
err_exit
;
...
@@ -825,7 +826,10 @@ static int enable_device (struct acpiphp_slot *slot)
...
@@ -825,7 +826,10 @@ static int enable_device (struct acpiphp_slot *slot)
goto
err_exit
;
goto
err_exit
;
/* returned `dev' is the *first function* only! */
/* returned `dev' is the *first function* only! */
dev
=
pci_scan_slot
(
slot
->
bridge
->
pci_bus
,
PCI_DEVFN
(
slot
->
device
,
0
));
num
=
pci_scan_slot
(
slot
->
bridge
->
pci_bus
,
PCI_DEVFN
(
slot
->
device
,
0
));
if
(
num
)
pci_bus_add_devices
(
slot
->
bridge
->
pci_bus
);
dev
=
pci_find_slot
(
slot
->
bridge
->
bus
,
PCI_DEVFN
(
slot
->
device
,
0
));
if
(
!
dev
)
{
if
(
!
dev
)
{
err
(
"No new device found
\n
"
);
err
(
"No new device found
\n
"
);
...
...
drivers/hotplug/cpqphp.h
View file @
ce65fb43
...
@@ -31,7 +31,7 @@
...
@@ -31,7 +31,7 @@
#include "pci_hotplug.h"
#include "pci_hotplug.h"
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <asm/io.h>
/* for read? and write? functions */
#include <asm/io.h>
/* for read? and write? functions */
#include <linux/delay.h>
/* for delays */
#if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE)
#if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE)
#define MY_NAME "cpqphp.o"
#define MY_NAME "cpqphp.o"
...
@@ -146,6 +146,10 @@ struct ctrl_reg { /* offset */
...
@@ -146,6 +146,10 @@ struct ctrl_reg { /* offset */
u8
reserved11
;
/* 0x2b */
u8
reserved11
;
/* 0x2b */
u8
slot_SERR
;
/* 0x2c */
u8
slot_SERR
;
/* 0x2c */
u8
slot_power
;
/* 0x2d */
u8
slot_power
;
/* 0x2d */
u8
reserved12
;
/* 0x2e */
u8
reserved13
;
/* 0x2f */
u8
next_curr_freq
;
/* 0x30 */
u8
reset_freq_mode
;
/* 0x31 */
}
__attribute__
((
packed
));
}
__attribute__
((
packed
));
/* offsets to the controller registers based on the above structure layout */
/* offsets to the controller registers based on the above structure layout */
...
@@ -173,6 +177,8 @@ enum ctrl_offsets {
...
@@ -173,6 +177,8 @@ enum ctrl_offsets {
CTRL_RESERVED11
=
offsetof
(
struct
ctrl_reg
,
reserved11
),
CTRL_RESERVED11
=
offsetof
(
struct
ctrl_reg
,
reserved11
),
SLOT_SERR
=
offsetof
(
struct
ctrl_reg
,
slot_SERR
),
SLOT_SERR
=
offsetof
(
struct
ctrl_reg
,
slot_SERR
),
SLOT_POWER
=
offsetof
(
struct
ctrl_reg
,
slot_power
),
SLOT_POWER
=
offsetof
(
struct
ctrl_reg
,
slot_power
),
NEXT_CURR_FREQ
=
offsetof
(
struct
ctrl_reg
,
next_curr_freq
),
RESET_FREQ_MODE
=
offsetof
(
struct
ctrl_reg
,
reset_freq_mode
),
};
};
struct
hrt
{
struct
hrt
{
...
@@ -294,12 +300,11 @@ struct controller {
...
@@ -294,12 +300,11 @@ struct controller {
struct
pci_resource
*
bus_head
;
struct
pci_resource
*
bus_head
;
struct
pci_dev
*
pci_dev
;
struct
pci_dev
*
pci_dev
;
struct
pci_bus
*
pci_bus
;
struct
pci_bus
*
pci_bus
;
struct
proc_dir_entry
*
proc_entry
;
struct
proc_dir_entry
*
proc_entry2
;
struct
event_info
event_queue
[
10
];
struct
event_info
event_queue
[
10
];
struct
slot
*
slot
;
struct
slot
*
slot
;
u8
next_event
;
u8
next_event
;
u8
interrupt
;
u8
interrupt
;
u8
cfgspc_irq
;
u8
bus
;
/* bus number for the pci hotplug controller */
u8
bus
;
/* bus number for the pci hotplug controller */
u8
rev
;
u8
rev
;
u8
slot_device_offset
;
u8
slot_device_offset
;
...
@@ -316,8 +321,6 @@ struct controller {
...
@@ -316,8 +321,6 @@ struct controller {
u8
pcix_speed_capability
;
/* PCI-X */
u8
pcix_speed_capability
;
/* PCI-X */
u8
pcix_support
;
/* PCI-X */
u8
pcix_support
;
/* PCI-X */
u16
vendor_id
;
u16
vendor_id
;
char
proc_name
[
20
];
char
proc_name2
[
20
];
struct
work_struct
int_task_event
;
struct
work_struct
int_task_event
;
wait_queue_head_t
queue
;
/* sleep & wake process */
wait_queue_head_t
queue
;
/* sleep & wake process */
};
};
...
@@ -344,6 +347,7 @@ struct resource_lists {
...
@@ -344,6 +347,7 @@ struct resource_lists {
#define PCI_SUB_HPC_ID2 0xA2F8
#define PCI_SUB_HPC_ID2 0xA2F8
#define PCI_SUB_HPC_ID3 0xA2F9
#define PCI_SUB_HPC_ID3 0xA2F9
#define PCI_SUB_HPC_ID_INTC 0xA2FA
#define PCI_SUB_HPC_ID_INTC 0xA2FA
#define PCI_SUB_HPC_ID4 0xA2FD
#define INT_BUTTON_IGNORE 0
#define INT_BUTTON_IGNORE 0
#define INT_PRESENCE_ON 1
#define INT_PRESENCE_ON 1
...
@@ -436,7 +440,7 @@ extern int cpqhp_return_board_resources (struct pci_func * func, struct resource
...
@@ -436,7 +440,7 @@ extern int cpqhp_return_board_resources (struct pci_func * func, struct resource
extern
void
cpqhp_destroy_resource_list
(
struct
resource_lists
*
resources
);
extern
void
cpqhp_destroy_resource_list
(
struct
resource_lists
*
resources
);
extern
int
cpqhp_configure_device
(
struct
controller
*
ctrl
,
struct
pci_func
*
func
);
extern
int
cpqhp_configure_device
(
struct
controller
*
ctrl
,
struct
pci_func
*
func
);
extern
int
cpqhp_unconfigure_device
(
struct
pci_func
*
func
);
extern
int
cpqhp_unconfigure_device
(
struct
pci_func
*
func
);
extern
struct
slot
*
cpqhp_find_slot
(
struct
controller
*
ctrl
,
u8
device
);
/* Global variables */
/* Global variables */
extern
int
cpqhp_debug
;
extern
int
cpqhp_debug
;
...
@@ -564,6 +568,7 @@ static inline void green_LED_blink (struct controller *ctrl, u8 slot)
...
@@ -564,6 +568,7 @@ static inline void green_LED_blink (struct controller *ctrl, u8 slot)
u32
led_control
;
u32
led_control
;
led_control
=
readl
(
ctrl
->
hpc_reg
+
LED_CONTROL
);
led_control
=
readl
(
ctrl
->
hpc_reg
+
LED_CONTROL
);
led_control
&=
~
(
0x0101L
<<
slot
);
led_control
|=
(
0x0001L
<<
slot
);
led_control
|=
(
0x0001L
<<
slot
);
writel
(
led_control
,
ctrl
->
hpc_reg
+
LED_CONTROL
);
writel
(
led_control
,
ctrl
->
hpc_reg
+
LED_CONTROL
);
}
}
...
@@ -605,15 +610,64 @@ static inline u8 read_slot_enable (struct controller *ctrl)
...
@@ -605,15 +610,64 @@ static inline u8 read_slot_enable (struct controller *ctrl)
}
}
/*
* get_controller_speed - find the current frequency/mode of controller.
*
* @ctrl: controller to get frequency/mode for.
*
* Returns controller speed.
*
*/
static
inline
u8
get_controller_speed
(
struct
controller
*
ctrl
)
static
inline
u8
get_controller_speed
(
struct
controller
*
ctrl
)
{
{
u8
curr_freq
;
u16
misc
;
u16
misc
;
if
(
ctrl
->
pcix_support
)
{
curr_freq
=
readb
(
ctrl
->
hpc_reg
+
NEXT_CURR_FREQ
);
if
((
curr_freq
&
0xB0
)
==
0xB0
)
return
PCI_SPEED_133MHz_PCIX
;
if
((
curr_freq
&
0xA0
)
==
0xA0
)
return
PCI_SPEED_100MHz_PCIX
;
if
((
curr_freq
&
0x90
)
==
0x90
)
return
PCI_SPEED_66MHz_PCIX
;
if
(
curr_freq
&
0x10
)
return
PCI_SPEED_66MHz
;
return
PCI_SPEED_33MHz
;
}
misc
=
readw
(
ctrl
->
hpc_reg
+
MISC
);
misc
=
readw
(
ctrl
->
hpc_reg
+
MISC
);
return
(
misc
&
0x0800
)
?
PCI_SPEED_66MHz
:
PCI_SPEED_33MHz
;
return
(
misc
&
0x0800
)
?
PCI_SPEED_66MHz
:
PCI_SPEED_33MHz
;
}
}
/*
* get_adapter_speed - find the max supported frequency/mode of adapter.
*
* @ctrl: hotplug controller.
* @hp_slot: hotplug slot where adapter is installed.
*
* Returns adapter speed.
*
*/
static
inline
u8
get_adapter_speed
(
struct
controller
*
ctrl
,
u8
hp_slot
)
{
u32
temp_dword
=
readl
(
ctrl
->
hpc_reg
+
NON_INT_INPUT
);
dbg
(
"slot: %d, PCIXCAP: %8x
\n
"
,
hp_slot
,
temp_dword
);
if
(
ctrl
->
pcix_support
)
{
if
(
temp_dword
&
(
0x10000
<<
hp_slot
))
return
PCI_SPEED_133MHz_PCIX
;
if
(
temp_dword
&
(
0x100
<<
hp_slot
))
return
PCI_SPEED_66MHz_PCIX
;
}
if
(
temp_dword
&
(
0x01
<<
hp_slot
))
return
PCI_SPEED_66MHz
;
return
PCI_SPEED_33MHz
;
}
static
inline
void
enable_slot_power
(
struct
controller
*
ctrl
,
u8
slot
)
static
inline
void
enable_slot_power
(
struct
controller
*
ctrl
,
u8
slot
)
{
{
u8
slot_power
;
u8
slot_power
;
...
@@ -721,5 +775,138 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl)
...
@@ -721,5 +775,138 @@ static inline int wait_for_ctrl_irq (struct controller *ctrl)
return
retval
;
return
retval
;
}
}
/**
* set_controller_speed - set the frequency and/or mode of a specific
* controller segment.
*
* @ctrl: controller to change frequency/mode for.
* @adapter_speed: the speed of the adapter we want to match.
* @hp_slot: the slot number where the adapter is installed.
*
* Returns 0 if we successfully change frequency and/or mode to match the
* adapter speed.
*
*/
static
inline
u8
set_controller_speed
(
struct
controller
*
ctrl
,
u8
adapter_speed
,
u8
hp_slot
)
{
struct
slot
*
slot
;
u8
reg
;
u8
slot_power
=
readb
(
ctrl
->
hpc_reg
+
SLOT_POWER
);
u16
reg16
;
u32
leds
=
readl
(
ctrl
->
hpc_reg
+
LED_CONTROL
);
if
(
ctrl
->
speed
==
adapter_speed
)
return
0
;
/* We don't allow freq/mode changes if we find another adapter running
* in another slot on this controller */
for
(
slot
=
ctrl
->
slot
;
slot
;
slot
=
slot
->
next
)
{
if
(
slot
->
device
==
(
hp_slot
+
ctrl
->
slot_device_offset
))
continue
;
if
(
!
slot
->
hotplug_slot
&&
!
slot
->
hotplug_slot
->
info
)
continue
;
if
(
slot
->
hotplug_slot
->
info
->
adapter_status
==
0
)
continue
;
/* If another adapter is running on the same segment but at a
* lower speed/mode, we allow the new adapter to function at
* this rate if supported */
if
(
ctrl
->
speed
<
adapter_speed
)
return
0
;
return
1
;
}
/* If the controller doesn't support freq/mode changes and the
* controller is running at a higher mode, we bail */
if
((
ctrl
->
speed
>
adapter_speed
)
&&
(
!
ctrl
->
pcix_speed_capability
))
return
1
;
/* But we allow the adapter to run at a lower rate if possible */
if
((
ctrl
->
speed
<
adapter_speed
)
&&
(
!
ctrl
->
pcix_speed_capability
))
return
0
;
/* We try to set the max speed supported by both the adapter and
* controller */
if
(
ctrl
->
speed_capability
<
adapter_speed
)
{
if
(
ctrl
->
speed
==
ctrl
->
speed_capability
)
return
0
;
adapter_speed
=
ctrl
->
speed_capability
;
}
writel
(
0x0L
,
ctrl
->
hpc_reg
+
LED_CONTROL
);
writeb
(
0x00
,
ctrl
->
hpc_reg
+
SLOT_ENABLE
);
set_SOGO
(
ctrl
);
wait_for_ctrl_irq
(
ctrl
);
if
(
adapter_speed
!=
PCI_SPEED_133MHz_PCIX
)
reg
=
0xF5
;
else
reg
=
0xF4
;
pci_write_config_byte
(
ctrl
->
pci_dev
,
0x41
,
reg
);
reg16
=
readw
(
ctrl
->
hpc_reg
+
NEXT_CURR_FREQ
);
reg16
&=
~
0x000F
;
switch
(
adapter_speed
)
{
case
(
PCI_SPEED_133MHz_PCIX
):
reg
=
0x75
;
reg16
|=
0xB
;
break
;
case
(
PCI_SPEED_100MHz_PCIX
):
reg
=
0x74
;
reg16
|=
0xA
;
break
;
case
(
PCI_SPEED_66MHz_PCIX
):
reg
=
0x73
;
reg16
|=
0x9
;
break
;
case
(
PCI_SPEED_66MHz
):
reg
=
0x73
;
reg16
|=
0x1
;
break
;
default:
/* 33MHz PCI 2.2 */
reg
=
0x71
;
break
;
}
reg16
|=
0xB
<<
12
;
writew
(
reg16
,
ctrl
->
hpc_reg
+
NEXT_CURR_FREQ
);
mdelay
(
5
);
/* Reenable interrupts */
writel
(
0
,
ctrl
->
hpc_reg
+
INT_MASK
);
pci_write_config_byte
(
ctrl
->
pci_dev
,
0x41
,
reg
);
/* Restart state machine */
reg
=
~
0xF
;
pci_read_config_byte
(
ctrl
->
pci_dev
,
0x43
,
&
reg
);
pci_write_config_byte
(
ctrl
->
pci_dev
,
0x43
,
reg
);
/* Only if mode change...*/
if
(((
ctrl
->
speed
==
PCI_SPEED_66MHz
)
&&
(
adapter_speed
==
PCI_SPEED_66MHz_PCIX
))
||
((
ctrl
->
speed
==
PCI_SPEED_66MHz_PCIX
)
&&
(
adapter_speed
==
PCI_SPEED_66MHz
)))
set_SOGO
(
ctrl
);
wait_for_ctrl_irq
(
ctrl
);
mdelay
(
1100
);
/* Restore LED/Slot state */
writel
(
leds
,
ctrl
->
hpc_reg
+
LED_CONTROL
);
writeb
(
slot_power
,
ctrl
->
hpc_reg
+
SLOT_ENABLE
);
set_SOGO
(
ctrl
);
wait_for_ctrl_irq
(
ctrl
);
ctrl
->
speed
=
adapter_speed
;
slot
=
cpqhp_find_slot
(
ctrl
,
hp_slot
+
ctrl
->
slot_device_offset
);
info
(
"Successfully changed frequency/mode for adapter in slot %d
\n
"
,
slot
->
number
);
return
0
;
}
#endif
#endif
drivers/hotplug/cpqphp_core.c
View file @
ce65fb43
...
@@ -24,6 +24,9 @@
...
@@ -24,6 +24,9 @@
*
*
* Send feedback to <greg@kroah.com>
* Send feedback to <greg@kroah.com>
*
*
* Jan 12, 2003 - Added 66/100/133MHz PCI-X support,
* Torben Mathiasen <torben.mathiasen@hp.com>
*
*/
*/
#include <linux/config.h>
#include <linux/config.h>
...
@@ -57,7 +60,7 @@ static void *cpqhp_rom_start;
...
@@ -57,7 +60,7 @@ static void *cpqhp_rom_start;
static
u8
power_mode
;
static
u8
power_mode
;
static
int
debug
;
static
int
debug
;
#define DRIVER_VERSION "0.9.
6
"
#define DRIVER_VERSION "0.9.
7
"
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver"
#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver"
...
@@ -835,6 +838,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -835,6 +838,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
u8
hp_slot
=
0
;
u8
hp_slot
=
0
;
u8
device
;
u8
device
;
u8
rev
;
u8
rev
;
u8
bus_cap
;
u16
temp_word
;
u16
temp_word
;
u16
vendor_id
;
u16
vendor_id
;
u16
subsystem_vid
;
u16
subsystem_vid
;
...
@@ -896,6 +900,39 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -896,6 +900,39 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
switch
(
subsystem_vid
)
{
switch
(
subsystem_vid
)
{
case
PCI_VENDOR_ID_COMPAQ
:
case
PCI_VENDOR_ID_COMPAQ
:
if
(
rev
>=
0x13
)
{
/* CIOBX */
ctrl
->
push_flag
=
1
;
ctrl
->
slot_switch_type
=
1
;
// Switch is present
ctrl
->
push_button
=
1
;
// Pushbutton is present
ctrl
->
pci_config_space
=
1
;
// Index/data access to working registers 0 = not supported, 1 = supported
ctrl
->
defeature_PHP
=
1
;
// PHP is supported
ctrl
->
pcix_support
=
1
;
// PCI-X supported
ctrl
->
pcix_speed_capability
=
1
;
pci_read_config_byte
(
pdev
,
0x41
,
&
bus_cap
);
if
(
bus_cap
&
0x80
)
{
dbg
(
"bus max supports 133MHz PCI-X
\n
"
);
ctrl
->
speed_capability
=
PCI_SPEED_133MHz_PCIX
;
break
;
}
if
(
bus_cap
&
0x40
)
{
dbg
(
"bus max supports 100MHz PCI-X
\n
"
);
ctrl
->
speed_capability
=
PCI_SPEED_100MHz_PCIX
;
break
;
}
if
(
bus_cap
&
20
)
{
dbg
(
"bus max supports 66MHz PCI-X
\n
"
);
ctrl
->
speed_capability
=
PCI_SPEED_66MHz_PCIX
;
break
;
}
if
(
bus_cap
&
10
)
{
dbg
(
"bus max supports 66MHz PCI
\n
"
);
ctrl
->
speed_capability
=
PCI_SPEED_66MHz
;
break
;
}
break
;
}
switch
(
subsystem_deviceid
)
{
switch
(
subsystem_deviceid
)
{
case
PCI_SUB_HPC_ID
:
case
PCI_SUB_HPC_ID
:
/* Original 6500/7000 implementation */
/* Original 6500/7000 implementation */
...
@@ -939,8 +976,18 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -939,8 +976,18 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ctrl
->
pcix_support
=
0
;
// PCI-X not supported
ctrl
->
pcix_support
=
0
;
// PCI-X not supported
ctrl
->
pcix_speed_capability
=
0
;
// N/A since PCI-X not supported
ctrl
->
pcix_speed_capability
=
0
;
// N/A since PCI-X not supported
break
;
break
;
case
PCI_SUB_HPC_ID4
:
/* First PCI-X implementation, 100MHz */
ctrl
->
push_flag
=
1
;
ctrl
->
slot_switch_type
=
1
;
// Switch is present
ctrl
->
speed_capability
=
PCI_SPEED_100MHz_PCIX
;
ctrl
->
push_button
=
1
;
// Pushbutton is present
ctrl
->
pci_config_space
=
1
;
// Index/data access to working registers 0 = not supported, 1 = supported
ctrl
->
defeature_PHP
=
1
;
// PHP is supported
ctrl
->
pcix_support
=
1
;
// PCI-X supported
ctrl
->
pcix_speed_capability
=
0
;
break
;
default:
default:
// TODO: Add SSIDs for CPQ systems that support PCI-X
err
(
msg_HPC_not_supported
);
err
(
msg_HPC_not_supported
);
rc
=
-
ENODEV
;
rc
=
-
ENODEV
;
goto
err_free_ctrl
;
goto
err_free_ctrl
;
...
@@ -1029,7 +1076,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -1029,7 +1076,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
info
(
"Initializing the PCI hot plug controller residing on PCI bus %d
\n
"
,
pdev
->
bus
->
number
);
info
(
"Initializing the PCI hot plug controller residing on PCI bus %d
\n
"
,
pdev
->
bus
->
number
);
dbg
(
"Hotplug controller capabilities:
\n
"
);
dbg
(
"Hotplug controller capabilities:
\n
"
);
dbg
(
" speed_capability %
s
\n
"
,
ctrl
->
speed_capability
==
PCI_SPEED_33MHz
?
"33MHz"
:
"66Mhz"
);
dbg
(
" speed_capability %
d
\n
"
,
ctrl
->
speed_capability
);
dbg
(
" slot_switch_type %s
\n
"
,
ctrl
->
slot_switch_type
==
0
?
"no switch"
:
"switch present"
);
dbg
(
" slot_switch_type %s
\n
"
,
ctrl
->
slot_switch_type
==
0
?
"no switch"
:
"switch present"
);
dbg
(
" defeature_PHP %s
\n
"
,
ctrl
->
defeature_PHP
==
0
?
"PHP not supported"
:
"PHP supported"
);
dbg
(
" defeature_PHP %s
\n
"
,
ctrl
->
defeature_PHP
==
0
?
"PHP not supported"
:
"PHP supported"
);
dbg
(
" alternate_base_address %s
\n
"
,
ctrl
->
alternate_base_address
==
0
?
"not supported"
:
"supported"
);
dbg
(
" alternate_base_address %s
\n
"
,
ctrl
->
alternate_base_address
==
0
?
"not supported"
:
"supported"
);
...
@@ -1082,7 +1129,6 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -1082,7 +1129,6 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
// Check for 66Mhz operation
// Check for 66Mhz operation
// TODO: Add PCI-X support
ctrl
->
speed
=
get_controller_speed
(
ctrl
);
ctrl
->
speed
=
get_controller_speed
(
ctrl
);
...
@@ -1119,6 +1165,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
...
@@ -1119,6 +1165,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
// The next line is required for cpqhp_find_available_resources
// The next line is required for cpqhp_find_available_resources
ctrl
->
interrupt
=
pdev
->
irq
;
ctrl
->
interrupt
=
pdev
->
irq
;
ctrl
->
cfgspc_irq
=
0
;
pci_read_config_byte
(
pdev
,
PCI_INTERRUPT_LINE
,
&
ctrl
->
cfgspc_irq
);
rc
=
cpqhp_find_available_resources
(
ctrl
,
cpqhp_rom_start
);
rc
=
cpqhp_find_available_resources
(
ctrl
,
cpqhp_rom_start
);
ctrl
->
add_support
=
!
rc
;
ctrl
->
add_support
=
!
rc
;
if
(
rc
)
{
if
(
rc
)
{
...
...
drivers/hotplug/cpqphp_ctrl.c
View file @
ce65fb43
...
@@ -136,9 +136,9 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl)
...
@@ -136,9 +136,9 @@ static u8 handle_switch_change(u8 change, struct controller * ctrl)
/*
/*
* find_slot
*
cpqhp_
find_slot
*/
*/
st
atic
inline
struct
slot
*
find_slot
(
struct
controller
*
ctrl
,
u8
device
)
st
ruct
slot
*
cpqhp_
find_slot
(
struct
controller
*
ctrl
,
u8
device
)
{
{
struct
slot
*
slot
;
struct
slot
*
slot
;
...
@@ -187,7 +187,7 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
...
@@ -187,7 +187,7 @@ static u8 handle_presence_change(u16 change, struct controller * ctrl)
rc
++
;
rc
++
;
p_slot
=
find_slot
(
ctrl
,
hp_slot
+
(
readb
(
ctrl
->
hpc_reg
+
SLOT_MASK
)
>>
4
));
p_slot
=
cpqhp_
find_slot
(
ctrl
,
hp_slot
+
(
readb
(
ctrl
->
hpc_reg
+
SLOT_MASK
)
>>
4
));
if
(
!
p_slot
)
if
(
!
p_slot
)
return
0
;
return
0
;
...
@@ -920,6 +920,7 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs)
...
@@ -920,6 +920,7 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs)
{
{
struct
controller
*
ctrl
=
data
;
struct
controller
*
ctrl
=
data
;
u8
schedule_flag
=
0
;
u8
schedule_flag
=
0
;
u8
reset
;
u16
misc
;
u16
misc
;
u32
Diff
;
u32
Diff
;
u32
temp_dword
;
u32
temp_dword
;
...
@@ -971,6 +972,15 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs)
...
@@ -971,6 +972,15 @@ irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs)
schedule_flag
+=
handle_power_fault
((
u8
)((
Diff
&
0xFF00L
)
>>
8
),
ctrl
);
schedule_flag
+=
handle_power_fault
((
u8
)((
Diff
&
0xFF00L
)
>>
8
),
ctrl
);
}
}
reset
=
readb
(
ctrl
->
hpc_reg
+
RESET_FREQ_MODE
);
if
(
reset
&
0x40
)
{
/* Bus reset has completed */
reset
&=
0xCF
;
writeb
(
reset
,
ctrl
->
hpc_reg
+
RESET_FREQ_MODE
);
reset
=
readb
(
ctrl
->
hpc_reg
+
RESET_FREQ_MODE
);
wake_up_interruptible
(
&
ctrl
->
queue
);
}
if
(
schedule_flag
)
{
if
(
schedule_flag
)
{
up
(
&
event_semaphore
);
up
(
&
event_semaphore
);
dbg
(
"Signal event_semaphore
\n
"
);
dbg
(
"Signal event_semaphore
\n
"
);
...
@@ -1172,6 +1182,7 @@ static u32 board_replaced(struct pci_func * func, struct controller * ctrl)
...
@@ -1172,6 +1182,7 @@ static u32 board_replaced(struct pci_func * func, struct controller * ctrl)
{
{
u8
hp_slot
;
u8
hp_slot
;
u8
temp_byte
;
u8
temp_byte
;
u8
adapter_speed
;
u32
index
;
u32
index
;
u32
rc
=
0
;
u32
rc
=
0
;
u32
src
=
8
;
u32
src
=
8
;
...
@@ -1189,7 +1200,6 @@ static u32 board_replaced(struct pci_func * func, struct controller * ctrl)
...
@@ -1189,7 +1200,6 @@ static u32 board_replaced(struct pci_func * func, struct controller * ctrl)
//*********************************
//*********************************
rc
=
CARD_FUNCTIONING
;
rc
=
CARD_FUNCTIONING
;
}
else
{
}
else
{
if
(
ctrl
->
speed
==
PCI_SPEED_66MHz
)
{
// Wait for exclusive access to hardware
// Wait for exclusive access to hardware
down
(
&
ctrl
->
crit_sect
);
down
(
&
ctrl
->
crit_sect
);
...
@@ -1212,9 +1222,11 @@ static u32 board_replaced(struct pci_func * func, struct controller * ctrl)
...
@@ -1212,9 +1222,11 @@ static u32 board_replaced(struct pci_func * func, struct controller * ctrl)
// Wait for SOBS to be unset
// Wait for SOBS to be unset
wait_for_ctrl_irq
(
ctrl
);
wait_for_ctrl_irq
(
ctrl
);
if
(
!
(
readl
(
ctrl
->
hpc_reg
+
NON_INT_INPUT
)
&
(
0x01
<<
hp_slot
)))
{
adapter_speed
=
get_adapter_speed
(
ctrl
,
hp_slot
);
if
(
ctrl
->
speed
!=
adapter_speed
)
if
(
set_controller_speed
(
ctrl
,
adapter_speed
,
hp_slot
))
rc
=
WRONG_BUS_FREQUENCY
;
rc
=
WRONG_BUS_FREQUENCY
;
}
// turn off board without attaching to the bus
// turn off board without attaching to the bus
disable_slot_power
(
ctrl
,
hp_slot
);
disable_slot_power
(
ctrl
,
hp_slot
);
...
@@ -1228,7 +1240,6 @@ static u32 board_replaced(struct pci_func * func, struct controller * ctrl)
...
@@ -1228,7 +1240,6 @@ static u32 board_replaced(struct pci_func * func, struct controller * ctrl)
if
(
rc
)
if
(
rc
)
return
(
rc
);
return
(
rc
);
}
// Wait for exclusive access to hardware
// Wait for exclusive access to hardware
down
(
&
ctrl
->
crit_sect
);
down
(
&
ctrl
->
crit_sect
);
...
@@ -1376,6 +1387,7 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
...
@@ -1376,6 +1387,7 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
{
{
u8
hp_slot
;
u8
hp_slot
;
u8
temp_byte
;
u8
temp_byte
;
u8
adapter_speed
;
int
index
;
int
index
;
u32
temp_register
=
0xFFFFFFFF
;
u32
temp_register
=
0xFFFFFFFF
;
u32
rc
=
0
;
u32
rc
=
0
;
...
@@ -1387,7 +1399,6 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
...
@@ -1387,7 +1399,6 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
dbg
(
"%s: func->device, slot_offset, hp_slot = %d, %d ,%d
\n
"
,
dbg
(
"%s: func->device, slot_offset, hp_slot = %d, %d ,%d
\n
"
,
__FUNCTION__
,
func
->
device
,
ctrl
->
slot_device_offset
,
hp_slot
);
__FUNCTION__
,
func
->
device
,
ctrl
->
slot_device_offset
,
hp_slot
);
if
(
ctrl
->
speed
==
PCI_SPEED_66MHz
)
{
// Wait for exclusive access to hardware
// Wait for exclusive access to hardware
down
(
&
ctrl
->
crit_sect
);
down
(
&
ctrl
->
crit_sect
);
...
@@ -1410,9 +1421,11 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
...
@@ -1410,9 +1421,11 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
// Wait for SOBS to be unset
// Wait for SOBS to be unset
wait_for_ctrl_irq
(
ctrl
);
wait_for_ctrl_irq
(
ctrl
);
if
(
!
(
readl
(
ctrl
->
hpc_reg
+
NON_INT_INPUT
)
&
(
0x01
<<
hp_slot
)))
{
adapter_speed
=
get_adapter_speed
(
ctrl
,
hp_slot
);
if
(
ctrl
->
speed
!=
adapter_speed
)
if
(
set_controller_speed
(
ctrl
,
adapter_speed
,
hp_slot
))
rc
=
WRONG_BUS_FREQUENCY
;
rc
=
WRONG_BUS_FREQUENCY
;
}
// turn off board without attaching to the bus
// turn off board without attaching to the bus
disable_slot_power
(
ctrl
,
hp_slot
);
disable_slot_power
(
ctrl
,
hp_slot
);
...
@@ -1426,8 +1439,8 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
...
@@ -1426,8 +1439,8 @@ static u32 board_added(struct pci_func * func, struct controller * ctrl)
if
(
rc
)
if
(
rc
)
return
(
rc
);
return
(
rc
);
}
p_slot
=
find_slot
(
ctrl
,
hp_slot
+
ctrl
->
slot_device_offset
);
p_slot
=
cpqhp_
find_slot
(
ctrl
,
hp_slot
+
ctrl
->
slot_device_offset
);
// turn on board and blink green LED
// turn on board and blink green LED
...
@@ -1800,7 +1813,7 @@ static void interrupt_event_handler(struct controller *ctrl)
...
@@ -1800,7 +1813,7 @@ static void interrupt_event_handler(struct controller *ctrl)
if
(
!
func
)
if
(
!
func
)
return
;
return
;
p_slot
=
find_slot
(
ctrl
,
hp_slot
+
ctrl
->
slot_device_offset
);
p_slot
=
cpqhp_
find_slot
(
ctrl
,
hp_slot
+
ctrl
->
slot_device_offset
);
if
(
!
p_slot
)
if
(
!
p_slot
)
return
;
return
;
...
@@ -1862,6 +1875,7 @@ static void interrupt_event_handler(struct controller *ctrl)
...
@@ -1862,6 +1875,7 @@ static void interrupt_event_handler(struct controller *ctrl)
down
(
&
ctrl
->
crit_sect
);
down
(
&
ctrl
->
crit_sect
);
dbg
(
"blink green LED and turn off amber
\n
"
);
dbg
(
"blink green LED and turn off amber
\n
"
);
amber_LED_off
(
ctrl
,
hp_slot
);
amber_LED_off
(
ctrl
,
hp_slot
);
green_LED_blink
(
ctrl
,
hp_slot
);
green_LED_blink
(
ctrl
,
hp_slot
);
...
@@ -1992,7 +2006,7 @@ int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func)
...
@@ -1992,7 +2006,7 @@ int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func)
device
=
func
->
device
;
device
=
func
->
device
;
hp_slot
=
device
-
ctrl
->
slot_device_offset
;
hp_slot
=
device
-
ctrl
->
slot_device_offset
;
p_slot
=
find_slot
(
ctrl
,
device
);
p_slot
=
cpqhp_
find_slot
(
ctrl
,
device
);
if
(
p_slot
)
{
if
(
p_slot
)
{
physical_slot
=
p_slot
->
number
;
physical_slot
=
p_slot
->
number
;
}
}
...
@@ -2091,7 +2105,7 @@ int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func)
...
@@ -2091,7 +2105,7 @@ int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func)
device
=
func
->
device
;
device
=
func
->
device
;
func
=
cpqhp_slot_find
(
ctrl
->
bus
,
device
,
index
++
);
func
=
cpqhp_slot_find
(
ctrl
->
bus
,
device
,
index
++
);
p_slot
=
find_slot
(
ctrl
,
device
);
p_slot
=
cpqhp_
find_slot
(
ctrl
,
device
);
if
(
p_slot
)
{
if
(
p_slot
)
{
physical_slot
=
p_slot
->
number
;
physical_slot
=
p_slot
->
number
;
}
}
...
...
drivers/hotplug/cpqphp_pci.c
View file @
ce65fb43
...
@@ -85,18 +85,20 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
...
@@ -85,18 +85,20 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
{
{
unsigned
char
bus
;
unsigned
char
bus
;
struct
pci_bus
*
child
;
struct
pci_bus
*
child
;
int
rc
=
0
;
int
num
;
if
(
func
->
pci_dev
==
NULL
)
if
(
func
->
pci_dev
==
NULL
)
func
->
pci_dev
=
pci_find_slot
(
func
->
bus
,
(
func
->
device
<<
3
)
|
(
func
->
function
&
0x7
));
func
->
pci_dev
=
pci_find_slot
(
func
->
bus
,
PCI_DEVFN
(
func
->
device
,
func
->
function
));
/
/Still NULL ? Well then scan for it !
/
* No pci device, we need to create it then */
if
(
func
->
pci_dev
==
NULL
)
{
if
(
func
->
pci_dev
==
NULL
)
{
dbg
(
"INFO: pci_dev still null
\n
"
);
dbg
(
"INFO: pci_dev still null
\n
"
);
//this will generate pci_dev structures for all functions, but we will only call this case when lookup fails
num
=
pci_scan_slot
(
ctrl
->
pci_dev
->
bus
,
PCI_DEVFN
(
func
->
device
,
func
->
function
));
func
->
pci_dev
=
pci_scan_slot
(
ctrl
->
pci_dev
->
bus
,
if
(
num
)
(
func
->
device
<<
3
)
+
(
func
->
function
&
0x7
));
pci_bus_add_devices
(
ctrl
->
pci_dev
->
bus
);
func
->
pci_dev
=
pci_find_slot
(
func
->
bus
,
PCI_DEVFN
(
func
->
device
,
func
->
function
));
if
(
func
->
pci_dev
==
NULL
)
{
if
(
func
->
pci_dev
==
NULL
)
{
dbg
(
"ERROR: pci_dev still null
\n
"
);
dbg
(
"ERROR: pci_dev still null
\n
"
);
return
0
;
return
0
;
...
@@ -107,10 +109,9 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
...
@@ -107,10 +109,9 @@ int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)
pci_read_config_byte
(
func
->
pci_dev
,
PCI_SECONDARY_BUS
,
&
bus
);
pci_read_config_byte
(
func
->
pci_dev
,
PCI_SECONDARY_BUS
,
&
bus
);
child
=
(
struct
pci_bus
*
)
pci_add_new_bus
(
func
->
pci_dev
->
bus
,
(
func
->
pci_dev
),
bus
);
child
=
(
struct
pci_bus
*
)
pci_add_new_bus
(
func
->
pci_dev
->
bus
,
(
func
->
pci_dev
),
bus
);
pci_do_scan_bus
(
child
);
pci_do_scan_bus
(
child
);
}
}
return
rc
;
return
0
;
}
}
...
@@ -1209,11 +1210,11 @@ int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start)
...
@@ -1209,11 +1210,11 @@ int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start)
temp
=
0
;
temp
=
0
;
if
(
!
cpqhp_nic_irq
)
{
if
(
!
cpqhp_nic_irq
)
{
cpqhp_nic_irq
=
ctrl
->
interrupt
;
cpqhp_nic_irq
=
ctrl
->
cfgspc_irq
;
}
}
if
(
!
cpqhp_disk_irq
)
{
if
(
!
cpqhp_disk_irq
)
{
cpqhp_disk_irq
=
ctrl
->
interrupt
;
cpqhp_disk_irq
=
ctrl
->
cfgspc_irq
;
}
}
dbg
(
"cpqhp_disk_irq, cpqhp_nic_irq= %d, %d
\n
"
,
cpqhp_disk_irq
,
cpqhp_nic_irq
);
dbg
(
"cpqhp_disk_irq, cpqhp_nic_irq= %d, %d
\n
"
,
cpqhp_disk_irq
,
cpqhp_nic_irq
);
...
...
drivers/hotplug/ibmphp_core.c
View file @
ce65fb43
...
@@ -846,22 +846,24 @@ static int ibm_configure_device (struct pci_func *func)
...
@@ -846,22 +846,24 @@ static int ibm_configure_device (struct pci_func *func)
{
{
unsigned
char
bus
;
unsigned
char
bus
;
struct
pci_bus
*
child
;
struct
pci_bus
*
child
;
int
rc
=
0
;
int
num
;
int
flag
=
0
;
/* this is to make sure we don't double scan the bus, for bridged devices primarily */
int
flag
=
0
;
/* this is to make sure we don't double scan the bus, for bridged devices primarily */
if
(
!
(
bus_structure_fixup
(
func
->
busno
)))
if
(
!
(
bus_structure_fixup
(
func
->
busno
)))
flag
=
1
;
flag
=
1
;
if
(
func
->
dev
==
NULL
)
if
(
func
->
dev
==
NULL
)
func
->
dev
=
pci_find_slot
(
func
->
busno
,
(
func
->
device
<<
3
)
|
(
func
->
function
&
0x7
));
func
->
dev
=
pci_find_slot
(
func
->
busno
,
PCI_DEVFN
(
func
->
device
,
func
->
function
));
if
(
func
->
dev
==
NULL
)
{
if
(
func
->
dev
==
NULL
)
{
struct
pci_bus
*
bus
=
ibmphp_find_bus
(
func
->
busno
);
struct
pci_bus
*
bus
=
ibmphp_find_bus
(
func
->
busno
);
if
(
!
bus
)
if
(
!
bus
)
return
0
;
return
0
;
func
->
dev
=
pci_scan_slot
(
bus
,
num
=
pci_scan_slot
(
bus
,
PCI_DEVFN
(
func
->
device
,
func
->
function
));
(
func
->
device
<<
3
)
+
(
func
->
function
&
0x7
));
if
(
num
)
pci_bus_add_devices
(
bus
);
func
->
dev
=
pci_find_slot
(
func
->
busno
,
PCI_DEVFN
(
func
->
device
,
func
->
function
));
if
(
func
->
dev
==
NULL
)
{
if
(
func
->
dev
==
NULL
)
{
err
(
"ERROR... : pci_dev still NULL
\n
"
);
err
(
"ERROR... : pci_dev still NULL
\n
"
);
return
0
;
return
0
;
...
@@ -873,7 +875,7 @@ static int ibm_configure_device (struct pci_func *func)
...
@@ -873,7 +875,7 @@ static int ibm_configure_device (struct pci_func *func)
pci_do_scan_bus
(
child
);
pci_do_scan_bus
(
child
);
}
}
return
rc
;
return
0
;
}
}
/*******************************************************
/*******************************************************
...
@@ -1415,7 +1417,7 @@ static int __init ibmphp_init (void)
...
@@ -1415,7 +1417,7 @@ static int __init ibmphp_init (void)
/* lock ourselves into memory with a module
/* lock ourselves into memory with a module
* count of -1 so that no one can unload us. */
* count of -1 so that no one can unload us. */
MOD_DEC_USE_COUNT
;
module_put
(
THIS_MODULE
)
;
exit:
exit:
return
rc
;
return
rc
;
...
...
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