static int ps3_open_hv_device_sb(struct ps3_system_bus_device *dev)
{
	int result;

	BUG_ON(!dev->bus_id);
	mutex_lock(&usage_hack.mutex);

	if (ps3_is_device(dev, 1, 1)) {
		usage_hack.sb_11++;
		if (usage_hack.sb_11 > 1) {
			result = 0;
			goto done;
		}
	}

	if (ps3_is_device(dev, 1, 2)) {
		usage_hack.sb_12++;
		if (usage_hack.sb_12 > 1) {
			result = 0;
			goto done;
		}
	}

	result = lv1_open_device(dev->bus_id, dev->dev_id, 0);

	if (result) {
		pr_debug("%s:%d: lv1_open_device failed: %s\n", __func__,
			__LINE__, ps3_result(result));
			result = -EPERM;
	}

done:
	mutex_unlock(&usage_hack.mutex);
	return result;
}
Esempio n. 2
0
static int ps3_probe_thread(void *data)
{
	struct ps3_notification_device dev;
	int res;
	unsigned int irq;
	u64 lpar;
	void *buf;
	struct ps3_notify_cmd *notify_cmd;
	struct ps3_notify_event *notify_event;

	pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__);

	buf = kzalloc(512, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	lpar = ps3_mm_phys_to_lpar(__pa(buf));
	notify_cmd = buf;
	notify_event = buf;

	/* dummy system bus device */
	dev.sbd.bus_id = (u64)data;
	dev.sbd.dev_id = PS3_NOTIFICATION_DEV_ID;
	dev.sbd.interrupt_id = PS3_NOTIFICATION_INTERRUPT_ID;

	res = lv1_open_device(dev.sbd.bus_id, dev.sbd.dev_id, 0);
	if (res) {
		pr_err("%s:%u: lv1_open_device failed %s\n", __func__,
		       __LINE__, ps3_result(res));
		goto fail_free;
	}

	res = ps3_sb_event_receive_port_setup(&dev.sbd, PS3_BINDING_CPU_ANY,
					      &irq);
	if (res) {
		pr_err("%s:%u: ps3_sb_event_receive_port_setup failed %d\n",
		       __func__, __LINE__, res);
	       goto fail_close_device;
	}

	spin_lock_init(&dev.lock);

	res = request_irq(irq, ps3_notification_interrupt, 0,
			  "ps3_notification", &dev);
	if (res) {
		pr_err("%s:%u: request_irq failed %d\n", __func__, __LINE__,
		       res);
		goto fail_sb_event_receive_port_destroy;
	}

	/* Setup and write the request for device notification. */
	notify_cmd->operation_code = 0; /* must be zero */
	notify_cmd->event_mask = 1UL << notify_region_probe;

	res = ps3_notification_read_write(&dev, lpar, 1);
	if (res)
		goto fail_free_irq;

	/* Loop here processing the requested notification events. */
	do {
		try_to_freeze();

		memset(notify_event, 0, sizeof(*notify_event));

		res = ps3_notification_read_write(&dev, lpar, 0);
		if (res)
			break;

		pr_debug("%s:%u: notify event type 0x%llx bus id %llu dev id %llu"
			 " type %llu port %llu\n", __func__, __LINE__,
			 notify_event->event_type, notify_event->bus_id,
			 notify_event->dev_id, notify_event->dev_type,
			 notify_event->dev_port);

		if (notify_event->event_type != notify_region_probe ||
		    notify_event->bus_id != dev.sbd.bus_id) {
			pr_warning("%s:%u: bad notify_event: event %llu, "
				   "dev_id %llu, dev_type %llu\n",
				   __func__, __LINE__, notify_event->event_type,
				   notify_event->dev_id,
				   notify_event->dev_type);
			continue;
		}

		ps3_find_and_add_device(dev.sbd.bus_id, notify_event->dev_id);

	} while (!kthread_should_stop());

fail_free_irq:
	free_irq(irq, &dev);
fail_sb_event_receive_port_destroy:
	ps3_sb_event_receive_port_destroy(&dev.sbd, irq);
fail_close_device:
	lv1_close_device(dev.sbd.bus_id, dev.sbd.dev_id);
fail_free:
	kfree(buf);

	probe_task = NULL;

	pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__);

	return 0;
}
Esempio n. 3
0
int ps3stor_setup(struct ps3_stordev *sd, int type)
{
	unsigned int i;
	int err;

	sd->sd_type = type;

	err = ps3repo_find_bus_by_type(PS3_BUS_TYPE_STOR, &sd->sd_busidx);
	if (err)
		goto out;

	err = ps3repo_read_bus_id(sd->sd_busidx, &sd->sd_busid);
	if (err)
		goto out;

	err = ps3repo_find_bus_dev_by_type(sd->sd_busidx, type, &sd->sd_devidx);
	if (err)
		goto out;

	err = ps3repo_read_bus_dev_id(sd->sd_busidx, sd->sd_devidx,
	    &sd->sd_devid);
	if (err)
		goto out;

	err = ps3repo_read_bus_dev_blk_size(sd->sd_busidx, sd->sd_devidx,
	    &sd->sd_blksize);
	if (err)
		goto out;

	err = ps3repo_read_bus_dev_nblocks(sd->sd_busidx, sd->sd_devidx,
	    &sd->sd_nblocks);
	if (err)
		goto out;

	err = ps3repo_read_bus_dev_nregs(sd->sd_busidx, sd->sd_devidx,
	    &sd->sd_nregs);
	if (err)
		goto out;

	for (i = 0; i < sd->sd_nregs; i++) {
		err = ps3repo_read_bus_dev_reg_id(sd->sd_busidx, sd->sd_devidx,
		    i, &sd->sd_regs[i].sr_id);
		if (err)
			goto out;

		err = ps3repo_read_bus_dev_reg_start(sd->sd_busidx,
		    sd->sd_devidx, i, &sd->sd_regs[i].sr_start);
		if (err)
			goto out;

		err = ps3repo_read_bus_dev_reg_size(sd->sd_busidx,
		    sd->sd_devidx, i, &sd->sd_regs[i].sr_size);
		if (err)
			goto out;
	}

	if (!sd->sd_nregs) {
		err = ENODEV;
		goto out;
	}

	err = lv1_open_device(sd->sd_busid, sd->sd_devid, 0);
	if (err)
		goto out;

	err = lv1_setup_dma(sd->sd_busid, sd->sd_devid, &sd->sd_dmabase);
	if (err)
		goto close_dev;

	return 0;

close_dev:

	lv1_close_device(sd->sd_busid, sd->sd_devid);

out:

	return err;
}
Esempio n. 4
0
static void gelic_debug_init(void)
{
	s64 result;
	u64 v2;
	u64 mac;
	u64 vlan_id;

	result = lv1_open_device(GELIC_BUS_ID, GELIC_DEVICE_ID, 0);
	if (result)
		lv1_panic(0);

	map_dma_mem(GELIC_BUS_ID, GELIC_DEVICE_ID, &dbg, sizeof(dbg),
		    &bus_addr);

	memset(&dbg, 0, sizeof(dbg));

	dbg.descr.buf_addr = bus_addr + offsetof(struct debug_block, pkt);

	wmb();

	result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,
				 GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0,
				 &mac, &v2);
	if (result)
		lv1_panic(0);

	mac <<= 16;

	h_eth = (struct ethhdr *)dbg.pkt;

	memset(&h_eth->dest, 0xff, 6);
	memcpy(&h_eth->src, &mac, 6);

	header_size = sizeof(struct ethhdr);

	result = lv1_net_control(GELIC_BUS_ID, GELIC_DEVICE_ID,
				 GELIC_LV1_GET_VLAN_ID,
				 GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0,
				 &vlan_id, &v2);
	if (!result) {
		h_eth->type = 0x8100;

		header_size += sizeof(struct vlantag);
		h_vlan = (struct vlantag *)(h_eth + 1);
		h_vlan->vlan = vlan_id;
		h_vlan->subtype = 0x0800;
		h_ip = (struct iphdr *)(h_vlan + 1);
	} else {
		h_eth->type = 0x0800;
		h_ip = (struct iphdr *)(h_eth + 1);
	}

	header_size += sizeof(struct iphdr);
	h_ip->ver_len = 0x45;
	h_ip->ttl = 10;
	h_ip->proto = 0x11;
	h_ip->src = 0x00000000;
	h_ip->dest = 0xffffffff;

	header_size += sizeof(struct udphdr);
	h_udp = (struct udphdr *)(h_ip + 1);
	h_udp->src = GELIC_DEBUG_PORT;
	h_udp->dest = GELIC_DEBUG_PORT;

	pmsgc = pmsg = (char *)(h_udp + 1);
}
Esempio n. 5
0
static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo)
{
	int error = -ENODEV;
	int result;
	const u64 notification_dev_id = (u64)-1LL;
	const unsigned int timeout = HZ;
	u64 lpar;
	u64 tag;
	void *buf;
	enum ps3_notify_type {
		notify_device_ready = 0,
		notify_region_probe = 1,
		notify_region_update = 2,
	};
	struct {
		u64 operation_code;	/* must be zero */
		u64 event_mask;		/* OR of 1UL << enum ps3_notify_type */
	} *notify_cmd;
	struct {
		u64 event_type;		/* enum ps3_notify_type */
		u64 bus_id;
		u64 dev_id;
		u64 dev_type;
		u64 dev_port;
	} *notify_event;

	pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id,
		 repo->dev_id, repo->dev_type);

	buf = kzalloc(512, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	lpar = ps3_mm_phys_to_lpar(__pa(buf));
	notify_cmd = buf;
	notify_event = buf;

	result = lv1_open_device(repo->bus_id, notification_dev_id, 0);
	if (result) {
		printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__,
		       __LINE__, ps3_result(result));
		goto fail_free;
	}

	/* Setup and write the request for device notification. */

	notify_cmd->operation_code = 0; /* must be zero */
	notify_cmd->event_mask = 1UL << notify_region_probe;

	result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar,
				   &tag);
	if (result) {
		printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__,
		       ps3_result(result));
		goto fail_close;
	}

	/* Wait for the write completion */

	result = ps3stor_wait_for_completion(notification_dev_id, tag,
					     timeout);
	if (result) {
		printk(KERN_ERR "%s:%u: write not completed %s\n", __func__,
		       __LINE__, ps3_result(result));
		goto fail_close;
	}

	/* Loop here processing the requested notification events. */

	while (1) {
		memset(notify_event, 0, sizeof(*notify_event));

		result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0,
					  lpar, &tag);
		if (result) {
			printk(KERN_ERR "%s:%u: write failed %s\n", __func__,
			       __LINE__, ps3_result(result));
			break;
		}

		result = ps3stor_wait_for_completion(notification_dev_id, tag,
						     timeout);
		if (result) {
			printk(KERN_ERR "%s:%u: read not completed %s\n",
			       __func__, __LINE__, ps3_result(result));
			break;
		}

		pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, "
			 "port %lu\n", __func__, __LINE__, repo->bus_index,
			 repo->dev_index, repo->dev_type,
			 notify_event->event_type, notify_event->dev_port);

		if (notify_event->event_type != notify_region_probe ||
		    notify_event->bus_id != repo->bus_id) {
			pr_debug("%s:%u: bad notify_event: event %lu, "
				 "dev_id %lu, dev_type %lu\n",
				 __func__, __LINE__, notify_event->event_type,
				 notify_event->dev_id, notify_event->dev_type);
			break;
		}

		if (notify_event->dev_id == repo->dev_id &&
		    notify_event->dev_type == repo->dev_type) {
			pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__,
				 __LINE__, repo->bus_index, repo->dev_index,
				 repo->dev_type);
			error = 0;
			break;
		}

		if (notify_event->dev_id == repo->dev_id &&
		    notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) {
			pr_debug("%s:%u: no access: dev_id %u\n", __func__,
				 __LINE__, repo->dev_id);
			break;
		}
	}

