Commit d236fbb8 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://linuxusb.bkbits.net/linus-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents b0a19b4f 7fc47df1
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev) #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt) #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
#define DRIVER_VERSION "0.2" #define DRIVER_VERSION "0.3"
#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" #define DRIVER_DESC "IBM Hot Plug PCI Controller Driver"
int ibmphp_debug; int ibmphp_debug;
...@@ -106,7 +106,7 @@ static inline int slot_update (struct slot **sl) ...@@ -106,7 +106,7 @@ static inline int slot_update (struct slot **sl)
return rc; return rc;
} }
static int get_max_slots (void) static int __init get_max_slots (void)
{ {
struct list_head * tmp; struct list_head * tmp;
int slot_count = 0; int slot_count = 0;
...@@ -528,7 +528,7 @@ static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value) ...@@ -528,7 +528,7 @@ static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value)
* function. It will also power off empty slots that are powered on since BIOS * function. It will also power off empty slots that are powered on since BIOS
* leaves those on, albeit disconnected * leaves those on, albeit disconnected
******************************************************************************/ ******************************************************************************/
static int init_ops (void) static int __init init_ops (void)
{ {
struct slot *slot_cur; struct slot *slot_cur;
int retval; int retval;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/init.h>
#include "ibmphp.h" #include "ibmphp.h"
/* /*
...@@ -76,7 +77,7 @@ static struct slot *alloc_ibm_slot (void) ...@@ -76,7 +77,7 @@ static struct slot *alloc_ibm_slot (void)
return slot; return slot;
} }
static struct ebda_hpc_list *alloc_ebda_hpc_list (void) static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void)
{ {
struct ebda_hpc_list *list; struct ebda_hpc_list *list;
...@@ -127,7 +128,7 @@ static void free_ebda_hpc (struct controller *controller) ...@@ -127,7 +128,7 @@ static void free_ebda_hpc (struct controller *controller)
kfree (controller); kfree (controller);
} }
static struct ebda_rsrc_list *alloc_ebda_rsrc_list (void) static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void)
{ {
struct ebda_rsrc_list *list; struct ebda_rsrc_list *list;
...@@ -149,7 +150,7 @@ static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) ...@@ -149,7 +150,7 @@ static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void)
return resource; return resource;
} }
static void print_bus_info (void) static void __init print_bus_info (void)
{ {
struct bus_info *ptr; struct bus_info *ptr;
struct list_head *ptr1; struct list_head *ptr1;
...@@ -184,7 +185,7 @@ static void print_ebda_pci_rsrc (void) ...@@ -184,7 +185,7 @@ static void print_ebda_pci_rsrc (void)
} }
} }
static void print_ebda_hpc (void) static void __init print_ebda_hpc (void)
{ {
struct controller *hpc_ptr; struct controller *hpc_ptr;
struct list_head *ptr1; struct list_head *ptr1;
...@@ -228,7 +229,7 @@ static void print_ebda_hpc (void) ...@@ -228,7 +229,7 @@ static void print_ebda_hpc (void)
} }
} }
int ibmphp_access_ebda (void) int __init ibmphp_access_ebda (void)
{ {
u8 format, num_ctlrs, rio_complete, hs_complete; u8 format, num_ctlrs, rio_complete, hs_complete;
u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base; u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base;
...@@ -387,7 +388,7 @@ int ibmphp_access_ebda (void) ...@@ -387,7 +388,7 @@ int ibmphp_access_ebda (void)
* each hpc from physical address to a list of hot plug controllers based on * each hpc from physical address to a list of hot plug controllers based on
* hpc descriptors. * hpc descriptors.
*/ */
static int ebda_rsrc_controller (void) static int __init ebda_rsrc_controller (void)
{ {
u16 addr, addr_slot, addr_bus; u16 addr, addr_slot, addr_bus;
u8 ctlr_id, temp, bus_index; u8 ctlr_id, temp, bus_index;
...@@ -649,7 +650,7 @@ static int ebda_rsrc_controller (void) ...@@ -649,7 +650,7 @@ static int ebda_rsrc_controller (void)
* map info (bus, devfun, start addr, end addr..) of i/o, memory, * map info (bus, devfun, start addr, end addr..) of i/o, memory,
* pfm from the physical addr to a list of resource. * pfm from the physical addr to a list of resource.
*/ */
static int ebda_rsrc_rsrc (void) static int __init ebda_rsrc_rsrc (void)
{ {
u16 addr; u16 addr;
short rsrc; short rsrc;
...@@ -717,7 +718,7 @@ static int ebda_rsrc_rsrc (void) ...@@ -717,7 +718,7 @@ static int ebda_rsrc_rsrc (void)
/* /*
* map info of scalability details and rio details from physical address * map info of scalability details and rio details from physical address
*/ */
static int ebda_rio_table(void) static int __init ebda_rio_table(void)
{ {
u16 offset; u16 offset;
u8 i; u8 i;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Written By: Jyoti Shah, IBM Corporation * Written By: Jyoti Shah, IBM Corporation
* *
* Copyright (c) 2001,2001 IBM Corp. * Copyright (c) 2001-2002 IBM Corp.
* *
* All rights reserved. * All rights reserved.
* *
...@@ -27,17 +27,14 @@ ...@@ -27,17 +27,14 @@
* *
*/ */
//#include <linux/delay.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h>
#include "ibmphp.h" #include "ibmphp.h"
#define POLL_NO 0x01
#define POLL_YES 0x00
static int to_debug = FALSE; static int to_debug = FALSE;
#define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) #define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0)
...@@ -98,19 +95,15 @@ static int to_debug = FALSE; ...@@ -98,19 +95,15 @@ static int to_debug = FALSE;
// if bits 20,22,25,26,27,29,30 are OFF return TRUE // if bits 20,22,25,26,27,29,30 are OFF return TRUE
#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) #define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE))
// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register
#define INCREMENT_POLLCNT(i) ((i < POLL_LATCH_CNT) ? i++ : (i=0))
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// global variables // global variables
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
static int ibmphp_shutdown; static int ibmphp_shutdown;
static int tid_poll; static int tid_poll;
static int stop_polling; // 2 values: poll, don't poll
static struct semaphore sem_hpcaccess; // lock access to HPC static struct semaphore sem_hpcaccess; // lock access to HPC
static struct semaphore semOperations; // lock all operations and static struct semaphore semOperations; // lock all operations and
// access to data structures // access to data structures
static struct semaphore sem_exit; // make sure polling thread goes away static struct semaphore sem_exit; // make sure polling thread goes away
static struct semaphore sem_poll; // make sure poll is idle
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// local function prototypes // local function prototypes
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
...@@ -134,15 +127,13 @@ static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *); ...@@ -134,15 +127,13 @@ static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *);
* *
* Action: initialize semaphores and variables * Action: initialize semaphores and variables
*---------------------------------------------------------------------*/ *---------------------------------------------------------------------*/
void ibmphp_hpc_initvars (void) void __init ibmphp_hpc_initvars (void)
{ {
debug ("%s - Entry\n", __FUNCTION__); debug ("%s - Entry\n", __FUNCTION__);
init_MUTEX (&sem_hpcaccess); init_MUTEX (&sem_hpcaccess);
init_MUTEX (&semOperations); init_MUTEX (&semOperations);
init_MUTEX_LOCKED (&sem_exit); init_MUTEX_LOCKED (&sem_exit);
init_MUTEX_LOCKED (&sem_poll);
stop_polling = POLL_YES;
to_debug = FALSE; to_debug = FALSE;
ibmphp_shutdown = FALSE; ibmphp_shutdown = FALSE;
tid_poll = 0; tid_poll = 0;
...@@ -710,11 +701,6 @@ void free_hpc_access (void) ...@@ -710,11 +701,6 @@ void free_hpc_access (void)
void ibmphp_lock_operations (void) void ibmphp_lock_operations (void)
{ {
down (&semOperations); down (&semOperations);
stop_polling = POLL_NO;
to_debug = TRUE;
/* waiting for polling to actually stop */
down (&sem_poll);
} }
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
...@@ -723,8 +709,6 @@ void ibmphp_lock_operations (void) ...@@ -723,8 +709,6 @@ void ibmphp_lock_operations (void)
void ibmphp_unlock_operations (void) void ibmphp_unlock_operations (void)
{ {
debug ("%s - Entry\n", __FUNCTION__); debug ("%s - Entry\n", __FUNCTION__);
stop_polling = POLL_YES;
to_debug = FALSE;
up (&semOperations); up (&semOperations);
debug ("%s - Exit\n", __FUNCTION__); debug ("%s - Exit\n", __FUNCTION__);
} }
...@@ -732,34 +716,30 @@ void ibmphp_unlock_operations (void) ...@@ -732,34 +716,30 @@ void ibmphp_unlock_operations (void)
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
* Name: poll_hpc() * Name: poll_hpc()
*---------------------------------------------------------------------*/ *---------------------------------------------------------------------*/
#define POLL_LATCH_REGISTER 0
#define POLL_SLOTS 1
#define POLL_SLEEP 2
static void poll_hpc (void) static void poll_hpc (void)
{ {
struct slot myslot, *pslot = NULL; struct slot myslot;
struct slot *pslot = NULL;
struct list_head *pslotlist; struct list_head *pslotlist;
int rc; int rc;
int poll_state = POLL_LATCH_REGISTER;
u8 oldlatchlow = 0x00; u8 oldlatchlow = 0x00;
u8 curlatchlow = 0x00; u8 curlatchlow = 0x00;
int pollcnt = 0; int poll_count = 0;
u8 ctrl_count = 0x00; u8 ctrl_count = 0x00;
debug ("poll_hpc - Entry\n"); debug ("%s - Entry\n", __FUNCTION__);
while (!ibmphp_shutdown) { while (!ibmphp_shutdown) {
if (stop_polling) { /* try to get the lock to do some kind of harware access */
debug ("poll_hpc - stop_polling\n"); down (&semOperations);
up (&sem_poll);
/* to prevent deadlock */
if (ibmphp_shutdown)
break;
/* to make the thread sleep */
down (&semOperations);
up (&semOperations);
debug ("poll_hpc - after stop_polling sleep\n");
} else {
if (pollcnt) {
// only poll the latch register
oldlatchlow = curlatchlow;
switch (poll_state) {
case POLL_LATCH_REGISTER:
oldlatchlow = curlatchlow;
ctrl_count = 0x00; ctrl_count = 0x00;
list_for_each (pslotlist, &ibmphp_slot_head) { list_for_each (pslotlist, &ibmphp_slot_head) {
if (ctrl_count >= ibmphp_get_total_controllers()) if (ctrl_count >= ibmphp_get_total_controllers())
...@@ -773,14 +753,16 @@ static void poll_hpc (void) ...@@ -773,14 +753,16 @@ static void poll_hpc (void)
&curlatchlow); &curlatchlow);
if (oldlatchlow != curlatchlow) if (oldlatchlow != curlatchlow)
process_changeinlatch (oldlatchlow, process_changeinlatch (oldlatchlow,
curlatchlow, pslot->ctrl); curlatchlow,
pslot->ctrl);
} }
} }
} }
} else { poll_state = POLL_SLOTS;
break;
case POLL_SLOTS:
list_for_each (pslotlist, &ibmphp_slot_head) { list_for_each (pslotlist, &ibmphp_slot_head) {
if (stop_polling)
break;
pslot = list_entry (pslotlist, struct slot, ibm_slot_list); pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
// make a copy of the old status // make a copy of the old status
memcpy ((void *) &myslot, (void *) pslot, memcpy ((void *) &myslot, (void *) pslot,
...@@ -791,31 +773,45 @@ static void poll_hpc (void) ...@@ -791,31 +773,45 @@ static void poll_hpc (void)
process_changeinstatus (pslot, &myslot); process_changeinstatus (pslot, &myslot);
} }
if (!stop_polling) { ctrl_count = 0x00;
ctrl_count = 0x00; list_for_each (pslotlist, &ibmphp_slot_head) {
list_for_each (pslotlist, &ibmphp_slot_head) { if (ctrl_count >= ibmphp_get_total_controllers())
if (ctrl_count >= ibmphp_get_total_controllers()) break;
break; pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
pslot = if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
list_entry (pslotlist, struct slot, ctrl_count++;
ibm_slot_list); if (READ_SLOT_LATCH (pslot->ctrl))
if (pslot->ctrl->ctlr_relative_id == ctrl_count) { rc = ibmphp_hpc_readslot (pslot,
ctrl_count++; READ_SLOTLATCHLOWREG,
if (READ_SLOT_LATCH (pslot->ctrl)) &curlatchlow);
rc = ibmphp_hpc_readslot (pslot,
READ_SLOTLATCHLOWREG,
&curlatchlow);
}
} }
} }
} ++poll_count;
INCREMENT_POLLCNT (pollcnt); if (poll_count >= POLL_LATCH_CNT) {
long_delay (POLL_INTERVAL_SEC * HZ); // snooze poll_count = 0;
poll_state = POLL_SLEEP;
}
break;
case POLL_SLEEP:
/* don't sleep with a lock on the hardware */
up (&semOperations);
long_delay (POLL_INTERVAL_SEC * HZ);
down (&semOperations);
poll_state = POLL_LATCH_REGISTER;
break;
} }
/* give up the harware semaphore */
up (&semOperations);
/* sleep for a short time just for good measure */
set_current_state (TASK_INTERRUPTIBLE);
schedule_timeout (HZ/10);
} }
up (&sem_poll);
up (&sem_exit); up (&sem_exit);
debug ("poll_hpc - Exit\n"); debug ("%s - Exit\n", __FUNCTION__);
} }
...@@ -1049,19 +1045,19 @@ static int hpc_poll_thread (void *data) ...@@ -1049,19 +1045,19 @@ static int hpc_poll_thread (void *data)
* *
* Action: start polling thread * Action: start polling thread
*---------------------------------------------------------------------*/ *---------------------------------------------------------------------*/
int ibmphp_hpc_start_poll_thread (void) int __init ibmphp_hpc_start_poll_thread (void)
{ {
int rc = 0; int rc = 0;
debug ("ibmphp_hpc_start_poll_thread - Entry\n"); debug ("%s - Entry\n", __FUNCTION__);
tid_poll = kernel_thread (hpc_poll_thread, 0, 0); tid_poll = kernel_thread (hpc_poll_thread, 0, 0);
if (tid_poll < 0) { if (tid_poll < 0) {
err ("ibmphp_hpc_start_poll_thread - Error, thread not started\n"); err ("%s - Error, thread not started\n", __FUNCTION__);
rc = -1; rc = -1;
} }
debug ("ibmphp_hpc_start_poll_thread - Exit tid_poll[%d] rc[%d]\n", tid_poll, rc); debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
return rc; return rc;
} }
...@@ -1070,9 +1066,9 @@ int ibmphp_hpc_start_poll_thread (void) ...@@ -1070,9 +1066,9 @@ int ibmphp_hpc_start_poll_thread (void)
* *
* Action: stop polling thread and cleanup * Action: stop polling thread and cleanup
*---------------------------------------------------------------------*/ *---------------------------------------------------------------------*/
void ibmphp_hpc_stop_poll_thread (void) void __exit ibmphp_hpc_stop_poll_thread (void)
{ {
debug ("ibmphp_hpc_stop_poll_thread - Entry\n"); debug ("%s - Entry\n", __FUNCTION__);
ibmphp_shutdown = TRUE; ibmphp_shutdown = TRUE;
ibmphp_lock_operations (); ibmphp_lock_operations ();
...@@ -1083,10 +1079,9 @@ void ibmphp_hpc_stop_poll_thread (void) ...@@ -1083,10 +1079,9 @@ void ibmphp_hpc_stop_poll_thread (void)
// cleanup // cleanup
free_hpc_access (); free_hpc_access ();
ibmphp_unlock_operations (); ibmphp_unlock_operations ();
up (&sem_poll);
up (&sem_exit); up (&sem_exit);
debug ("ibmphp_hpc_stop_poll_thread - Exit\n"); debug ("%s - Exit\n", __FUNCTION__);
} }
/*---------------------------------------------------------------------- /*----------------------------------------------------------------------
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/init.h>
#include "ibmphp.h" #include "ibmphp.h"
static int flags = 0; /* for testing */ static int flags = 0; /* for testing */
...@@ -45,7 +46,7 @@ static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); ...@@ -45,7 +46,7 @@ static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
static LIST_HEAD(gbuses); static LIST_HEAD(gbuses);
static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr) static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr)
{ {
struct bus_node * newbus; struct bus_node * newbus;
...@@ -61,7 +62,7 @@ static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr) ...@@ -61,7 +62,7 @@ static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr)
return newbus; return newbus;
} }
static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr) static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr)
{ {
struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
if (!rs) { if (!rs) {
...@@ -77,7 +78,7 @@ static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr) ...@@ -77,7 +78,7 @@ static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr)
return rs; return rs;
} }
static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
{ {
struct bus_node * newbus; struct bus_node * newbus;
struct range_node *newrange; struct range_node *newrange;
...@@ -184,7 +185,7 @@ static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_r ...@@ -184,7 +185,7 @@ static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_r
* Input: ptr to the head of the resource list from EBDA * Input: ptr to the head of the resource list from EBDA
* Output: 0, -1 or error codes * Output: 0, -1 or error codes
***************************************************************************/ ***************************************************************************/
int ibmphp_rsrc_init (void) int __init ibmphp_rsrc_init (void)
{ {
struct ebda_pci_rsrc *curr; struct ebda_pci_rsrc *curr;
struct range_node *newrange = NULL; struct range_node *newrange = NULL;
...@@ -1650,7 +1651,7 @@ void ibmphp_free_resources (void) ...@@ -1650,7 +1651,7 @@ void ibmphp_free_resources (void)
* a new Mem node * a new Mem node
* This routine is called right after initialization * This routine is called right after initialization
*******************************************************************************/ *******************************************************************************/
static int once_over (void) static int __init once_over (void)
{ {
struct resource_node *pfmem_cur; struct resource_node *pfmem_cur;
struct resource_node *pfmem_prev; struct resource_node *pfmem_prev;
...@@ -1871,7 +1872,7 @@ void ibmphp_print_test (void) ...@@ -1871,7 +1872,7 @@ void ibmphp_print_test (void)
* behind them All these are TO DO. * behind them All these are TO DO.
* Also need to add more error checkings... (from fnc returns etc) * Also need to add more error checkings... (from fnc returns etc)
*/ */
static int update_bridge_ranges (struct bus_node **bus) static int __init update_bridge_ranges (struct bus_node **bus)
{ {
u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address; u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address;
u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
...@@ -1885,7 +1886,7 @@ static int update_bridge_ranges (struct bus_node **bus) ...@@ -1885,7 +1886,7 @@ static int update_bridge_ranges (struct bus_node **bus)
bus_cur = *bus; bus_cur = *bus;
busno = bus_cur->busno; busno = bus_cur->busno;
debug ("inside update_bridge_ranges \n"); debug ("inside %s \n", __FUNCTION__);
debug ("bus_cur->busno = %x\n", bus_cur->busno); debug ("bus_cur->busno = %x\n", bus_cur->busno);
for (device = 0; device < 32; device++) { for (device = 0; device < 32; device++) {
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/namei.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "pci_hotplug.h" #include "pci_hotplug.h"
......
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