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; }
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; }
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; }
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); }
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; }
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)); }