lkml.org 
[lkml]   [2019]   [Mar]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 1/4] mtd: rawnand: Turn the ONFI support to generic
Date
Fix headers to make way for adding helper functions.

Add onfi helper structure.

Add helper functions in raw NAND core, which later will be used during
ONFI detection.

Signed-off-by: Shivamurthy Shastri <sshivamurthy@micron.com>
---
drivers/mtd/nand/raw/internals.h | 6 +-
drivers/mtd/nand/raw/nand_base.c | 236 ++++++++++++++++++++++++++++---
drivers/mtd/nand/raw/nand_onfi.c | 215 +++++-----------------------
include/linux/mtd/nand.h | 30 ++++
include/linux/mtd/rawnand.h | 5 +
5 files changed, 289 insertions(+), 203 deletions(-)

diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h
index a204f9d7e123..eb34dece4754 100644
--- a/drivers/mtd/nand/raw/internals.h
+++ b/drivers/mtd/nand/raw/internals.h
@@ -90,7 +90,7 @@ int nand_write_page_raw_notsupp(struct nand_chip *chip, const u8 *buf,
int oob_required, int page);
int nand_exit_status_op(struct nand_chip *chip);
int nand_read_param_page_op(struct nand_chip *chip, u8 page, void *buf,
- unsigned int len);
+ unsigned int len);
void nand_decode_ext_id(struct nand_chip *chip);
void panic_nand_wait(struct nand_chip *chip, unsigned long timeo);
void sanitize_string(uint8_t *s, size_t len);
@@ -138,10 +138,6 @@ void nand_legacy_set_defaults(struct nand_chip *chip);
void nand_legacy_adjust_cmdfunc(struct nand_chip *chip);
int nand_legacy_check_hooks(struct nand_chip *chip);

-/* ONFI functions */
-u16 onfi_crc16(u16 crc, u8 const *p, size_t len);
-int nand_onfi_detect(struct nand_chip *chip);
-
/* JEDEC functions */
int nand_jedec_detect(struct nand_chip *chip);

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 0bc898bdb6e1..fc2c7d6ea4f2 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4194,24 +4194,6 @@ static void nand_set_defaults(struct nand_chip *chip)
chip->buf_align = 1;
}

