From: Geert.Uytterhoeven@sonycom•com
To: linuxppc-dev@ozlabs•org, linux-kernel@vger•kernel.org
Cc: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom•com>
Subject: [patch 4/7] ps3: Storage Driver Probing
Date: Fri, 25 May 2007 10:36:11 +0200 [thread overview]
Message-ID: <20070525083632.474400000@sonycom.com> (raw)
In-Reply-To: 20070525083607.784351000@sonycom.com
Add storage driver probing.
New storage devices are detected and added by a kthread.
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom•com>
---
arch/powerpc/platforms/ps3/device-init.c | 344 +++++++++++++++++++++++++++++++
1 files changed, 344 insertions(+)
--- a/arch/powerpc/platforms/ps3/device-init.c
+++ b/arch/powerpc/platforms/ps3/device-init.c
@@ -28,6 +28,7 @@
#include <asm/firmware.h>
#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
#include "platform.h"
@@ -508,6 +509,348 @@ static int __devinit ps3_register_av(voi
return result;
}
+#ifdef DEBUG
+static const char *ps3stor_dev_type(enum ps3_dev_type dev_type)
+{
+ switch (dev_type) {
+ case PS3_DEV_TYPE_STOR_DISK:
+ return "disk";
+
+ case PS3_DEV_TYPE_STOR_ROM:
+ return "rom";
+
+ case PS3_DEV_TYPE_STOR_FLASH:
+ return "flash";
+
+ case PS3_DEV_TYPE_NONE:
+ return "not present";
+
+ default:
+ return "unknown";
+ }
+}
+#else
+static inline const char *ps3stor_dev_type(enum ps3_dev_type dev_type)
+{
+ return NULL;
+}
+#endif /* DEBUG */
+
+#define NOTIFICATION_DEVID ((u64)(-1L))
+#define NOTIFICATION_TIMEOUT HZ
+
+static u64 ps3stor_wait_for_completion(u64 devid, u64 tag,
+ unsigned int timeout)
+{
+ unsigned int retries = 0;
+ u64 res = -1, status;
+
+ for (retries = 0; retries < timeout; retries++) {
+ res = lv1_storage_check_async_status(NOTIFICATION_DEVID, tag,
+ &status);
+ if (!res)
+ break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+ if (res)
+ pr_debug("%s:%u: check_async_status returns %ld status %lx\n",
+ __func__, __LINE__, res, status);
+
+ return res;
+}
+
+static int ps3stor_probe_notification(struct ps3_storage_device *dev,
+ enum ps3_dev_type dev_type)
+{
+ int error = -ENODEV, res;
+ u64 *buf;
+ u64 lpar;
+
+ pr_info("%s:%u: Requesting notification\n", __func__, __LINE__);
+
+ buf = kzalloc(512, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ lpar = ps3_mm_phys_to_lpar(__pa(buf));
+
+ /* 2-1) open special event device */
+ res = lv1_open_device(dev->sbd.did.bus_id, NOTIFICATION_DEVID, 0);
+ if (res) {
+ printk(KERN_ERR "%s:%u: open notification device failed %d\n",
+ __func__, __LINE__, res);
+ goto fail_free;
+ }
+
+ /* 2-2) write info to request notify */
+ buf[0] = 0;
+ buf[1] = (1 << 1); /* region update info only */
+ res = lv1_storage_write(NOTIFICATION_DEVID, 0, 0, 1, 0, lpar,
+ &dev->tag);
+ if (res) {
+ printk(KERN_ERR "%s:%u: notify request write failed %d\n",
+ __func__, __LINE__, res);
+ goto fail_close;
+ }
+
+ /* wait for completion in one second */
+ res = ps3stor_wait_for_completion(NOTIFICATION_DEVID, dev->tag,
+ NOTIFICATION_TIMEOUT);
+ if (res) {
+ /* write not completed */
+ printk(KERN_ERR "%s:%u: write not completed %d\n", __func__,
+ __LINE__, res);
+ goto fail_close;
+ }
+
+ /* 2-3) read to wait region notification for each device */
+ while (1) {
+ memset(buf, 0, 512);
+ lv1_storage_read(NOTIFICATION_DEVID, 0, 0, 1, 0, lpar,
+ &dev->tag);
+ res = ps3stor_wait_for_completion(NOTIFICATION_DEVID, dev->tag,
+ NOTIFICATION_TIMEOUT);
+ if (res) {
+ /* read not completed */
+ printk(KERN_ERR "%s:%u: read not completed %d\n",
+ __func__, __LINE__, res);
+ break;
+ }
+
+ /* 2-4) verify the notification */
+ if (buf[0] != 1 || buf[1] != dev->sbd.did.bus_id) {
+ /* other info notified */
+ pr_debug("%s:%u: notification info %ld dev=%lx type=%lx\n",
+ __func__, __LINE__, buf[0], buf[2], buf[3]);
+ break;
+ }
+
+ if (buf[2] == dev->sbd.did.dev_id && buf[3] == dev_type) {
+ pr_debug("%s:%u: device ready\n", __func__, __LINE__);
+ error = 0;
+ break;
+ }
+ }
+
+fail_close:
+ lv1_close_device(dev->sbd.did.bus_id, NOTIFICATION_DEVID);
+
+fail_free:
+ kfree(buf);
+ return error;
+}
+
+static int ps3stor_probe_dev(struct ps3_repository_device *repo)
+{
+ int error;
+ u64 port, blk_size, num_blocks;
+ unsigned int num_regions, i;
+ struct ps3_storage_device *dev;
+ enum ps3_dev_type dev_type;
+ unsigned int match_id;
+
+ pr_info("%s:%u: Probing new storage device %u\n", __func__, __LINE__,
+ repo->dev_index);
+
+ error = ps3_repository_read_dev_id(repo->bus_index, repo->dev_index,
+ &repo->did.dev_id);
+ if (error) {
+ printk(KERN_ERR "%s:%u: read_dev_id failed %d\n", __func__,
+ __LINE__, error);
+ return -ENODEV;
+ }
+
+ error = ps3_repository_read_dev_type(repo->bus_index, repo->dev_index,
+ &dev_type);
+ if (error) {
+ printk(KERN_ERR "%s:%u: read_dev_type failed %d\n", __func__,
+ __LINE__, error);
+ return -ENODEV;
+ }
+
+ pr_debug("%s:%u: index %u:%u: id %u:%u dev_type %u (%s)\n", __func__,
+ __LINE__, repo->bus_index, repo->dev_index, repo->did.bus_id,
+ repo->did.dev_id, dev_type, ps3stor_dev_type(dev_type));
+
+ switch (dev_type) {
+ case PS3_DEV_TYPE_STOR_DISK:
+ match_id = PS3_MATCH_ID_STOR_DISK;
+ break;
+
+ case PS3_DEV_TYPE_STOR_ROM:
+ match_id = PS3_MATCH_ID_STOR_ROM;
+ break;
+
+ case PS3_DEV_TYPE_STOR_FLASH:
+ match_id = PS3_MATCH_ID_STOR_FLASH;
+ break;
+
+ default:
+ return 0;
+ }
+
+ error = ps3_repository_read_stor_dev_info(repo->bus_index,
+ repo->dev_index, &port,
+ &blk_size, &num_blocks,
+ &num_regions);
+ if (error) {
+ printk(KERN_ERR "%s:%u: _read_stor_dev_info failed %d\n",
+ __func__, __LINE__, error);
+ return -ENODEV;
+ }
+ pr_debug("%s:%u: index %u:%u: port %lu blk_size %lu num_blocks %lu "
+ "num_regions %u\n",
+ __func__, __LINE__, repo->bus_index, repo->dev_index, port,
+ blk_size, num_blocks, num_regions);
+
+ dev = kzalloc(sizeof(struct ps3_storage_device)+
+ num_regions*sizeof(struct ps3_storage_region),
+ GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->sbd.did = repo->did;
+ ps3_system_bus_device_init(&dev->sbd, match_id, &dev->dma_region,
+ NULL);
+ dev->blk_size = blk_size;
+ dev->num_regions = num_regions;
+
+ error = ps3_repository_find_interrupt(repo,
+ PS3_INTERRUPT_TYPE_EVENT_PORT,
+ &dev->sbd.interrupt_id);
+ if (error) {
+ printk(KERN_ERR "%s:%u: find_interrupt failed %d\n", __func__,
+ __LINE__, error);
+ goto cleanup;
+ }
+
+ /* FIXME Do we really need this? I guess for kboot only? */
+ error = ps3stor_probe_notification(dev, dev_type);
+ if (error) {
+ printk(KERN_ERR "%s:%u: probe_notification failed %d\n",
+ __func__, __LINE__, error);
+ goto cleanup;
+ }
+
+ for (i = 0; i < num_regions; i++) {
+ unsigned int id;
+ u64 start, size;
+
+ error = ps3_repository_read_stor_dev_region(repo->bus_index,
+ repo->dev_index, i,
+ &id, &start,
+ &size);
+ if (error) {
+ printk(KERN_ERR
+ "%s:%u: read_stor_dev_region failed %d\n",
+ __func__, __LINE__, error);
+ goto cleanup;
+ }
+ pr_debug("%s:%u: region %u: id %u start %lu size %lu\n",
+ __func__, __LINE__, i, id, start, size);
+
+ dev->regions[i].id = id;
+ dev->regions[i].start = start;
+ dev->regions[i].size = size;
+ }
+
+ error = ps3_system_bus_device_register(&dev->sbd, PS3_IOBUS_SB);
+ if (error) {
+ printk(KERN_ERR
+ "%s:%u: ps3_system_bus_device_register failed %d\n",
+ __func__, __LINE__, error);
+ goto cleanup;
+ }
+ return 0;
+
+cleanup:
+ kfree(dev);
+ return -ENODEV;
+}
+
+static int ps3stor_thread(void *data)
+{
+ struct ps3_repository_device *repo = data;
+ int error;
+ unsigned int n, ms = 250;
+
+ pr_debug("%s:%u: kthread started\n", __func__, __LINE__);
+
+ do {
+ try_to_freeze();
+
+// pr_debug("%s:%u: Checking for new storage devices...\n",
+// __func__, __LINE__);
+ error = ps3_repository_read_bus_num_dev(repo->bus_index, &n);
+ if (error) {
+ printk(KERN_ERR "%s:%u: read_bus_num_dev failed %d\n",
+ __func__, __LINE__, error);
+ break;
+ }
+
+ if (n > repo->dev_index) {
+ pr_debug("%s:%u: Found %u storage devices (%u new)\n",
+ __func__, __LINE__, n, n - repo->dev_index);
+
+ while (repo->dev_index < n && !error) {
+ error = ps3stor_probe_dev(repo);
+ repo->dev_index++;
+ }
+
+ ms = 250;
+ }
+
+ msleep_interruptible(ms);
+ if (ms < 60000)
+ ms <<= 1;
+ } while (!kthread_should_stop());
+
+ pr_debug("%s:%u: kthread finished\n", __func__, __LINE__);
+
+ return 0;
+}
+
+static int __devinit ps3_register_storage_devices(void)
+{
+ int error;
+ static struct ps3_repository_device repo;
+ struct task_struct *task;
+
+ if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ return -ENODEV;
+
+ error = ps3_repository_find_bus(PS3_BUS_TYPE_STORAGE, 0,
+ &repo.bus_index);
+ if (error) {
+ printk(KERN_ERR "%s: Cannot find storage bus (%d)\n", __func__,
+ error);
+ return -ENODEV;
+ }
+ pr_debug("%s:%u: Storage bus has index %u\n", __func__, __LINE__,
+ repo.bus_index);
+
+ error = ps3_repository_read_bus_id(repo.bus_index, &repo.did.bus_id);
+ if (error) {
+ printk(KERN_ERR "%s: read_bus_id failed %d\n", __func__,
+ error);
+ return -ENODEV;
+ }
+
+ pr_debug("%s:%u: Storage bus has id %u\n", __func__, __LINE__,
+ repo.did.bus_id);
+
+ task = kthread_run(ps3stor_thread, &repo, "ps3stor-probe");
+ if (IS_ERR(task)) {
+ error = PTR_ERR(task);
+ printk(KERN_ERR "%s: kthread_run failed %d\n", __func__,
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
static int __devinit ps3_register_fb(void)
{
int error;
@@ -556,6 +899,7 @@ static int __init ps3_register_known_dev
result = ps3_register_sys_manager();
result = ps3_register_sound();
result = ps3_register_gelic();
+ result = ps3_register_storage_devices();
pr_debug(" <- %s:%d\n", __func__, __LINE__);
return result;
--
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
next prev parent reply other threads:[~2007-05-25 8:37 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-25 8:36 [patch 0/7] RFC: PS3 Storage Drivers Geert.Uytterhoeven
2007-05-25 8:36 ` [patch 1/7] ps3: Preallocate bootmem memory for the PS3 FLASH ROM storage driver Geert.Uytterhoeven
2007-05-25 22:35 ` Benjamin Herrenschmidt
2007-05-26 8:51 ` Geert Uytterhoeven
2007-05-26 22:17 ` Benjamin Herrenschmidt
2007-05-27 18:24 ` Arnd Bergmann
2007-05-25 8:36 ` [patch 2/7] ps3: Extract ps3_repository_find_bus() Geert.Uytterhoeven
2007-05-25 8:36 ` [patch 3/7] ps3: Storage Driver Core Geert.Uytterhoeven
2007-05-25 8:36 ` Geert.Uytterhoeven [this message]
2007-05-25 16:18 ` [patch 4/7] ps3: Storage Driver Probing Arnd Bergmann
2007-05-25 17:09 ` Geoff Levand
2007-05-25 19:48 ` Geert Uytterhoeven
2007-05-25 22:54 ` Benjamin Herrenschmidt
2007-05-25 22:47 ` Benjamin Herrenschmidt
2007-05-26 8:56 ` Geert Uytterhoeven
2007-05-25 8:36 ` [patch 5/7] ps3: Disk Storage Driver Geert.Uytterhoeven
2007-05-25 11:45 ` Olaf Hering
2007-05-25 19:43 ` Geert Uytterhoeven
2007-05-25 20:47 ` Olaf Hering
2007-05-25 16:26 ` Arnd Bergmann
2007-05-25 19:40 ` Geert Uytterhoeven
2007-05-25 20:43 ` Arnd Bergmann
2007-05-25 21:22 ` Geert Uytterhoeven
2007-05-25 22:45 ` Arnd Bergmann
2007-05-25 22:53 ` Benjamin Herrenschmidt
2007-05-25 22:48 ` Benjamin Herrenschmidt
2007-05-25 8:36 ` [patch 6/7] ps3: ROM " Geert.Uytterhoeven
2007-05-25 11:24 ` Olaf Hering
2007-05-25 22:45 ` Benjamin Herrenschmidt
2007-05-26 8:52 ` Geert Uytterhoeven
2007-05-26 22:18 ` Benjamin Herrenschmidt
2007-05-29 9:55 ` Christoph Hellwig
2007-05-25 16:50 ` Arnd Bergmann
2007-05-25 19:36 ` Geert Uytterhoeven
2007-05-25 21:04 ` Arnd Bergmann
2007-05-29 10:51 ` Christoph Hellwig
2007-05-29 10:49 ` Christoph Hellwig
2007-05-29 11:11 ` Geert Uytterhoeven
2007-05-29 11:31 ` Benjamin Herrenschmidt
2007-05-30 10:13 ` Christoph Hellwig
2007-05-30 11:45 ` Benjamin Herrenschmidt
2007-05-30 17:18 ` Geoff Levand
2007-05-29 16:21 ` Geert Uytterhoeven
2007-05-30 10:01 ` Christoph Hellwig
2007-05-25 8:36 ` [patch 7/7] ps3: FLASH " Geert.Uytterhoeven
2007-05-29 9:53 ` Christoph Hellwig
2007-05-29 9:57 ` Geert Uytterhoeven
2007-05-29 10:51 ` Christoph Hellwig
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070525083632.474400000@sonycom.com \
--to=geert.uytterhoeven@sonycom$(echo .)com \
--cc=linux-kernel@vger$(echo .)kernel.org \
--cc=linuxppc-dev@ozlabs$(echo .)org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox