/* Copyright 2009-2011 Freescale Semiconductor, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Freescale Semiconductor nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * * ALTERNATIVELY, this software may be distributed under the terms of the * GNU General Public License ("GPL") as published by the Free Software * Foundation, either version 2 of that License or (at your option) any * later version. * * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pme2_test.h" static u8 pme_db[] = { 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rev 2.2 */ /* 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x48, 0x41, 0x40, 0x20, 0x00, 0x11, */ /* Rev 2.1 */ 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x90, 0x41, 0x40, 0x20, 0x00, 0x11, /* Rev 2.0 */ /* 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x20, 0x41, 0x40, 0x20, 0x00, 0x11, */ 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rev 2.0 */ /* 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x48, 0x41, 0xff, 0x81, 0x00, 0x00, */ /* Rev 2.1 */ 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x90, 0x41, 0xff, 0x81, 0x00, 0x00, /* Rev 2.0 */ /* 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x20, 0x41, 0xff, 0x81, 0x00, 0x00, */ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0x01, 0xff, 0x80, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; static u8 db_read[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rev 2.2 */ /* 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x48, 0x41 */ /* Rev 2.1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x90, 0x41 /* Rev 2.0 */ /* 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x20, 0x41 */ }; static u8 db_read_expected_result[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, /* Rev 2.2 */ /* 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x48, 0x41, 0x40, 0x20, 0x00, 0x11*/ /* Rev 2.1 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x90, 0x41, 0x40, 0x20, 0x00, 0x11 /* Rev 2.0 */ /* 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x20, 0x41, 0x40, 0x20, 0x00, 0x11*/ }; struct pmtcc_ctx { struct pme_ctx base_ctx; struct qm_fd result_fd; struct completion done; u8 ern; }; static void pmtcc_cb(struct pme_ctx *ctx, const struct qm_fd *fd, struct pme_ctx_token *ctx_token) { struct pmtcc_ctx *my_ctx = (struct pmtcc_ctx *)ctx; memcpy(&my_ctx->result_fd, fd, sizeof(*fd)); complete(&my_ctx->done); } static void pmtcc_ern_cb(struct pme_ctx *ctx, const struct qm_mr_entry *mr, struct pme_ctx_token *ctx_token) { struct pmtcc_ctx *my_ctx = (struct pmtcc_ctx *)ctx; my_ctx->result_fd = mr->ern.fd; my_ctx->ern = 1; complete(&my_ctx->done); } #define FIRST_PMTCC 56 int pme2_clear_sample_db(void) { struct pmtcc_ctx ctx = { .base_ctx.cb = pmtcc_cb, .base_ctx.ern_cb = pmtcc_ern_cb, .ern = 0 }; struct qm_fd fd; int ret = 0; enum pme_status status; struct pme_ctx_token token; void *mem; struct cpumask backup_mask = current->cpus_allowed; struct cpumask new_mask = *qman_affine_cpus(); cpumask_and(&new_mask, &new_mask, bman_affine_cpus()); ret = set_cpus_allowed_ptr(current, &new_mask); if (ret) { pr_info("cleanr_sample_db: can't set cpumask\n"); goto _clear_0; } init_completion(&ctx.done); ret = pme_ctx_init(&ctx.base_ctx, PME_CTX_FLAG_EXCLUSIVE | PME_CTX_FLAG_PMTCC | PME_CTX_FLAG_LOCAL, 0, 4, 4, 0, NULL); if (ret) { pr_err("clear_sample_db: can't init ctx\n"); goto _clear_1; } /* enable the context */ ret = pme_ctx_enable(&ctx.base_ctx); if (ret) { pr_err("clear_sample_db: can't enable ctx\n"); goto _clear_2; } /* Write the database */ memset(&fd, 0, sizeof(struct qm_fd)); mem = kmalloc(FIRST_PMTCC, GFP_KERNEL); if (!mem) goto _clear_3; memcpy(mem, pme_db, FIRST_PMTCC); fd.length20 = FIRST_PMTCC; qm_fd_addr_set64(&fd, pme_map(mem)); ret = pme_ctx_pmtcc(&ctx.base_ctx, PME_CTX_OP_WAIT, &fd, &token); if (ret == -ENODEV) { pr_err("clear_sample_db: not the control plane, bailing\n"); goto _clear_4; } if (ret) { pr_err("clear_sample_db: error with pmtcc\n"); goto _clear_4; } wait_for_completion(&ctx.done); if (ctx.ern) { pr_err("clear_sample_db: Rx ERN from pmtcc\n"); goto _clear_4; } status = pme_fd_res_status(&ctx.result_fd); if (status) { pr_info("clear_sample_db: PMTCC write status failed %d\n", status); goto _clear_4; } _clear_4: kfree(mem); _clear_3: /* Disable */ ret = pme_ctx_disable(&ctx.base_ctx, PME_CTX_OP_WAIT | PME_CTX_OP_WAIT_INT, NULL); _clear_2: pme_ctx_finish(&ctx.base_ctx); _clear_1: ret = set_cpus_allowed_ptr(current, &backup_mask); if (ret) pr_info("clear_sample_db: can't restore cpumask"); _clear_0: if (!ret) pr_info("clear_sample_db: Done\n"); else pr_info("clear_sample_db: Error 0x%x\n", ret); return ret; } int pme2_sample_db(void) { struct pmtcc_ctx ctx = { .base_ctx.cb = pmtcc_cb, .base_ctx.ern_cb = pmtcc_ern_cb, .ern = 0 }; struct qm_fd fd; struct qm_sg_entry *sg_table = NULL; int ret = 0; enum pme_status status; struct pme_ctx_token token; void *mem = NULL, *mem_result = NULL; u32 pme_rev; struct cpumask backup_mask = current->cpus_allowed; struct cpumask new_mask = *qman_affine_cpus(); cpumask_and(&new_mask, &new_mask, bman_affine_cpus()); ret = set_cpus_allowed_ptr(current, &new_mask); if (ret) { pr_info("sample_db: can't set cpumask\n"); goto _finish_0; } ret = pme_attr_get(pme_attr_rev1, &pme_rev); if (ret) { pr_err("sample_db: can't read pme revision %d\n", ret); goto _finish_1; } /* If Rev 2.0, Rev 2.2...update database */ switch (pme_rev & 0x0000FFFF) { case 0x00000200: pr_info("sample_db: db for pme ver 2.0\n"); pme_db[133] = 0x01; pme_db[134] = 0x20; pme_db[161] = 0x01; pme_db[162] = 0x20; db_read[21] = 0x01; db_read[22] = 0x20; db_read_expected_result[21] = 0x01; db_read_expected_result[22] = 0x20; break; case 0x00000201: pr_info("sample_db: db for pme ver 2.1\n"); break; case 0x00000202: pr_info("sample_db: db for pme ver 2.2\n"); pme_db[134] = 0x48; pme_db[162] = 0x48; db_read[22] = 0x48; db_read_expected_result[22] = 0x48; break; default: pr_err("sample_db: Unknown pme hw ver 0x%x\n", pme_rev & 0x0000FFFF); ret = -ENODEV; goto _finish_1; } init_completion(&ctx.done); ret = pme_ctx_init(&ctx.base_ctx, PME_CTX_FLAG_EXCLUSIVE | PME_CTX_FLAG_PMTCC | PME_CTX_FLAG_LOCAL, 0, 4, 4, 0, NULL); if (ret) { pr_err("sample_db: can't init ctx\n"); goto _finish_1; } /* enable the context */ ret = pme_ctx_enable(&ctx.base_ctx); if (ret) { pr_err("sample_db: can't enable ctx\n"); goto _finish_2; } /* Write the database */ memset(&fd, 0, sizeof(struct qm_fd)); mem = kmalloc(sizeof(pme_db), GFP_KERNEL); if (!mem) goto _finish_3; memcpy(mem, pme_db, sizeof(pme_db)); fd.length20 = sizeof(pme_db); qm_fd_addr_set64(&fd, pme_map(mem)); ret = pme_ctx_pmtcc(&ctx.base_ctx, PME_CTX_OP_WAIT, &fd, &token); if (ret == -ENODEV) { pr_err("sample_db: not the control plane, bailing\n"); goto _finish_4; } if (ret) { pr_err("sample_db: error with pmtcc\n"); goto _finish_4; } wait_for_completion(&ctx.done); if (ctx.ern) { pr_err("sample_db: Rx ERN from pmtcc\n"); goto _finish_4; } status = pme_fd_res_status(&ctx.result_fd); if (status) { pr_info("sample_db: PMTCC write status failed %d\n", status); goto _finish_4; } kfree(mem); mem = NULL; /* Read back the database */ init_completion(&ctx.done); memset(&fd, 0, sizeof(struct qm_fd)); sg_table = kzalloc(2 * sizeof(*sg_table), GFP_KERNEL | GFP_DMA); mem_result = kmalloc(28, GFP_KERNEL); mem = kmalloc(sizeof(db_read), GFP_KERNEL); if (!sg_table || !mem || !mem_result) { pr_err("sample_db: out of memory\n"); ret = -ENOMEM; goto _finish_4; } memcpy(mem, db_read, sizeof(db_read)); qm_sg_entry_set64(&sg_table[0], pme_map(mem_result)); sg_table[0].length = 28; qm_sg_entry_set64(&sg_table[1], pme_map(mem)); sg_table[1].length = sizeof(db_read); sg_table[1].final = 1; fd.format = qm_fd_compound; qm_fd_addr_set64(&fd, pme_map(sg_table)); ret = pme_ctx_pmtcc(&ctx.base_ctx, PME_CTX_OP_WAIT, &fd, &token); if (ret) { pr_err("sample_db: error with pmtcc\n"); goto _finish_4; } wait_for_completion(&ctx.done); if (ctx.ern) { ret = -EINVAL; pr_err("sample_db: Rx ERN from pmtcc\n"); goto _finish_4; } status = pme_fd_res_status(&ctx.result_fd); if (status) { ret = -EINVAL; pr_err("sample_db: PMTCC read status failed %d\n", status); goto _finish_4; } if (pme_fd_res_flags(&ctx.result_fd) & PME_STATUS_UNRELIABLE) { pr_err("sample_db: flags result set %x\n", pme_fd_res_flags(&ctx.result_fd)); ret = -EINVAL; goto _finish_4; } if (memcmp(db_read_expected_result, mem_result, 28) != 0) { pr_err("sample_db: DB read result not expected\n"); pr_err("Expected\n"); hexdump(db_read_expected_result, sizeof(db_read_expected_result)); pr_info("Received\n"); hexdump(mem_result, 28); ret = -EINVAL; } _finish_4: kfree(mem_result); kfree(sg_table); kfree(mem); _finish_3: /* Disable */ ret = pme_ctx_disable(&ctx.base_ctx, PME_CTX_OP_WAIT | PME_CTX_OP_WAIT_INT, NULL); _finish_2: pme_ctx_finish(&ctx.base_ctx); _finish_1: if (ret) set_cpus_allowed_ptr(current, &backup_mask); else { ret = set_cpus_allowed_ptr(current, &backup_mask); if (ret) pr_info("sample_db: can't restore cpumask"); } _finish_0: if (!ret) pr_info("pme: sample DB initialised\n"); else pr_info("pme: Error during sample DB 0x%x\n", ret); return ret; }