* [PATCH 8/14] powerpc: add ps3 platform repository support
@ 2006-11-22 4:20 Geoff Levand
2006-12-01 14:25 ` cast truncates bits from constant value (8000000000000000 becomes 0) Geert Uytterhoeven
0 siblings, 1 reply; 13+ messages in thread
From: Geoff Levand @ 2006-11-22 4:20 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
From: Geoff Levand <geoffrey.levand@am.sony.com>
Adds support for the PS3 repository.
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
---
arch/powerpc/platforms/ps3/repository.c | 840 ++++++++++++++++++++++++++++++++
include/asm-powerpc/ps3.h | 139 +++++
2 files changed, 979 insertions(+)
Index: cell--common--6/arch/powerpc/platforms/ps3/repository.c
===================================================================
--- /dev/null
+++ cell--common--6/arch/powerpc/platforms/ps3/repository.c
@@ -0,0 +1,840 @@
+/*
+ * PS3 repository routines.
+ *
+ * Copyright (C) 2006 Sony Computer Entertainment Inc.
+ * Copyright 2006 Sony Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/ps3.h>
+#include <asm/lv1call.h>
+
+enum ps3_vendor_id {
+ PS3_VENDOR_ID_NONE = 0,
+ PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
+};
+
+enum ps3_lpar_id {
+ PS3_LPAR_ID_CURRENT = 0,
+ PS3_LPAR_ID_PME = 1,
+};
+
+#define dump_field(_a, _b) _dump_field(_a, _b, __func__, __LINE__)
+static void _dump_field(const char *hdr, u64 n, const char* func, int line)
+{
+#if defined(DEBUG)
+ char s[16];
+ const char *const in = (const char *)&n;
+ unsigned int i;
+
+ for (i = 0; i < 8; i++)
+ s[i] = (in[i] <= 126 && in[i] >= 32) ? in[i] : '.';
+ s[i] = 0;
+
+ pr_debug("%s:%d: %s%016lx : %s\n", func, line, hdr, n, s);
+#endif
+}
+
+#define dump_node_name(_a, _b, _c, _d, _e) \
+ _dump_node_name(_a, _b, _c, _d, _e, __func__, __LINE__)
+static void _dump_node_name (unsigned int lpar_id, u64 n1, u64 n2, u64 n3,
+ u64 n4, const char* func, int line)
+{
+ pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id);
+ _dump_field("n1: ", n1, func, line);
+ _dump_field("n2: ", n2, func, line);
+ _dump_field("n3: ", n3, func, line);
+ _dump_field("n4: ", n4, func, line);
+}
+
+#define dump_node(_a, _b, _c, _d, _e, _f, _g) \
+ _dump_node(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
+static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
+ u64 v1, u64 v2, const char* func, int line)
+{
+ pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id);
+ _dump_field("n1: ", n1, func, line);
+ _dump_field("n2: ", n2, func, line);
+ _dump_field("n3: ", n3, func, line);
+ _dump_field("n4: ", n4, func, line);
+ pr_debug("%s:%d: v1: %016lx\n", func, line, v1);
+ pr_debug("%s:%d: v2: %016lx\n", func, line, v2);
+}
+
+/**
+ * make_first_field - Make the first field of a repository node name.
+ * @text: Text portion of the field.
+ * @index: Numeric index portion of the field. Use zero for 'don't care'.
+ *
+ * This routine sets the vendor id to zero (non-vendor specific).
+ * Returns field value.
+ */
+
+static u64 make_first_field(const char *text, u64 index)
+{
+ u64 n;
+
+ strncpy((char *)&n, text, 8);
+ return PS3_VENDOR_ID_NONE + (n >> 32) + index;
+}
+
+/**
+ * make_field - Make subsequent fields of a repository node name.
+ * @text: Text portion of the field. Use "" for 'don't care'.
+ * @index: Numeric index portion of the field. Use zero for 'don't care'.
+ *
+ * Returns field value.
+ */
+
+static u64 make_field(const char *text, u64 index)
+{
+ u64 n;
+
+ strncpy((char *)&n, text, 8);
+ return n + index;
+}
+
+/**
+ * read_node - Read a repository node from raw fields.
+ * @n1: First field of node name.
+ * @n2: Second field of node name. Use zero for 'don't care'.
+ * @n3: Third field of node name. Use zero for 'don't care'.
+ * @n4: Fourth field of node name. Use zero for 'don't care'.
+ * @v1: First repository value (high word).
+ * @v2: Second repository value (low word). Optional parameter, use zero
+ * for 'don't care'.
+ */
+
+static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
+ u64 *_v1, u64 *_v2)
+{
+ int result;
+ u64 v1;
+ u64 v2;
+
+ if (lpar_id == PS3_LPAR_ID_CURRENT) {
+ u64 id;
+ lv1_get_logical_partition_id(&id);
+ lpar_id = id;
+ }
+
+ result = lv1_get_repository_node_value(lpar_id, n1, n2, n3, n4, &v1,
+ &v2);
+
+ if (result) {
+ pr_debug("%s:%d: lv1_get_repository_node_value failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ dump_node_name(lpar_id, n1, n2, n3, n4);
+ return result;
+ }
+
+ dump_node(lpar_id, n1, n2, n3, n4, v1, v2);
+
+ if (_v1)
+ *_v1 = v1;
+ if (_v2)
+ *_v2 = v2;
+
+ if (v1 && !_v1)
+ pr_debug("%s:%d: warning: discarding non-zero v1: %016lx\n",
+ __func__, __LINE__, v1);
+ if (v2 && !_v2)
+ pr_debug("%s:%d: warning: discarding non-zero v2: %016lx\n",
+ __func__, __LINE__, v2);
+
+ return result;
+}
+
+int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
+ u64 *value)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field(bus_str, 0),
+ 0, 0,
+ value, 0);
+}
+
+int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id)
+{
+ int result;
+ u64 v1;
+ u64 v2; /* unused */
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("id", 0),
+ 0, 0,
+ &v1, &v2);
+ *bus_id = v1;
+ return result;
+}
+
+int ps3_repository_read_bus_type(unsigned int bus_index,
+ enum ps3_bus_type *bus_type)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("type", 0),
+ 0, 0,
+ &v1, 0);
+ *bus_type = v1;
+ return result;
+}
+
+int ps3_repository_read_bus_num_dev(unsigned int bus_index,
+ unsigned int *num_dev)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("num_dev", 0),
+ 0, 0,
+ &v1, 0);
+ *num_dev = v1;
+ return result;
+}
+
+int ps3_repository_read_dev_str(unsigned int bus_index,
+ unsigned int dev_index, const char *dev_str, u64 *value)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field(dev_str, 0),
+ 0,
+ value, 0);
+}
+
+int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
+ unsigned int *dev_id)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("id", 0),
+ 0,
+ &v1, 0);
+ *dev_id = v1;
+ return result;
+}
+
+int ps3_repository_read_dev_type(unsigned int bus_index,
+ unsigned int dev_index, enum ps3_dev_type *dev_type)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("type", 0),
+ 0,
+ &v1, 0);
+ *dev_type = v1;
+ return result;
+}
+
+int ps3_repository_read_dev_intr(unsigned int bus_index,
+ unsigned int dev_index, unsigned int intr_index,
+ unsigned int *intr_type, unsigned int* interrupt_id)
+{
+ int result;
+ u64 v1;
+ u64 v2;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("intr", intr_index),
+ 0,
+ &v1, &v2);
+ *intr_type = v1;
+ *interrupt_id = v2;
+ return result;
+}
+
+int ps3_repository_read_dev_reg_type(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("reg", reg_index),
+ make_field("type", 0),
+ &v1, 0);
+ *reg_type = v1;
+ return result;
+}
+
+int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index, u64 *bus_addr, u64 *len)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("bus", bus_index),
+ make_field("dev", dev_index),
+ make_field("reg", reg_index),
+ make_field("data", 0),
+ bus_addr, len);
+}
+
+int ps3_repository_read_dev_reg(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type,
+ u64 *bus_addr, u64 *len)
+{
+ int result = ps3_repository_read_dev_reg_type(bus_index, dev_index,
+ reg_index, reg_type);
+ return result ? result
+ : ps3_repository_read_dev_reg_addr(bus_index, dev_index,
+ reg_index, bus_addr, len);
+}
+
+#if defined(DEBUG)
+int ps3_repository_dump_resource_info(unsigned int bus_index,
+ unsigned int dev_index)
+{
+ int result = 0;
+ unsigned int res_index;
+
+ pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
+ bus_index, dev_index);
+
+ for (res_index = 0; res_index < 10; res_index++) {
+ enum ps3_interrupt_type intr_type;
+ unsigned int interrupt_id;
+
+ result = ps3_repository_read_dev_intr(bus_index, dev_index,
+ res_index, &intr_type, &interrupt_id);
+
+ if (result) {
+ if (result != LV1_NO_ENTRY)
+ pr_debug("%s:%d ps3_repository_read_dev_intr"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ bus_index, dev_index);
+ break;
+ }
+
+ pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n",
+ __func__, __LINE__, bus_index, dev_index, intr_type,
+ interrupt_id);
+ }
+
+ for (res_index = 0; res_index < 10; res_index++) {
+ enum ps3_region_type reg_type;
+ u64 bus_addr;
+ u64 len;
+
+ result = ps3_repository_read_dev_reg(bus_index, dev_index,
+ res_index, ®_type, &bus_addr, &len);
+
+ if (result) {
+ if (result != LV1_NO_ENTRY)
+ pr_debug("%s:%d ps3_repository_read_dev_reg"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ bus_index, dev_index);
+ break;
+ }
+
+ pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n",
+ __func__, __LINE__, bus_index, dev_index, reg_type,
+ bus_addr, len);
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+static int dump_device_info(unsigned int bus_index, unsigned int num_dev)
+{
+ int result = 0;
+ unsigned int dev_index;
+
+ pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, bus_index);
+
+ for (dev_index = 0; dev_index < num_dev; dev_index++) {
+ enum ps3_dev_type dev_type;
+ unsigned int dev_id;
+
+ result = ps3_repository_read_dev_type(bus_index, dev_index,
+ &dev_type);
+
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_dev_type"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ bus_index, dev_index);
+ break;
+ }
+
+ result = ps3_repository_read_dev_id(bus_index, dev_index,
+ &dev_id);
+
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_dev_id"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ bus_index, dev_index);
+ continue;
+ }
+
+ pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__,
+ __LINE__, bus_index, dev_index, dev_type, dev_id);
+
+ ps3_repository_dump_resource_info(bus_index, dev_index);
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+int ps3_repository_dump_bus_info(void)
+{
+ int result = 0;
+ unsigned int bus_index;
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ for (bus_index = 0; bus_index < 10; bus_index++) {
+ enum ps3_bus_type bus_type;
+ unsigned int bus_id;
+ unsigned int num_dev;
+
+ result = ps3_repository_read_bus_type(bus_index, &bus_type);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_type(%u) failed\n",
+ __func__, __LINE__, bus_index);
+ break;
+ }
+
+ result = ps3_repository_read_bus_id(bus_index, &bus_id);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_id(%u) failed\n",
+ __func__, __LINE__, bus_index);
+ continue;
+ }
+
+ if (bus_index != bus_id)
+ pr_debug("%s:%d bus_index != bus_id\n",
+ __func__, __LINE__);
+
+ result = ps3_repository_read_bus_num_dev(bus_index, &num_dev);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_num_dev(%u) failed\n",
+ __func__, __LINE__, bus_index);
+ continue;
+ }
+
+ pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n",
+ __func__, __LINE__, bus_index, bus_type, bus_id,
+ num_dev);
+
+ dump_device_info(bus_index, num_dev);
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+#endif /* defined(DEBUG) */
+
+static int find_device(unsigned int bus_index, unsigned int num_dev,
+ unsigned int start_dev_index, enum ps3_dev_type dev_type,
+ struct ps3_repository_device *dev)
+{
+ int result = 0;
+ unsigned int dev_index;
+
+ pr_debug("%s:%d: find dev_type %u\n", __func__, __LINE__, dev_type);
+
+ dev->dev_index = UINT_MAX;
+
+ for (dev_index = start_dev_index; dev_index < num_dev; dev_index++) {
+ enum ps3_dev_type x;
+
+ result = ps3_repository_read_dev_type(bus_index, dev_index,
+ &x);
+
+ if (result) {
+ pr_debug("%s:%d read_dev_type failed\n",
+ __func__, __LINE__);
+ return result;
+ }
+
+ if (x == dev_type)
+ break;
+ }
+
+ BUG_ON(dev_index == num_dev);
+
+ pr_debug("%s:%d: found dev_type %u at dev_index %u\n",
+ __func__, __LINE__, dev_type, dev_index);
+
+ result = ps3_repository_read_dev_id(bus_index, dev_index,
+ &dev->did.dev_id);
+
+ if (result) {
+ pr_debug("%s:%d read_dev_id failed\n",
+ __func__, __LINE__);
+ return result;
+ }
+
+ dev->dev_index = dev_index;
+
+ pr_debug("%s:%d found: dev_id %u\n", __func__, __LINE__,
+ dev->did.dev_id);
+
+ return result;
+}
+
+int ps3_repository_find_device (enum ps3_bus_type bus_type,
+ enum ps3_dev_type dev_type,
+ const struct ps3_repository_device *start_dev,
+ struct ps3_repository_device *dev)
+{
+ int result = 0;
+ unsigned int bus_index;
+ unsigned int num_dev;
+
+ pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__,
+ bus_type, dev_type);
+
+ dev->bus_index = UINT_MAX;
+
+ for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10;
+ bus_index++) {
+ enum ps3_bus_type x;
+
+ result = ps3_repository_read_bus_type(bus_index, &x);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_type failed\n",
+ __func__, __LINE__);
+ return result;
+ }
+ if (x == bus_type)
+ break;
+ }
+
+ BUG_ON(bus_index == 10);
+
+ pr_debug("%s:%d: found bus_type %u at bus_index %u\n",
+ __func__, __LINE__, bus_type, bus_index);
+
+ result = ps3_repository_read_bus_num_dev(bus_index, &num_dev);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_num_dev failed\n",
+ __func__, __LINE__);
+ return result;
+ }
+
+ result = find_device(bus_index, num_dev, start_dev
+ ? start_dev->dev_index + 1 : 0, dev_type, dev);
+
+ if (result) {
+ pr_debug("%s:%d get_did failed\n", __func__, __LINE__);
+ return result;
+ }
+
+ result = ps3_repository_read_bus_id(bus_index, &dev->did.bus_id);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_id failed\n",
+ __func__, __LINE__);
+ return result;
+ }
+
+ dev->bus_index = bus_index;
+
+ pr_debug("%s:%d found: bus_id %u, dev_id %u\n",
+ __func__, __LINE__, dev->did.bus_id, dev->did.dev_id);
+
+ return result;
+}
+
+int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
+ enum ps3_interrupt_type intr_type, unsigned int *interrupt_id)
+{
+ int result = 0;
+ unsigned int res_index;
+
+ pr_debug("%s:%d: find intr_type %u\n", __func__, __LINE__, intr_type);
+
+ *interrupt_id = UINT_MAX;
+
+ for (res_index = 0; res_index < 10; res_index++) {
+ enum ps3_interrupt_type t;
+ unsigned int id;
+
+ result = ps3_repository_read_dev_intr(dev->bus_index,
+ dev->dev_index, res_index, &t, &id);
+
+ if (result) {
+ pr_debug("%s:%d read_dev_intr failed\n",
+ __func__, __LINE__);
+ return result;
+ }
+
+ if (t == intr_type) {
+ *interrupt_id = id;
+ break;
+ }
+ }
+
+ BUG_ON(res_index == 10);
+
+ pr_debug("%s:%d: found intr_type %u at res_index %u\n",
+ __func__, __LINE__, intr_type, res_index);
+
+ return result;
+}
+
+int ps3_repository_find_region(const struct ps3_repository_device *dev,
+ enum ps3_region_type reg_type, u64 *bus_addr, u64 *len)
+{
+ int result = 0;
+ unsigned int res_index;
+
+ pr_debug("%s:%d: find reg_type %u\n", __func__, __LINE__, reg_type);
+
+ *bus_addr = *len = 0;
+
+ for (res_index = 0; res_index < 10; res_index++) {
+ enum ps3_region_type t;
+ u64 a;
+ u64 l;
+
+ result = ps3_repository_read_dev_reg(dev->bus_index,
+ dev->dev_index, res_index, &t, &a, &l);
+
+ if (result) {
+ pr_debug("%s:%d read_dev_reg failed\n",
+ __func__, __LINE__);
+ return result;
+ }
+
+ if (t == reg_type) {
+ *bus_addr = a;
+ *len = l;
+ break;
+ }
+ }
+
+ BUG_ON(res_index == 10);
+
+ pr_debug("%s:%d: found reg_type %u at res_index %u\n",
+ __func__, __LINE__, reg_type, res_index);
+
+ return result;
+}
+
+int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size)
+{
+ return read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("pu", 0),
+ ppe_id,
+ make_field("rm_size", 0),
+ rm_size, 0);
+}
+
+int ps3_repository_read_region_total(u64 *region_total)
+{
+ return read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("rgntotal", 0),
+ 0, 0,
+ region_total, 0);
+}
+
+/**
+ * ps3_repository_read_mm_info - Read mm info for single pu system.
+ * @rm_base: Real mode memory base address.
+ * @rm_size: Real mode memory size.
+ * @region_total: Maximum memory region size.
+ */
+
+int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)
+{
+ int result;
+ u64 ppe_id;
+
+ lv1_get_logical_ppe_id(&ppe_id);
+ *rm_base = 0;
+ result = ps3_repository_read_rm_size(ppe_id, rm_size);
+ return result ? result
+ : ps3_repository_read_region_total(region_total);
+}
+
+/**
+ * ps3_repository_read_num_spu_reserved - Number of physical spus reserved.
+ * @num_spu: Number of physical spus.
+ */
+
+int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("spun", 0),
+ 0, 0,
+ &v1, 0);
+ *num_spu_reserved = v1;
+ return result;
+}
+
+/**
+ * ps3_repository_read_num_spu_resource_id - Number of spu resource reservations.
+ * @num_resource_id: Number of spu resource ids.
+ */
+
+int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("spursvn", 0),
+ 0, 0,
+ &v1, 0);
+ *num_resource_id = v1;
+ return result;
+}
+
+/**
+ * ps3_repository_read_spu_resource_id - spu resource reservation id value.
+ * @res_index: Resource reservation index.
+ * @resource_type: Resource reservation type.
+ * @resource_id: Resource reservation id.
+ */
+
+int ps3_repository_read_spu_resource_id(unsigned int res_index,
+ enum ps3_spu_resource_type* resource_type, unsigned int *resource_id)
+{
+ int result;
+ u64 v1;
+ u64 v2;
+
+ result = read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("spursv", 0),
+ res_index,
+ 0,
+ &v1, &v2);
+ *resource_type = v1;
+ *resource_id = v2;
+ return result;
+}
+
+int ps3_repository_read_boot_dat_address(u64 *address)
+{
+ return read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("boot_dat", 0),
+ make_field("address", 0),
+ 0,
+ address, 0);
+}
+
+int ps3_repository_read_boot_dat_size(unsigned int *size)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("boot_dat", 0),
+ make_field("size", 0),
+ 0,
+ &v1, 0);
+ *size = v1;
+ return result;
+}
+
+/**
+ * ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area.
+ * address: lpar address of cell_ext_os_area
+ * @size: size of cell_ext_os_area
+ */
+
+int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size)
+{
+ int result;
+
+ *size = 0;
+ result = ps3_repository_read_boot_dat_address(lpar_addr);
+ return result ? result
+ : ps3_repository_read_boot_dat_size(size);
+}
+
+int ps3_repository_read_num_be(unsigned int *num_be)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_PME,
+ make_first_field("ben", 0),
+ 0,
+ 0,
+ 0,
+ &v1, 0);
+ *num_be = v1;
+ return result;
+}
+
+int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("be", be_index),
+ 0,
+ 0,
+ 0,
+ node_id, 0);
+}
+
+int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq)
+{
+ return read_node(PS3_LPAR_ID_PME,
+ make_first_field("be", 0),
+ node_id,
+ make_field("clock", 0),
+ 0,
+ tb_freq, 0);
+}
+
+int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq)
+{
+ int result;
+ u64 node_id;
+
+ *tb_freq = 0;
+ result = ps3_repository_read_be_node_id(0, &node_id);
+ return result ? result
+ : ps3_repository_read_tb_freq(node_id, tb_freq);
+}
Index: cell--common--6/include/asm-powerpc/ps3.h
===================================================================
--- cell--common--6.orig/include/asm-powerpc/ps3.h
+++ cell--common--6/include/asm-powerpc/ps3.h
@@ -247,4 +247,143 @@
#endif
}
+/* repository bus info */
+
+enum ps3_bus_type {
+ PS3_BUS_TYPE_SB = 4,
+ PS3_BUS_TYPE_STORAGE = 5,
+};
+
+enum ps3_dev_type {
+ PS3_DEV_TYPE_SB_GELIC = 3,
+ PS3_DEV_TYPE_SB_USB = 4,
+ PS3_DEV_TYPE_SB_GPIO = 6,
+};
+
+int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
+ u64 *value);
+int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id);
+int ps3_repository_read_bus_type(unsigned int bus_index,
+ enum ps3_bus_type *bus_type);
+int ps3_repository_read_bus_num_dev(unsigned int bus_index,
+ unsigned int *num_dev);
+
+/* repository bus device info */
+
+enum ps3_interrupt_type {
+ PS3_INTERRUPT_TYPE_EVENT_PORT = 2,
+ PS3_INTERRUPT_TYPE_SB_OHCI = 3,
+ PS3_INTERRUPT_TYPE_SB_EHCI = 4,
+ PS3_INTERRUPT_TYPE_OTHER = 5,
+};
+
+enum ps3_region_type {
+ PS3_REGION_TYPE_SB_OHCI = 3,
+ PS3_REGION_TYPE_SB_EHCI = 4,
+ PS3_REGION_TYPE_SB_GPIO = 5,
+};
+
+int ps3_repository_read_dev_str(unsigned int bus_index,
+ unsigned int dev_index, const char *dev_str, u64 *value);
+int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
+ unsigned int *dev_id);
+int ps3_repository_read_dev_type(unsigned int bus_index,
+ unsigned int dev_index, enum ps3_dev_type *dev_type);
+int ps3_repository_read_dev_intr(unsigned int bus_index,
+ unsigned int dev_index, unsigned int intr_index,
+ enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id);
+int ps3_repository_read_dev_reg_type(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index,
+ enum ps3_region_type *reg_type);
+int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index, u64 *bus_addr,
+ u64 *len);
+int ps3_repository_read_dev_reg(unsigned int bus_index,
+ unsigned int dev_index, unsigned int reg_index,
+ enum ps3_region_type *reg_type, u64 *bus_addr, u64 *len);
+
+/* repository bus enumerators */
+
+struct ps3_repository_device {
+ unsigned int bus_index;
+ unsigned int dev_index;
+ struct ps3_device_id did;
+};
+
+int ps3_repository_find_device(enum ps3_bus_type bus_type,
+ enum ps3_dev_type dev_type,
+ const struct ps3_repository_device *start_dev,
+ struct ps3_repository_device *dev);
+static inline int ps3_repository_find_first_device(
+ enum ps3_bus_type bus_type, enum ps3_dev_type dev_type,
+ struct ps3_repository_device *dev)
+{
+ return ps3_repository_find_device(bus_type, dev_type, NULL, dev);
+}
+int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
+ enum ps3_interrupt_type intr_type, unsigned int *interrupt_id);
+int ps3_repository_find_region(const struct ps3_repository_device *dev,
+ enum ps3_region_type reg_type, u64 *bus_addr, u64 *len);
+
+/* repository block device info */
+
+int ps3_repository_read_dev_port(unsigned int bus_index,
+ unsigned int dev_index, u64 *port);
+int ps3_repository_read_dev_blk_size(unsigned int bus_index,
+ unsigned int dev_index, u64 *blk_size);
+int ps3_repository_read_dev_num_blocks(unsigned int bus_index,
+ unsigned int dev_index, u64 *num_blocks);
+int ps3_repository_read_dev_num_regions(unsigned int bus_index,
+ unsigned int dev_index, unsigned int *num_regions);
+int ps3_repository_read_dev_region_id(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index,
+ unsigned int *region_id);
+int ps3_repository_read_dev_region_size(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index, u64 *region_size);
+int ps3_repository_read_dev_region_start(unsigned int bus_index,
+ unsigned int dev_index, unsigned int region_index, u64 *region_start);
+
+/* repository pu and memory info */
+
+int ps3_repository_read_num_pu(unsigned int *num_pu);
+int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id);
+int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base);
+int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
+int ps3_repository_read_region_total(u64 *region_total);
+int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
+ u64 *region_total);
+
+/* repository pme info */
+
+int ps3_repository_read_num_be(unsigned int *num_be);
+int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id);
+int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq);
+int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq);
+
+/* repository 'Other OS' area */
+
+int ps3_repository_read_boot_dat_addr(u64 *lpar_addr);
+int ps3_repository_read_boot_dat_size(unsigned int *size);
+int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size);
+
+/* repository spu info */
+
+/**
+ * enum spu_resource_type - Type of spu resource.
+ * @spu_resource_type_shared: Logical spu is shared with other partions.
+ * @spu_resource_type_exclusive: Logical spu is not shared with other partions.
+ *
+ * Returned by ps3_repository_read_spu_resource_id().
+ */
+
+enum ps3_spu_resource_type {
+ PS3_SPU_RESOURCE_TYPE_SHARED = 0,
+ PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL,
+};
+
+int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved);
+int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
+int ps3_repository_read_spu_resource_id(unsigned int res_index,
+ enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
+
#endif
^ permalink raw reply [flat|nested] 13+ messages in thread
* cast truncates bits from constant value (8000000000000000 becomes 0)
2006-11-22 4:20 [PATCH 8/14] powerpc: add ps3 platform repository support Geoff Levand
@ 2006-12-01 14:25 ` Geert Uytterhoeven
2006-12-01 14:39 ` Al Viro
2006-12-01 15:30 ` Linus Torvalds
0 siblings, 2 replies; 13+ messages in thread
From: Geert Uytterhoeven @ 2006-12-01 14:25 UTC (permalink / raw)
To: linux-sparse; +Cc: Linux/PPC Development
On Tue, 21 Nov 2006, Geoff Levand wrote:
> +enum ps3_vendor_id {
> + PS3_VENDOR_ID_NONE = 0,
> + PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
> +};
I've just ran `make C=1' (PPC in 64-bit mode, and sparse is called with -m64),
and noticed that sparse (cloned from
git://git.kernel.org/pub/scm/devel/sparse/sparse.git a few minutes ago)
complains about the second value with:
| warning: cast truncates bits from constant value (8000000000000000 becomes 0)
Section 6.7.2.2.4 of C99 says:
| Each enumerated type shall be compatible with char, a signed integer type, or
| an unsigned integer type. The choice of type is implementation-defined, but
| shall be capable of representing the values of all the members of the
| enumeration.
The code snippet
| u64 x = PS3_VENDOR_ID_SONY;
| printk("PS3_VENDOR_ID_SONY = %lu\n", x);
does print the expected (i.e. non-zero) result.
Hence this looks like a bug in sparse.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- Sony Network and Software Technology Center Europe (NSCE)
Geert.Uytterhoeven@sonycom.com ------- The Corporate Village, Da Vincilaan 7-D1
Voice +32-2-7008453 Fax +32-2-7008622 ---------------- B-1935 Zaventem, Belgium
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 14:25 ` cast truncates bits from constant value (8000000000000000 becomes 0) Geert Uytterhoeven
@ 2006-12-01 14:39 ` Al Viro
2006-12-01 14:55 ` Geert Uytterhoeven
2006-12-01 15:30 ` Linus Torvalds
1 sibling, 1 reply; 13+ messages in thread
From: Al Viro @ 2006-12-01 14:39 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: Linux/PPC Development, linux-sparse
On Fri, Dec 01, 2006 at 03:25:08PM +0100, Geert Uytterhoeven wrote:
> On Tue, 21 Nov 2006, Geoff Levand wrote:
> > +enum ps3_vendor_id {
> > + PS3_VENDOR_ID_NONE = 0,
> > + PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
> > +};
>
> I've just ran `make C=1' (PPC in 64-bit mode, and sparse is called with -m64),
> and noticed that sparse (cloned from
> git://git.kernel.org/pub/scm/devel/sparse/sparse.git a few minutes ago)
> complains about the second value with:
>
> | warning: cast truncates bits from constant value (8000000000000000 becomes 0)
>
> Section 6.7.2.2.4 of C99 says:
>
> | Each enumerated type shall be compatible with char, a signed integer type, or
> | an unsigned integer type. The choice of type is implementation-defined, but
> | shall be capable of representing the values of all the members of the
> | enumeration.
FWIW, that code is *not* valid C99; note that all enumeration members must
fit the range of int (see 6.7.2.2.2). What you quote speaks about the
objects of type enum <something>, which is not the same as type of enum
members. In C99 it's int, plain and simple. Value outside of the range
of int => undefined behaviour. Note that with
enum foo {A, B} x;
you might very well have sizeof(A) != sizeof(x).
IOW, you are using a gccism in an area where gcc is bloody inconsistent
in the set of bugs it shows in different versions.
Generally safe way is to split the anonymous huge enum members into
single-element enums and pray that gcc will at least stay consistent
in handling of those.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 14:39 ` Al Viro
@ 2006-12-01 14:55 ` Geert Uytterhoeven
2006-12-02 7:50 ` Michael Ellerman
0 siblings, 1 reply; 13+ messages in thread
From: Geert Uytterhoeven @ 2006-12-01 14:55 UTC (permalink / raw)
To: Al Viro; +Cc: Linux/PPC Development, linux-sparse
On Fri, 1 Dec 2006, Al Viro wrote:
> On Fri, Dec 01, 2006 at 03:25:08PM +0100, Geert Uytterhoeven wrote:
> > On Tue, 21 Nov 2006, Geoff Levand wrote:
> > > +enum ps3_vendor_id {
> > > + PS3_VENDOR_ID_NONE = 0,
> > > + PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
> > > +};
> >
> > I've just ran `make C=1' (PPC in 64-bit mode, and sparse is called with -m64),
> > and noticed that sparse (cloned from
> > git://git.kernel.org/pub/scm/devel/sparse/sparse.git a few minutes ago)
> > complains about the second value with:
> >
> > | warning: cast truncates bits from constant value (8000000000000000 becomes 0)
> >
> > Section 6.7.2.2.4 of C99 says:
> >
> > | Each enumerated type shall be compatible with char, a signed integer type, or
> > | an unsigned integer type. The choice of type is implementation-defined, but
> > | shall be capable of representing the values of all the members of the
> > | enumeration.
>
> FWIW, that code is *not* valid C99; note that all enumeration members must
> fit the range of int (see 6.7.2.2.2). What you quote speaks about the
You're right. I missed that one.
> IOW, you are using a gccism in an area where gcc is bloody inconsistent
> in the set of bugs it shows in different versions.
Hmmm...
> Generally safe way is to split the anonymous huge enum members into
> single-element enums and pray that gcc will at least stay consistent
> in handling of those.
Or fall back to #defines, which is what we were trying to avoid in the first
place (i.e. group related values together in enums)...
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- Sony Network and Software Technology Center Europe (NSCE)
Geert.Uytterhoeven@sonycom.com ------- The Corporate Village, Da Vincilaan 7-D1
Voice +32-2-7008453 Fax +32-2-7008622 ---------------- B-1935 Zaventem, Belgium
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 14:25 ` cast truncates bits from constant value (8000000000000000 becomes 0) Geert Uytterhoeven
2006-12-01 14:39 ` Al Viro
@ 2006-12-01 15:30 ` Linus Torvalds
2006-12-01 16:51 ` Geoff Levand
1 sibling, 1 reply; 13+ messages in thread
From: Linus Torvalds @ 2006-12-01 15:30 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: Linux/PPC Development, linux-sparse
On Fri, 1 Dec 2006, Geert Uytterhoeven wrote:
>
> On Tue, 21 Nov 2006, Geoff Levand wrote:
> > +enum ps3_vendor_id {
> > + PS3_VENDOR_ID_NONE = 0,
> > + PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
> > +};
>
> I've just ran `make C=1' (PPC in 64-bit mode, and sparse is called with -m64),
> and noticed that sparse (cloned from
> git://git.kernel.org/pub/scm/devel/sparse/sparse.git a few minutes ago)
> complains about the second value with:
>
> | warning: cast truncates bits from constant value (8000000000000000 becomes 0)
>
> Section 6.7.2.2.4 of C99 says:
>
> | Each enumerated type shall be compatible with char, a signed integer type, or
> | an unsigned integer type. The choice of type is implementation-defined, but
> | shall be capable of representing the values of all the members of the
> | enumeration.
>
> The code snippet
>
> | u64 x = PS3_VENDOR_ID_SONY;
> | printk("PS3_VENDOR_ID_SONY = %lu\n", x);
>
> does print the expected (i.e. non-zero) result.
>
> Hence this looks like a bug in sparse.
It's really a bug in gcc, but it's documented, so it's a "feature".
Gcc allows large enums, but does so in such a strange manner that it's
totally hopeless to catch problems. Also, putting a value that is larger
than "unsigned int" into an enum is really setting yourself up for bugs
and not even guaranteed to work for standard C, so sparse takes a dim view
of it and just says that enums are limited in size to "int" or "unsigned
int".
You can either ignore that warning or just use a #define.
Linus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 15:30 ` Linus Torvalds
@ 2006-12-01 16:51 ` Geoff Levand
2006-12-01 20:20 ` Linus Torvalds
0 siblings, 1 reply; 13+ messages in thread
From: Geoff Levand @ 2006-12-01 16:51 UTC (permalink / raw)
To: Linus Torvalds
Cc: Geert Uytterhoeven, Linux/PPC Development, linux-sparse,
Andrew Pinski
Linus Torvalds wrote:
>
> On Fri, 1 Dec 2006, Geert Uytterhoeven wrote:
>>
>> On Tue, 21 Nov 2006, Geoff Levand wrote:
>> > +enum ps3_vendor_id {
>> > + PS3_VENDOR_ID_NONE = 0,
>> > + PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
>> > +};
>>
>> I've just ran `make C=1' (PPC in 64-bit mode, and sparse is called with -m64),
>> and noticed that sparse (cloned from
>> git://git.kernel.org/pub/scm/devel/sparse/sparse.git a few minutes ago)
>> complains about the second value with:
>>
>> | warning: cast truncates bits from constant value (8000000000000000 becomes 0)
>>
>> Section 6.7.2.2.4 of C99 says:
>>
>> | Each enumerated type shall be compatible with char, a signed integer type, or
>> | an unsigned integer type. The choice of type is implementation-defined, but
>> | shall be capable of representing the values of all the members of the
>> | enumeration.
>>
>> The code snippet
>>
>> | u64 x = PS3_VENDOR_ID_SONY;
>> | printk("PS3_VENDOR_ID_SONY = %lu\n", x);
>>
>> does print the expected (i.e. non-zero) result.
>>
>> Hence this looks like a bug in sparse.
>
> It's really a bug in gcc, but it's documented, so it's a "feature".
>
> Gcc allows large enums, but does so in such a strange manner that it's
> totally hopeless to catch problems. Also, putting a value that is larger
> than "unsigned int" into an enum is really setting yourself up for bugs
> and not even guaranteed to work for standard C, so sparse takes a dim view
> of it and just says that enums are limited in size to "int" or "unsigned
> int".
>
> You can either ignore that warning or just use a #define.
One of the gcc maintainers (Andrew Pinski) told me to set it up that
way, so I figured it was safe.
-Geoff
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 16:51 ` Geoff Levand
@ 2006-12-01 20:20 ` Linus Torvalds
2006-12-01 20:49 ` Derek M Jones
2006-12-01 20:50 ` Linus Torvalds
0 siblings, 2 replies; 13+ messages in thread
From: Linus Torvalds @ 2006-12-01 20:20 UTC (permalink / raw)
To: Geoff Levand
Cc: Geert Uytterhoeven, Linux/PPC Development, linux-sparse,
Andrew Pinski
On Fri, 1 Dec 2006, Geoff Levand wrote:
>
> One of the gcc maintainers (Andrew Pinski) told me to set it up that
> way, so I figured it was safe.
It _is_ safe, as long as you stick to gcc, and as long as you don't mix
signs in your values, for example.
But we actually want to let people compile even the kernel with other
compilers than gcc. Most of the time, that means that we strongly
encourage those compiler people to support all the gcc extensions (let's
face it, standardization is good, and open standards work better than
closed ones, and gcc is the most widely spread open and portable compiler
BY FAR, so it would be stupid to _not_ do that).
But at times, some of the gcc extensions aren't necessarily that well
defined or thought out, or simply not worth it. The extended type system
for enums in gcc is just basically messy, and it doesn't really offer you
anything important.
Compared with inline assembly, for example, inline assembly may be even
messier and more complicated, but inline assembly definitely offers you
something very important. The strange enum type extensions? What do they
really offer above and beyond the standard C preprocessor #define's? Apart
from some (very limited) name scoping advantages, there really isn't
anything that it really helps with.
And as Al already mentioned, some of the extensions aren't even compatible
within different versions of gcc itself. Admittedly they are all fairly
special, but basically the "type" of different individual enum members
simply isn't well-defined in all cases, and will even depend on thigns
like the order they were declared in, if I recall correctly.
Messy, messy.
Linus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 20:20 ` Linus Torvalds
@ 2006-12-01 20:49 ` Derek M Jones
2006-12-01 21:00 ` Al Viro
2006-12-01 20:50 ` Linus Torvalds
1 sibling, 1 reply; 13+ messages in thread
From: Derek M Jones @ 2006-12-01 20:49 UTC (permalink / raw)
To: Linus Torvalds
Cc: Geert Uytterhoeven, Linux/PPC Development, linux-sparse,
Andrew Pinski
Linus,
>> One of the gcc maintainers (Andrew Pinski) told me to set it up that
>> way, so I figured it was safe.
>
> It _is_ safe, as long as you stick to gcc, and as long as you don't mix
> signs in your values, for example.
>
> But we actually want to let people compile even the kernel with other
> compilers than gcc. Most of the time, that means that we strongly
> encourage those compiler people to support all the gcc extensions (let's
> face it, standardization is good, and open standards work better than
> closed ones, and gcc is the most widely spread open and portable compiler
> BY FAR, so it would be stupid to _not_ do that).
The C++ Standard explicitly supports enumeration constants not
having type int. See sentence 858 of
http://www.coding-guidelines.com/cbook/cbook1_0b.pdf
for a discussion of the issues (plus some other sentences).
C compiler vendors, at least those who extend the language, are more
likely to want to follow the C++ rules (which are documented) than the
gcc rules (which are poorly documented).
The C++ way of doing things is also likely to be followed by vendors
whose C compiler is enabled by a command line switch on their C++
compiler (eg, at least one vendor based in Seattle).
--
Derek M. Jones tel: +44 (0) 1252 520 667
Knowledge Software Ltd mailto:derek@knosof.co.uk
Applications Standards Conformance Testing http://www.knosof.co.uk
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 20:20 ` Linus Torvalds
2006-12-01 20:49 ` Derek M Jones
@ 2006-12-01 20:50 ` Linus Torvalds
2006-12-01 21:17 ` Geoff Levand
1 sibling, 1 reply; 13+ messages in thread
From: Linus Torvalds @ 2006-12-01 20:50 UTC (permalink / raw)
To: Geoff Levand
Cc: Geert Uytterhoeven, Linux/PPC Development, linux-sparse,
Andrew Pinski
On Fri, 1 Dec 2006, Linus Torvalds wrote:
>
> But at times, some of the gcc extensions aren't necessarily that well
> defined or thought out, or simply not worth it. The extended type system
> for enums in gcc is just basically messy, and it doesn't really offer you
> anything important.
Btw, try this stupid program, to see just how _strange_ gcc enums are.. A
sizeof of the enum is not the same as the size of the individual entries.
Notice also how the size of the enum entry is _not_ tied to the type of
the expression it had, but literally to its _value_. The size of "one"
ends up being 4, even though it was initialized with a "1ll" value.
So with gcc-enums, you CANNOT get a sane type result.
In contrast, if you want sane types, you could easily do
#define one (1ull)
#define other (0x10000ull)
#define strange (0x100000000ull)
and they'd all have the same type (and having the same type means that
they act the same in expressions - you get the same expression type in
mixing these values, _unlike_ the insane gcc enum cases)
Linus
---
enum hello {
one = 1ll,
other = 0x10000,
bigval = 0x1000000000000ll,
};
int main(int argc, char **argv)
{
printf("%zu %zu %zu %zu\n",
sizeof(enum hello),
sizeof(one),
sizeof(other),
sizeof(bigval));
return 0;
}
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 20:49 ` Derek M Jones
@ 2006-12-01 21:00 ` Al Viro
2006-12-01 21:19 ` Linus Torvalds
0 siblings, 1 reply; 13+ messages in thread
From: Al Viro @ 2006-12-01 21:00 UTC (permalink / raw)
To: Derek M Jones
Cc: Andrew Pinski, linux-sparse, Linux/PPC Development,
Linus Torvalds, Geert Uytterhoeven
On Fri, Dec 01, 2006 at 08:49:19PM +0000, Derek M Jones wrote:
> The C++ Standard explicitly supports enumeration constants not
> having type int. See sentence 858 of
> http://www.coding-guidelines.com/cbook/cbook1_0b.pdf
> for a discussion of the issues (plus some other sentences).
>
> C compiler vendors, at least those who extend the language, are more
> likely to want to follow the C++ rules (which are documented) than the
> gcc rules (which are poorly documented).
>
> The C++ way of doing things is also likely to be followed by vendors
> whose C compiler is enabled by a command line switch on their C++
> compiler (eg, at least one vendor based in Seattle).
"C++ way of doing things" is hardly an endorsement. _IF_ we are changing
the way enum works, might as well do it sanely and have the type of
enumeration constant same as that of expression initializing it (with
usual implicit initializers). But yes, that explicitly changes semantics -
enum { A = 0L, B, C }; will have A, B and C long, not int. Direct
contradiction with C90/C99...
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 20:50 ` Linus Torvalds
@ 2006-12-01 21:17 ` Geoff Levand
0 siblings, 0 replies; 13+ messages in thread
From: Geoff Levand @ 2006-12-01 21:17 UTC (permalink / raw)
To: Linus Torvalds
Cc: Geert Uytterhoeven, Linux/PPC Development, linux-sparse,
Andrew Pinski
Linus Torvalds wrote:
> Btw, try this stupid program, to see just how _strange_ gcc enums are.. A
> sizeof of the enum is not the same as the size of the individual entries.
Yes, interesting. I think your comment regarding compatibility with other
compilers is the convincing one.
Another way is to change the encoding of the value such that it fits into
the range of an enum. For this particular case, the values are actually
for a field in the high 3 bits, so I can just do the shift when the value
is used.
-Geoff
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 21:00 ` Al Viro
@ 2006-12-01 21:19 ` Linus Torvalds
0 siblings, 0 replies; 13+ messages in thread
From: Linus Torvalds @ 2006-12-01 21:19 UTC (permalink / raw)
To: Al Viro
Cc: Andrew Pinski, Derek M Jones, Linux/PPC Development, linux-sparse,
Geert Uytterhoeven
On Fri, 1 Dec 2006, Al Viro wrote:
>
> "C++ way of doing things" is hardly an endorsement. _IF_ we are changing
> the way enum works, might as well do it sanely and have the type of
> enumeration constant same as that of expression initializing it (with
> usual implicit initializers). But yes, that explicitly changes semantics -
> enum { A = 0L, B, C }; will have A, B and C long, not int. Direct
> contradiction with C90/C99...
Well, the C++ definition at least means that enumerated names have the
same types _after_ the enumaration is closed (ie the example I sent out
will at least give the same value for the sizeof() of everything).
So the C++ definition is a lot saner than what gcc does now.
On the other hand, I do agree that "keeping the enumerated type the same
as the initializer expression type" is _also_ a sane situation. And it's
better than the C++ situation in the sense that at least the sizes are
_consistent_ (which C++ is not - the size AT DEFINITION time is
potentially different from the size AFTER the definition).
So in the C++ world, you have the odd situation that
enum strange {
one = (char) 1,
other = sizeof(one),
};
we will actually end up with
other != sizeof(one)
AFTER the declaration (because when "other" got its value, "one" had a
type of "char", but _after_ the declaration, "one" will have a type of
"size_t" or "int" or whatever, because the final type of "one" depends on
the type of the enumerator.
So the C++ definition is really odd, but it's better than what gcc does,
because at least all the values end up having a common type at the end.
The version where all the values _keep_ their types all the time, and you
can force them to be whatever you want (by just making sure the
initializer expression has the right type) is the most flexible one and at
least doesn't have inconsistencies like the above example, but it's
neither what gcc nor the C++ standard (or any older C standard, for that
matter) actually says.
Anyway, because of all this, enum types are a mess. sparse warns if you
can't fit it in an "int", which is the traditional and fairly dependable
old C behaviour, and basically says "extended integer types for enums are
flaky as hell - warn about them!"
Linus
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: cast truncates bits from constant value (8000000000000000 becomes 0)
2006-12-01 14:55 ` Geert Uytterhoeven
@ 2006-12-02 7:50 ` Michael Ellerman
0 siblings, 0 replies; 13+ messages in thread
From: Michael Ellerman @ 2006-12-02 7:50 UTC (permalink / raw)
To: Geert Uytterhoeven; +Cc: Linux/PPC Development, linux-sparse, Al Viro
[-- Attachment #1: Type: text/plain, Size: 2116 bytes --]
On Fri, 2006-12-01 at 15:55 +0100, Geert Uytterhoeven wrote:
> On Fri, 1 Dec 2006, Al Viro wrote:
> > On Fri, Dec 01, 2006 at 03:25:08PM +0100, Geert Uytterhoeven wrote:
> > > On Tue, 21 Nov 2006, Geoff Levand wrote:
> > > > +enum ps3_vendor_id {
> > > > + PS3_VENDOR_ID_NONE = 0,
> > > > + PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
> > > > +};
> > >
> > > I've just ran `make C=1' (PPC in 64-bit mode, and sparse is called with -m64),
> > > and noticed that sparse (cloned from
> > > git://git.kernel.org/pub/scm/devel/sparse/sparse.git a few minutes ago)
> > > complains about the second value with:
> > >
> > > | warning: cast truncates bits from constant value (8000000000000000 becomes 0)
> > >
> > > Section 6.7.2.2.4 of C99 says:
> > >
> > > | Each enumerated type shall be compatible with char, a signed integer type, or
> > > | an unsigned integer type. The choice of type is implementation-defined, but
> > > | shall be capable of representing the values of all the members of the
> > > | enumeration.
> >
> > FWIW, that code is *not* valid C99; note that all enumeration members must
> > fit the range of int (see 6.7.2.2.2). What you quote speaks about the
>
> You're right. I missed that one.
>
> > IOW, you are using a gccism in an area where gcc is bloody inconsistent
> > in the set of bugs it shows in different versions.
>
> Hmmm...
>
> > Generally safe way is to split the anonymous huge enum members into
> > single-element enums and pray that gcc will at least stay consistent
> > in handling of those.
>
> Or fall back to #defines, which is what we were trying to avoid in the first
> place (i.e. group related values together in enums)...
The enum achieves very little in this case IMHO, it's just a more
verbose way of #defining - and it doesn't even have reliable semantics.
cheers
--
Michael Ellerman
OzLabs, IBM Australia Development Lab
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2006-12-02 7:50 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-22 4:20 [PATCH 8/14] powerpc: add ps3 platform repository support Geoff Levand
2006-12-01 14:25 ` cast truncates bits from constant value (8000000000000000 becomes 0) Geert Uytterhoeven
2006-12-01 14:39 ` Al Viro
2006-12-01 14:55 ` Geert Uytterhoeven
2006-12-02 7:50 ` Michael Ellerman
2006-12-01 15:30 ` Linus Torvalds
2006-12-01 16:51 ` Geoff Levand
2006-12-01 20:20 ` Linus Torvalds
2006-12-01 20:49 ` Derek M Jones
2006-12-01 21:00 ` Al Viro
2006-12-01 21:19 ` Linus Torvalds
2006-12-01 20:50 ` Linus Torvalds
2006-12-01 21:17 ` Geoff Levand
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).