-/* Sanitize ONFI strings so we can safely print them */
-void sanitize_string(uint8_t *s, size_t len)
-{
- ssize_t i;
-
- /* Null terminate */
- s[len - 1] = 0;
-
- /* Remove non printable chars */
- for (i = 0; i < len - 1; i++) {
- if (s[i] < ' ' || s[i] > 127)
- s[i] = '?';
- }
-
- /* Remove trailing spaces */
- strim(s);
-}
-
/*
* nand_id_has_period - Check if an ID string has a given wraparound period
* @id_data: the ID string
@@ -4461,6 +4443,222 @@ nand_manufacturer_name(const struct nand_manufacturer *manufacturer)
return manufacturer ? manufacturer->name : "Unknown";
}

+/* Parse the ONFI parameter Page */
+int nand_onfi_read_op(struct nand_device *base, u8 page, void *buf,
+ unsigned int len)
+{
+ struct nand_chip *chip = device_to_nand(base);
+ struct nand_onfi_params *p = buf;
+ int ret;
+ unsigned int i;
+
+ ret = nand_read_param_page_op(chip, 0, NULL, 0);
+ if (ret)
+ return 0;
+
+ for (i = 0; i < 3; i++) {
+ ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
+ if (ret)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Parse the Extended Parameter Page. */
+static int nand_ext_param_page(struct nand_chip *chip,
+ struct nand_onfi_params *p)
+{
+ struct onfi_ext_param_page *ep;
+ struct onfi_ext_section *s;
+ struct onfi_ext_ecc_info *ecc;
+ u8 *cursor;
+ int ret;
+ int len;
+ int i;
+
+ /*
+ * The nand_flash_detect_ext_param_page() uses the
+ * Change Read Column command which maybe not supported
+ * by the chip->legacy.cmdfunc. So try to update the
+ * chip->legacy.cmdfunc now. We do not replace user supplied
+ * command function.
+ */
+ nand_legacy_adjust_cmdfunc(chip);
+
+ len = le16_to_cpu(p->ext_param_page_length) * 16;
+ ep = kmalloc(len, GFP_KERNEL);
+ if (!ep)
+ return -ENOMEM;
+
+ /* Send our own NAND_CMD_PARAM. */
+ ret = nand_read_param_page_op(chip, 0, NULL, 0);
+ if (ret)
+ goto ext_out;
+
+ /* Use the Change Read Column command to skip the ONFI param pages. */
+ ret = nand_change_read_column_op(chip,
+ sizeof(*p) * p->num_of_param_pages,
+ ep, len, true);
+ if (ret)
+ goto ext_out;
+
+ ret = -EINVAL;
+ if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
+ != le16_to_cpu(ep->crc))) {
+ pr_debug("fail in the CRC.\n");
+ goto ext_out;
+ }
+
+ /*
+ * Check the signature.
+ * Do not strictly follow the ONFI spec, maybe changed in future.
+ */
+ if (strncmp(ep->sig, "EPPS", 4)) {
+ pr_debug("The signature is invalid.\n");
+ goto ext_out;
+ }
+
+ /* find the ECC section. */
+ cursor = (uint8_t *)(ep + 1);
+ for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
+ s = ep->sections + i;
+ if (s->type == ONFI_SECTION_TYPE_2)
+ break;
+ cursor += s->length * 16;
+ }
+ if (i == ONFI_EXT_SECTION_MAX) {
+ pr_debug("We can not find the ECC section.\n");
+ goto ext_out;
+ }
+
+ /* get the info we want. */
+ ecc = (struct onfi_ext_ecc_info *)cursor;
+
+ if (!ecc->codeword_size) {
+ pr_debug("Invalid codeword size\n");
+ goto ext_out;
+ }
+
+ chip->base.ecc.requirements.strength = ecc->ecc_bits;
+ chip->base.ecc.requirements.step_size = 1 << ecc->codeword_size;
+ ret = 0;
+
+ext_out:
+ kfree(ep);
+ return ret;
+}
+
+static int check_onfi_version(struct nand_device *base,
+ struct nand_onfi_params *p, int *onfi_version)
+{
+ struct nand_chip *chip = device_to_nand(base);
+ int val;
+
+ if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
+ chip->manufacturer.desc->ops->fixup_onfi_param_page)
+ chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
+
+ /* Check version */
+ val = le16_to_cpu(p->revision);
+ if (val & ONFI_VERSION_2_3)
+ *onfi_version = 23;
+ else if (val & ONFI_VERSION_2_2)
+ *onfi_version = 22;
+ else if (val & ONFI_VERSION_2_1)
+ *onfi_version = 21;
+ else if (val & ONFI_VERSION_2_0)
+ *onfi_version = 20;
+ else if (val & ONFI_VERSION_1_0)
+ *onfi_version = 10;
+
+ if (!(*onfi_version)) {
+ pr_info("unsupported ONFI version: %d\n", val);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int nand_intf_data(struct nand_device *base, struct nand_onfi_params *p)
+{
+ struct nand_chip *chip = device_to_nand(base);
+ struct onfi_params *onfi;
+ int onfi_version;
+ int ret;
+
+ check_onfi_version(base, p, &onfi_version);
+
+ /* The Extended Parameter Page is supported since ONFI 2.1. */
+ if (onfi_version >= 21 &&
+ (le16_to_cpu(p->features) &
+ ONFI_FEATURE_EXT_PARAM_PAGE)) {
+ if (nand_ext_param_page(chip, p))
+ pr_warn("Failed to detect ONFI extended param page\n");
+ }
+
+ chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
+ if (!chip->parameters.model)
+ return -ENOMEM;
+
+ if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ /* Save some parameters from the parameter page for future use */
+ if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
+ chip->parameters.supports_set_get_features = true;
+ bitmap_set(chip->parameters.get_feature_list,
+ ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+ bitmap_set(chip->parameters.set_feature_list,
+ ONFI_FEATURE_ADDR_TIMING_MODE, 1);
+ }
+
+ onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
+ if (!onfi) {
+ return ret = -ENOMEM;
+ goto free_model;
+ }
+
+ check_onfi_version(base, p, &onfi_version);
+ onfi->version = onfi_version;
+ onfi->tPROG = le16_to_cpu(p->t_prog);
+ onfi->tBERS = le16_to_cpu(p->t_bers);
+ onfi->tR = le16_to_cpu(p->t_r);
+ onfi->tCCS = le16_to_cpu(p->t_ccs);
+ onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
+ onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
+ memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
+ chip->parameters.onfi = onfi;
+
+ return 1;
+
+free_model:
+ kfree(chip->parameters.model);
+
+ return ret;
+}
+
+/*
+ * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
+ */
+int rawnand_onfi_detect(struct nand_chip *chip)
+{
+ char id[4];
+ int ret;
+
+ /* Try ONFI for unknown chip or LP */
+ ret = nand_readid_op(chip, 0x20, id, sizeof(id));
+ if (ret || strncmp(id, "ONFI", 4))
+ return 0;
+
+ chip->base.helper.page = 0;
+ chip->base.helper.check_revision = check_onfi_version;
+ chip->base.helper.parameter_page_read = nand_onfi_read_op;
+ chip->base.helper.init_intf_data = nand_intf_data;
+
+ return nand_onfi_detect(&chip->base);
+}
+
/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
@@ -4556,7 +4754,7 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)

