Commit dd391066 authored by Jes Sorensen's avatar Jes Sorensen Committed by Jeff Garzik

acenic net driver update:

* PCI write posting fixes, remove pa-specific code
* support 2.5.x kernels (synchronize_irq, cli/sti cleanups)
parent 1d462e8d
......@@ -47,6 +47,7 @@
* flushing the Jumbo ring.
* Hans Grobler <grobh@sun.ac.za>: Memory leak fixes in the
* driver init path.
* Grant Grundler <grundler@cup.hp.com>: PCI write posting fixes.
*/
#include <linux/config.h>
......@@ -120,6 +121,9 @@
#ifndef PCI_DEVICE_ID_FARALLON_PN9000SX
#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a
#endif
#ifndef PCI_DEVICE_ID_FARALLON_PN9100T
#define PCI_DEVICE_ID_FARALLON_PN9100T 0xfa
#endif
#ifndef PCI_VENDOR_ID_SGI
#define PCI_VENDOR_ID_SGI 0x10a9
#endif
......@@ -140,10 +144,13 @@ static struct pci_device_id acenic_pci_tbl[] __initdata = {
{ PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T,
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
/*
* Farallon used the DEC vendor ID on their cards incorrectly.
* Farallon used the DEC vendor ID on their cards incorrectly,
* then later Alteon's ID.
*/
{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX,
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_FARALLON_PN9100T,
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC,
PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
{ }
......@@ -173,14 +180,26 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
#endif
#ifndef SET_MODULE_OWNER
#define SET_MODULE_OWNER(dev) {do{} while(0);}
#define SET_MODULE_OWNER(dev) do{} while(0)
#define ACE_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
#define ACE_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
#else
#define ACE_MOD_INC_USE_COUNT {do{} while(0);}
#define ACE_MOD_DEC_USE_COUNT {do{} while(0);}
#define ACE_MOD_INC_USE_COUNT do{} while(0)
#define ACE_MOD_DEC_USE_COUNT do{} while(0)
#endif
#if LINUX_VERSION_CODE >= 0x2051c
#define ace_sync_irq(irq) synchronize_irq(irq)
#else
#define ace_sync_irq(irq) synchronize_irq()
#endif
#if LINUX_VERSION_CODE < 0x2051e
#define local_irq_save(flags) do{__save_flags(flags) ; \
__cli();} while(0)
#define local_irq_restore(flags) __restore_flags(flags)
#endif
#if (LINUX_VERSION_CODE < 0x02030d)
#define pci_resource_start(dev, bar) dev->base_address[bar]
......@@ -192,6 +211,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
#define net_device device
#endif
#if (LINUX_VERSION_CODE < 0x02032a)
typedef u32 dma_addr_t;
......@@ -215,8 +235,6 @@ static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
(((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO)
#define pci_dma_supported(dev, mask) \
(((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0)
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
#elif (LINUX_VERSION_CODE < 0x02040d)
......@@ -240,8 +258,15 @@ pci_map_page(struct pci_dev *cookie, struct page *page, unsigned long off,
}
#define pci_unmap_page(cookie, dma_addr, size, dir) \
pci_unmap_single(cookie, dma_addr, size, dir)
#endif
#if (LINUX_VERSION_CODE < 0x020412)
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
#define pci_unmap_addr(PTR, ADDR_NAME) 0
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do{} while(0)
#define pci_unmap_len(PTR, LEN_NAME) 0
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do{} while(0)
#endif
......@@ -259,7 +284,7 @@ pci_map_page(struct pci_dev *cookie, struct page *page, unsigned long off,
#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy)
#define netif_stop_queue(dev) set_bit(0, &dev->tbusy)
#define late_stop_netif_stop_queue(dev) {do{} while(0);}
#define late_stop_netif_stop_queue(dev) do{} while(0)
#define early_stop_netif_stop_queue(dev) test_and_set_bit(0,&dev->tbusy)
#define early_stop_netif_wake_queue(dev) netif_wake_queue(dev)
......@@ -273,7 +298,7 @@ static inline void netif_start_queue(struct net_device *dev)
#define ace_mark_net_bh() mark_bh(NET_BH)
#define netif_queue_stopped(dev) dev->tbusy
#define netif_running(dev) dev->start
#define ace_if_down(dev) {do{dev->start = 0;} while(0);}
#define ace_if_down(dev) do{dev->start = 0;} while(0)
#define tasklet_struct tq_struct
static inline void tasklet_schedule(struct tasklet_struct *tasklet)
......@@ -291,13 +316,13 @@ static inline void tasklet_init(struct tasklet_struct *tasklet,
tasklet->routine = (void (*)(void *))func;
tasklet->data = (void *)data;
}
#define tasklet_kill(tasklet) {do{} while(0);}
#define tasklet_kill(tasklet) do{} while(0)
#else
#define late_stop_netif_stop_queue(dev) netif_stop_queue(dev)
#define early_stop_netif_stop_queue(dev) 0
#define early_stop_netif_wake_queue(dev) {do{} while(0);}
#define ace_mark_net_bh() {do{} while(0);}
#define ace_if_down(dev) {do{} while(0);}
#define early_stop_netif_wake_queue(dev) do{} while(0)
#define ace_mark_net_bh() do{} while(0)
#define ace_if_down(dev) do{} while(0)
#endif
#if (LINUX_VERSION_CODE >= 0x02031b)
......@@ -313,7 +338,7 @@ static inline void tasklet_init(struct tasklet_struct *tasklet,
#ifndef ARCH_HAS_PREFETCHW
#ifndef prefetchw
#define prefetchw(x) {do{} while(0);}
#define prefetchw(x) do{} while(0)
#endif
#endif
......@@ -568,7 +593,7 @@ static int tx_ratio[ACE_MAX_MOD_PARMS];
static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
static char version[] __initdata =
"acenic.c: v0.89 03/15/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
"acenic.c: v0.92 08/05/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
" http://home.cern.ch/~jes/gige/acenic.html\n";
static struct net_device *root_dev;
......@@ -611,6 +636,8 @@ int __devinit acenic_probe (ACE_PROBE_ARG)
*/
!((pdev->vendor == PCI_VENDOR_ID_DEC) &&
(pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) &&
!((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
(pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T)) &&
!((pdev->vendor == PCI_VENDOR_ID_SGI) &&
(pdev->device == PCI_DEVICE_ID_SGI_ACENIC)))
continue;
......@@ -664,6 +691,11 @@ int __devinit acenic_probe (ACE_PROBE_ARG)
printk(version);
}
if (pci_enable_device(pdev)) {
kfree(dev);
continue;
}
/*
* Enable master mode before we start playing with the
* pci_command word since pci_set_master() will modify
......@@ -708,9 +740,17 @@ int __devinit acenic_probe (ACE_PROBE_ARG)
switch(pdev->vendor) {
case PCI_VENDOR_ID_ALTEON:
if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) {
strncpy(ap->name, "Farallon PN9100-T "
"Gigabit Ethernet", sizeof (ap->name));
printk(KERN_INFO "%s: Farallon PN9100-T ",
dev->name);
} else {
strncpy(ap->name, "AceNIC Gigabit Ethernet",
sizeof (ap->name));
printk(KERN_INFO "%s: Alteon AceNIC ", dev->name);
printk(KERN_INFO "%s: Alteon AceNIC ",
dev->name);
}
break;
case PCI_VENDOR_ID_3COM:
strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
......@@ -846,6 +886,7 @@ static void __exit ace_module_cleanup(void)
* This clears any pending interrupts
*/
writel(1, &regs->Mb0Lo);
readl(&regs->CpuCtrl); /* flush */
/*
* Make sure no other CPUs are processing interrupts
......@@ -856,7 +897,7 @@ static void __exit ace_module_cleanup(void)
* Then release the RX buffers - jumbo buffers were
* already released in ace_close().
*/
synchronize_irq();
ace_sync_irq(root_dev->irq);
for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
......@@ -1138,34 +1179,30 @@ static int __init ace_init(struct net_device *dev)
* to any crashes involving the NIC
*/
writel(HW_RESET | (HW_RESET << 24), &regs->HostCtrl);
wmb();
readl(&regs->HostCtrl); /* PCI write posting */
udelay(5);
/*
* Don't access any other registes before this point!
* Don't access any other registers before this point!
*/
#ifdef __BIG_ENDIAN
/*
* This will most likely need BYTE_SWAP once we switch
* to using __raw_writel()
*/
#ifdef __parisc__
writel((WORD_SWAP | BYTE_SWAP | CLR_INT |
((WORD_SWAP | BYTE_SWAP | CLR_INT) << 24)),
&regs->HostCtrl);
#else
writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)),
&regs->HostCtrl);
#endif
#else
writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)),
&regs->HostCtrl);
#endif
mb();
readl(&regs->HostCtrl); /* PCI write posting */
/*
* Stop the NIC CPU and clear pending interrupts
*/
writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
readl(&regs->CpuCtrl); /* PCI write posting */
writel(0, &regs->Mb0Lo);
tig_ver = readl(&regs->HostCtrl) >> 28;
......@@ -1186,6 +1223,7 @@ static int __init ace_init(struct net_device *dev)
tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor,
tigon2FwReleaseFix);
writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
readl(&regs->CpuBCtrl); /* PCI write posting */
/*
* The SRAM bank size does _not_ indicate the amount
* of memory on the card, it controls the _bank_ size!
......@@ -1217,7 +1255,7 @@ static int __init ace_init(struct net_device *dev)
writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL |
ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
#endif
mb();
readl(&regs->ModeStat); /* PCI write posting */
mac1 = 0;
for(i = 0; i < 4; i++) {
......@@ -1355,7 +1393,7 @@ static int __init ace_init(struct net_device *dev)
tmp &= ~DMA_READ_WRITE_MASK;
tmp |= DMA_READ_MAX_128;
/*
* All the docs sy MUST NOT. Well, I did.
* All the docs say MUST NOT. Well, I did.
* Nothing terrible happens, if we load wrong size.
* Bit w&i still works better!
*/
......@@ -1364,6 +1402,13 @@ static int __init ace_init(struct net_device *dev)
writel(tmp, &regs->PciState);
#if 0
/*
* The Host PCI bus controller driver has to set FBB.
* If all devices on that PCI bus support FBB, then the controller
* can enable FBB support in the Host PCI Bus controller (or on
* the PCI-PCI bridge if that applies).
* -ggg
*/
/*
* I have received reports from people having problems when this
* bit is enabled.
......@@ -1445,9 +1490,9 @@ static int __init ace_init(struct net_device *dev)
set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring_dma);
info->evt_ctrl.flags = 0;
set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma);
*(ap->evt_prd) = 0;
wmb();
set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma);
writel(0, &regs->EvtCsm);
set_aceaddr(&info->cmd_ctrl.rngptr, 0x100);
......@@ -1579,7 +1624,13 @@ static int __init ace_init(struct net_device *dev)
writel(0, &regs->MaskInt);
writel(1, &regs->IfIdx);
#if 0
/*
* McKinley boxes do not like us fiddling with AssistState
* this early
*/
writel(1, &regs->AssistState);
#endif
writel(DEF_STAT, &regs->TuneStatTicks);
writel(DEF_TRACE, &regs->TuneTrace);
......@@ -1689,10 +1740,19 @@ static int __init ace_init(struct net_device *dev)
*/
memset(&ap->stats, 0, sizeof(ap->stats));
/*
* Enable DMA engine now.
* If we do this sooner, Mckinley box pukes.
* I assume it's because Tigon II DMA engine wants to check
* *something* even before the CPU is started.
*/
writel(1, &regs->AssistState); /* enable DMA */
/*
* Start the NIC CPU
*/
writel(readl(&regs->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), &regs->CpuCtrl);
readl(&regs->CpuCtrl);
/*
* Wait for the firmware to spin up - max 3 seconds.
......@@ -1705,6 +1765,7 @@ static int __init ace_init(struct net_device *dev)
ace_dump_trace(ap);
writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
readl(&regs->CpuCtrl);
/* aman@sgi.com - account for badly behaving firmware/NIC:
* - have observed that the NIC may continue to generate
......@@ -1719,6 +1780,7 @@ static int __init ace_init(struct net_device *dev)
writel(readl(&regs->CpuBCtrl) | CPU_HALT,
&regs->CpuBCtrl);
writel(0, &regs->Mb0Lo);
readl(&regs->Mb0Lo);
ecode = -EBUSY;
goto init_error;
......@@ -2393,6 +2455,7 @@ static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
* threads and it is wrong even for that case.
*/
writel(0, &regs->Mb0Lo);
readl(&regs->Mb0Lo);
/*
* There is no conflict between transmit handling in
......@@ -2496,12 +2559,13 @@ static void ace_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
struct ace_private *ap = dev->priv;
unsigned long flags;
save_flags(flags);
cli();
local_irq_save(flags);
ace_mask_irq(dev);
ap->vlgrp = grp;
restore_flags(flags);
ace_unmask_irq(dev);
local_irq_restore(flags);
}
......@@ -2510,13 +2574,14 @@ static void ace_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
struct ace_private *ap = dev->priv;
unsigned long flags;
save_flags(flags);
cli();
local_irq_save(flags);
ace_mask_irq(dev);
if (ap->vlgrp)
ap->vlgrp->vlan_devices[vid] = NULL;
restore_flags(flags);
ace_unmask_irq(dev);
local_irq_restore(flags);
}
#endif /* ACENIC_DO_VLAN */
......@@ -2620,8 +2685,9 @@ static int ace_close(struct net_device *dev)
* Make sure one CPU is not processing packets while
* buffers are being released by another.
*/
save_flags(flags);
cli();
local_irq_save(flags);
ace_mask_irq(dev);
for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) {
struct sk_buff *skb;
......@@ -2658,7 +2724,8 @@ static int ace_close(struct net_device *dev)
ace_issue_cmd(regs, &cmd);
}
restore_flags(flags);
ace_unmask_irq(dev);
local_irq_restore(flags);
ACE_MOD_DEC_USE_COUNT;
return 0;
......@@ -2877,7 +2944,7 @@ static int ace_change_mtu(struct net_device *dev, int new_mtu)
}
} else {
while (test_and_set_bit(0, &ap->jumbo_refill_busy));
synchronize_irq();
ace_sync_irq(dev->irq);
ace_set_rxtx_parms(dev, 0);
if (ap->jumbo) {
struct cmd cmd;
......@@ -3259,22 +3326,27 @@ static void __init eeprom_start(struct ace_regs *regs)
{
u32 local;
readl(&regs->LocalCtrl);
udelay(ACE_SHORT_DELAY);
local = readl(&regs->LocalCtrl);
local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
}
......@@ -3289,6 +3361,7 @@ static void __init eeprom_prep(struct ace_regs *regs, u8 magic)
local &= ~EEPROM_DATA_OUT;
local |= EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
for (i = 0; i < 8; i++, magic <<= 1) {
......@@ -3298,15 +3371,18 @@ static void __init eeprom_prep(struct ace_regs *regs, u8 magic)
else
local &= ~EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
}
}
......@@ -3320,10 +3396,12 @@ static int __init eeprom_check_ack(struct ace_regs *regs)
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_LONG_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
/* sample data in middle of high clk */
......@@ -3331,6 +3409,7 @@ static int __init eeprom_check_ack(struct ace_regs *regs)
udelay(ACE_SHORT_DELAY);
mb();
writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
return state;
......@@ -3345,18 +3424,22 @@ static void __init eeprom_stop(struct ace_regs *regs)
local = readl(&regs->LocalCtrl);
local |= EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
local &= ~EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
local |= EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_LONG_DELAY);
local &= ~EEPROM_CLK_OUT;
......@@ -3433,10 +3516,12 @@ static int __init read_eeprom_byte(struct net_device *dev,
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
udelay(ACE_LONG_DELAY);
mb();
local |= EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
/* sample data mid high clk */
......@@ -3447,11 +3532,13 @@ static int __init read_eeprom_byte(struct net_device *dev,
local = readl(&regs->LocalCtrl);
local &= ~EEPROM_CLK_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
udelay(ACE_SHORT_DELAY);
mb();
if (i == 7) {
local |= EEPROM_WRITE_ENABLE;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
}
......@@ -3459,11 +3546,14 @@ static int __init read_eeprom_byte(struct net_device *dev,
local |= EEPROM_DATA_OUT;
writel(local, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
writel(readl(&regs->LocalCtrl) | EEPROM_CLK_OUT, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
udelay(ACE_LONG_DELAY);
writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
readl(&regs->LocalCtrl);
mb();
udelay(ACE_SHORT_DELAY);
eeprom_stop(regs);
......
......@@ -748,6 +748,32 @@ static inline void ace_set_txprd(struct ace_regs *regs,
}
static inline void ace_mask_irq(struct net_device *dev)
{
struct ace_private *ap = dev->priv;
struct ace_regs *regs = ap->regs;
if (ACE_IS_TIGON_I(ap))
writel(1, &regs->MaskInt);
else
writel(readl(&regs->HostCtrl) | MASK_INTS, &regs->HostCtrl);
ace_sync_irq(dev->irq);
}
static inline void ace_unmask_irq(struct net_device *dev)
{
struct ace_private *ap = dev->priv;
struct ace_regs *regs = ap->regs;
if (ACE_IS_TIGON_I(ap))
writel(0, &regs->MaskInt);
else
writel(readl(&regs->HostCtrl) &= ~MASK_INTS, &regs->HostCtrl);
}
/*
* Prototypes
*/
......
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