fail_close:
	lv1_close_device(repo->bus_id, notification_dev_id);
fail_free:
	kfree(buf);
	pr_debug(" <- %s:%u\n", __func__, __LINE__);
	return error;
}
Esempio n. 6
0
static int 
ps3bus_attach(device_t self) 
{
	struct ps3bus_softc *sc;
	struct ps3bus_devinfo *dinfo;
	int bus_index, dev_index, result;
	uint64_t bustype, bus, devs;
	uint64_t dev, devtype;
	uint64_t junk;
	device_t cdev;

	sc = device_get_softc(self);
	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
	sc->sc_mem_rman.rm_descr = "PS3Bus Memory Mapped I/O";
	sc->sc_intr_rman.rm_type = RMAN_ARRAY;
	sc->sc_intr_rman.rm_descr = "PS3Bus Interrupts";
	rman_init(&sc->sc_mem_rman);
	rman_init(&sc->sc_intr_rman);
	rman_manage_region(&sc->sc_intr_rman, 0, ~0);

	/* Get memory regions for DMA */
	mem_regions(&sc->regions, &sc->rcount, &sc->regions, &sc->rcount);

	/*
	 * Probe all the PS3's buses.
	 */

	for (bus_index = 0; bus_index < 5; bus_index++) {
		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("type"), 0, 0, &bustype, &junk);

		if (result != 0)
			continue;

		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("id"), 0, 0, &bus, &junk);

		if (result != 0)
			continue;

		result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
		    (lv1_repository_string("bus") >> 32) | bus_index,
		    lv1_repository_string("num_dev"), 0, 0, &devs, &junk);

		for (dev_index = 0; dev_index < devs; dev_index++) {
			result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
			    (lv1_repository_string("bus") >> 32) | bus_index,
			    lv1_repository_string("dev") | dev_index,
			    lv1_repository_string("type"), 0, &devtype, &junk);

			if (result != 0)
				continue;

			result = lv1_get_repository_node_value(PS3_LPAR_ID_PME,
			    (lv1_repository_string("bus") >> 32) | bus_index,
			    lv1_repository_string("dev") | dev_index,
			    lv1_repository_string("id"), 0, &dev, &junk);

			if (result != 0)
				continue;
			
			switch (devtype) {
			case PS3_DEVTYPE_USB:
				/* USB device has OHCI and EHCI USB host controllers */

				lv1_open_device(bus, dev, 0);

				/* OHCI host controller */

				dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
				    M_WAITOK | M_ZERO);

				dinfo->bus = bus;
				dinfo->dev = dev;
				dinfo->bustype = bustype;
				dinfo->devtype = devtype;
				dinfo->busidx = bus_index;
				dinfo->devidx = dev_index;

				ps3bus_resources_init_by_type(&sc->sc_mem_rman, bus_index,
				    dev_index, OHCI_IRQ, OHCI_REG, dinfo);

				cdev = device_add_child(self, "ohci", -1);
				if (cdev == NULL) {
					device_printf(self,
					    "device_add_child failed\n");
					free(dinfo, M_PS3BUS);
					continue;
				}

				mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
				device_set_ivars(cdev, dinfo);

				/* EHCI host controller */

				dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
				    M_WAITOK | M_ZERO);

				dinfo->bus = bus;
				dinfo->dev = dev;
				dinfo->bustype = bustype;
				dinfo->devtype = devtype;
				dinfo->busidx = bus_index;
				dinfo->devidx = dev_index;

				ps3bus_resources_init_by_type(&sc->sc_mem_rman, bus_index,
				    dev_index, EHCI_IRQ, EHCI_REG, dinfo);

				cdev = device_add_child(self, "ehci", -1);
				if (cdev == NULL) {
					device_printf(self,
					    "device_add_child failed\n");
					free(dinfo, M_PS3BUS);
					continue;
				}

				mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
				device_set_ivars(cdev, dinfo);
				break;
			default:
				dinfo = malloc(sizeof(*dinfo), M_PS3BUS,
				    M_WAITOK | M_ZERO);

				dinfo->bus = bus;
				dinfo->dev = dev;
				dinfo->bustype = bustype;
				dinfo->devtype = devtype;
				dinfo->busidx = bus_index;
				dinfo->devidx = dev_index;

				if (dinfo->bustype == PS3_BUSTYPE_SYSBUS ||
				    dinfo->bustype == PS3_BUSTYPE_STORAGE)
					lv1_open_device(bus, dev, 0);

				ps3bus_resources_init(&sc->sc_mem_rman, bus_index,
				    dev_index, dinfo);

				cdev = device_add_child(self, NULL, -1);
				if (cdev == NULL) {
					device_printf(self,
					    "device_add_child failed\n");
					free(dinfo, M_PS3BUS);
					continue;
				}

				mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
				device_set_ivars(cdev, dinfo);
			}
		}
	}
	
	clock_register(self, 1000);

	return (bus_generic_attach(self));
}