if (!type->name || !type->pagesize) {
/* Check if the chip is ONFI compliant */
- ret = nand_onfi_detect(chip);
+ ret = rawnand_onfi_detect(chip);
if (ret < 0)
return ret;
else if (ret)
diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c
index 9d21b47ebef1..61fcb6994b45 100644
--- a/drivers/mtd/nand/raw/nand_onfi.c
+++ b/drivers/mtd/nand/raw/nand_onfi.c
@@ -13,8 +13,7 @@
*/

#include <linux/slab.h>
-
-#include "internals.h"
+#include <linux/mtd/nand.h>

u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
{
@@ -28,88 +27,13 @@ u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
return crc;
}

-/* Parse the Extended Parameter Page. */
-static int nand_flash_detect_ext_param_page(struct nand_chip *chip,
- struct nand_onfi_params *p)
-{
- struct onfi_ext_param_page *ep;
- struct onfi_ext_section *s;
- struct onfi_ext_ecc_info *ecc;
- uint8_t *cursor;
- int ret;
- int len;
- int i;
-
- len = le16_to_cpu(p->ext_param_page_length) * 16;
- ep = kmalloc(len, GFP_KERNEL);
- if (!ep)
- return -ENOMEM;
-
- /* Send our own NAND_CMD_PARAM. */
- ret = nand_read_param_page_op(chip, 0, NULL, 0);
- if (ret)
- goto ext_out;
-
- /* Use the Change Read Column command to skip the ONFI param pages. */
- ret = nand_change_read_column_op(chip,
- sizeof(*p) * p->num_of_param_pages,
- ep, len, true);
- if (ret)
- goto ext_out;
-
- ret = -EINVAL;
- if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
- != le16_to_cpu(ep->crc))) {
- pr_debug("fail in the CRC.\n");
- goto ext_out;
- }
-
- /*
- * Check the signature.
- * Do not strictly follow the ONFI spec, maybe changed in future.
- */
- if (strncmp(ep->sig, "EPPS", 4)) {
- pr_debug("The signature is invalid.\n");
- goto ext_out;
- }
-
- /* find the ECC section. */
- cursor = (uint8_t *)(ep + 1);
- for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
- s = ep->sections + i;
- if (s->type == ONFI_SECTION_TYPE_2)
- break;
- cursor += s->length * 16;
- }
- if (i == ONFI_EXT_SECTION_MAX) {
- pr_debug("We can not find the ECC section.\n");
- goto ext_out;
- }
-
- /* get the info we want. */
- ecc = (struct onfi_ext_ecc_info *)cursor;
-
- if (!ecc->codeword_size) {
- pr_debug("Invalid codeword size\n");
- goto ext_out;
- }
-
- chip->base.ecc.requirements.strength = ecc->ecc_bits;
- chip->base.ecc.requirements.step_size = 1 << ecc->codeword_size;
- ret = 0;
-
-ext_out:
- kfree(ep);
- return ret;
-}
-
/*
* Recover data with bit-wise majority
*/
-static void nand_bit_wise_majority(const void **srcbufs,
- unsigned int nsrcbufs,
- void *dstbuf,
- unsigned int bufsize)
+void nand_bit_wise_majority(const void **srcbufs,
+ unsigned int nsrcbufs,
+ void *dstbuf,
+ unsigned int bufsize)
{
int i, j, k;

@@ -134,44 +58,49 @@ static void nand_bit_wise_majority(const void **srcbufs,
}
}

+/* Sanitize ONFI strings so we can safely print them */
+void sanitize_string(u8 *s, size_t len)
+{
+ ssize_t i;
+
+ /* Null terminate */
+ s[len - 1] = 0;
+
+ /* Remove non printable chars */
+ for (i = 0; i < len - 1; i++) {
+ if (s[i] < ' ' || s[i] > 127)
+ s[i] = '?';
+ }
+
+ /* Remove trailing spaces */
+ strim(s);
+}
+
/*
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
*/
-int nand_onfi_detect(struct nand_chip *chip)
+int nand_onfi_detect(struct nand_device *base)
{
- struct mtd_info *mtd = nand_to_mtd(chip);
+ struct mtd_info *mtd = &base->mtd;
struct nand_memory_organization *memorg;
struct nand_onfi_params *p;
- struct onfi_params *onfi;
int onfi_version = 0;
- char id[4];
- int i, ret, val;
-
- memorg = nanddev_get_memorg(&chip->base);
+ int i, ret;

- /* Try ONFI for unknown chip or LP */
- ret = nand_readid_op(chip, 0x20, id, sizeof(id));
- if (ret || strncmp(id, "ONFI", 4))
- return 0;
+ memorg = nanddev_get_memorg(base);

/* ONFI chip: allocate a buffer to hold its parameter page */
- p = kzalloc((sizeof(*p) * 3), GFP_KERNEL);
+ p = kzalloc(sizeof(*p) * 3, GFP_KERNEL);
if (!p)
return -ENOMEM;

- ret = nand_read_param_page_op(chip, 0, NULL, 0);
- if (ret) {
- ret = 0;
+ ret = base->helper.parameter_page_read(base, base->helper.page,
+ p, sizeof(*p) * 3);
+ if (!ret) {
goto free_onfi_param_page;
}

for (i = 0; i < 3; i++) {
- ret = nand_read_data_op(chip, &p[i], sizeof(*p), true);
- if (ret) {
- ret = 0;
- goto free_onfi_param_page;
- }
-
if (onfi_crc16(ONFI_CRC_BASE, (u8 *)&p[i], 254) ==
le16_to_cpu(p->crc)) {
if (i)
@@ -194,35 +123,12 @@ int nand_onfi_detect(struct nand_chip *chip)
}
}

- if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
- chip->manufacturer.desc->ops->fixup_onfi_param_page)
- chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p);
-
- /* Check version */
- val = le16_to_cpu(p->revision);
- if (val & ONFI_VERSION_2_3)
- onfi_version = 23;
- else if (val & ONFI_VERSION_2_2)
- onfi_version = 22;
- else if (val & ONFI_VERSION_2_1)
- onfi_version = 21;
- else if (val & ONFI_VERSION_2_0)
- onfi_version = 20;
- else if (val & ONFI_VERSION_1_0)
- onfi_version = 10;
-
- if (!onfi_version) {
- pr_info("unsupported ONFI version: %d\n", val);
+ ret = base->helper.check_revision(base, p, &onfi_version);
+ if (!ret)
goto free_onfi_param_page;
- }

sanitize_string(p->manufacturer, sizeof(p->manufacturer));
sanitize_string(p->model, sizeof(p->model));
- chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
- if (!chip->parameters.model) {
- ret = -ENOMEM;
- goto free_onfi_param_page;
- }

memorg->pagesize = le32_to_cpu(p->byte_per_page);
mtd->writesize = memorg->pagesize;
@@ -248,63 +154,14 @@ int nand_onfi_detect(struct nand_chip *chip)
memorg->max_bad_eraseblocks_per_lun = le32_to_cpu(p->blocks_per_lun);
memorg->bits_per_cell = p->bits_per_cell;

- if (le16_to_cpu(p->features) & ONFI_FEATURE_16_BIT_BUS)
- chip->options |= NAND_BUSWIDTH_16;
-
if (p->ecc_bits != 0xff) {
- chip->base.ecc.requirements.strength = p->ecc_bits;
- chip->base.ecc.requirements.step_size = 512;
- } else if (onfi_version >= 21 &&
- (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
-
- /*
- * The nand_flash_detect_ext_param_page() uses the
- * Change Read Column command which maybe not supported
- * by the chip->legacy.cmdfunc. So try to update the
- * chip->legacy.cmdfunc now. We do not replace user supplied
- * command function.
- */
- nand_legacy_adjust_cmdfunc(chip);
-
- /* The Extended Parameter Page is supported since ONFI 2.1. */
- if (nand_flash_detect_ext_param_page(chip, p))
- pr_warn("Failed to detect ONFI extended param page\n");
- } else {
- pr_warn("Could not retrieve ONFI ECC requirements\n");
+ base->ecc.requirements.strength = p->ecc_bits;
+ base->ecc.requirements.step_size = 512;
}

- /* Save some parameters from the parameter page for future use */
- if (le16_to_cpu(p->opt_cmd) & ONFI_OPT_CMD_SET_GET_FEATURES) {
- chip->parameters.supports_set_get_features = true;
- bitmap_set(chip->parameters.get_feature_list,
- ONFI_FEATURE_ADDR_TIMING_MODE, 1);
- bitmap_set(chip->parameters.set_feature_list,
- ONFI_FEATURE_ADDR_TIMING_MODE, 1);
- }
-
- onfi = kzalloc(sizeof(*onfi), GFP_KERNEL);
- if (!onfi) {
- ret = -ENOMEM;
- goto free_model;
- }
-
- onfi->version = onfi_version;
- onfi->tPROG = le16_to_cpu(p->t_prog);
- onfi->tBERS = le16_to_cpu(p->t_bers);
- onfi->tR = le16_to_cpu(p->t_r);
- onfi->tCCS = le16_to_cpu(p->t_ccs);
- onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode);
- onfi->vendor_revision = le16_to_cpu(p->vendor_revision);
- memcpy(onfi->vendor, p->vendor, sizeof(p->vendor));
- chip->parameters.onfi = onfi;
+ ret = base->helper.init_intf_data(base, p);

/* Identification done, free the full ONFI parameter page and exit */
- kfree(p);
-
- return 1;
-
-free_model:
- kfree(chip->parameters.model);
free_onfi_param_page:
kfree(p);

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index b3a5506a891b..3f7e2b495e93 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -13,6 +13,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand-ecc-sw-hamming.h>
#include <linux/mtd/nand-ecc-sw-bch.h>
+#include <linux/mtd/onfi.h>

struct nand_device;

@@ -269,6 +270,24 @@ struct nand_ecc {
struct nand_ecc_engine *engine;
};

+/**
+ * struct onfi_helper - ONFI helper functions that should be implemented by
+ * specialized layers (raw NAND, SPI NAND, etc.)
+ * @page: Page number for ONFI parameter table
+ * @check_revision: Check ONFI revision number
+ * @parameter_page_read: Function to read parameter pages
+ * @init_intf_data: Initialize interface specific data or fixups
+ */
+struct onfi_helper {
+ u8 page;
+ int (*check_revision)(struct nand_device *base,
+ struct nand_onfi_params *p, int *onfi_version);
+ int (*parameter_page_read)(struct nand_device *base, u8 page,
+ void *buf, unsigned int len);
+ int (*init_intf_data)(struct nand_device *base,
+ struct nand_onfi_params *p);
+};
+
/**
* struct nand_device - NAND device
* @mtd: MTD instance attached to the NAND device
@@ -276,6 +295,7 @@ struct nand_ecc {
* @rowconv: position to row address converter
* @bbt: bad block table info
* @ops: NAND operations attached to the NAND device
+ * @helper: Helper functions to detect and initialize ONFI NAND
*
* Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND)
* should declare their own NAND object embedding a nand_device struct (that's
@@ -294,6 +314,7 @@ struct nand_device {
struct nand_row_converter rowconv;
struct nand_bbt bbt;
const struct nand_ops *ops;
+ struct onfi_helper helper;
};

/**
@@ -888,4 +909,13 @@ static inline bool nanddev_bbt_is_initialized(struct nand_device *nand)
int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo);
int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len);

+/* ONFI functions */
+u16 onfi_crc16(u16 crc, u8 const *p, size_t len);
+void nand_bit_wise_majority(const void **srcbufs,
+ unsigned int nsrcbufs,
+ void *dstbuf,
+ unsigned int bufsize);
+void sanitize_string(u8 *s, size_t len);
+int nand_onfi_detect(struct nand_device *base);
+
#endif /* __LINUX_MTD_NAND_H */
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 174d2d27200f..bcb18cade2e8 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -1079,6 +1079,11 @@ static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip)
return &chip->base.mtd;
}

+static inline struct nand_chip *device_to_nand(struct nand_device *base)
+{
+ return container_of(base, struct nand_chip, base);
+}
+
static inline void *nand_get_controller_data(struct nand_chip *chip)
{
return chip->priv;
--
2.17.1
\
 
 \ /
  Last update: 2019-03-26 11:52    [W:0.063 / U:0.240 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site