📄 shpchprm_acpi.c
字号:
break; case ACPI_WRITE_COMBINING_MEMORY: dbg(" Type Specific: Write-combining memory\n"); break; case ACPI_PREFETCHABLE_MEMORY: aprh = &ab->p_mem_head; dbg(" Type Specific: Prefetchable memory\n"); break; default: dbg(" Type Specific: Invalid cache attribute\n"); break; } dbg(" Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32->attribute.memory.read_write_attribute ? "/Write":" Only"); break; case ACPI_IO_RANGE: dbg(" Resource Type: I/O Range\n"); aprh = &ab->io_head; tprh = &ab->tio_head; switch (data32->attribute.io.range_attribute) { case ACPI_NON_ISA_ONLY_RANGES: dbg(" Type Specific: Non-ISA Io Addresses\n"); break; case ACPI_ISA_ONLY_RANGES: dbg(" Type Specific: ISA Io Addresses\n"); break; case ACPI_ENTIRE_RANGE: dbg(" Type Specific: ISA and non-ISA Io Addresses\n"); break; default: dbg(" Type Specific: Invalid range attribute\n"); break; } break; case ACPI_BUS_NUMBER_RANGE: dbg(" Resource Type: Bus Number Range(fixed)\n"); /* fixup to be compatible with the rest of php driver */ data32->min_address_range++; data32->address_length--; aprh = &ab->bus_head; tprh = &ab->tbus_head; break; default: dbg(" Resource Type: Invalid resource type. Exiting.\n"); return; } dbg(" Resource %s\n", ACPI_CONSUMER == data32->producer_consumer ? "Consumer":"Producer"); dbg(" %s decode\n", ACPI_SUB_DECODE == data32->decode ? "Subtractive":"Positive"); dbg(" Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->min_address_fixed ? "":"not"); dbg(" Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32->max_address_fixed ? "":"not"); dbg(" Granularity: %08X\n", data32->granularity); dbg(" Address range min: %08X\n", data32->min_address_range); dbg(" Address range max: %08X\n", data32->max_address_range); dbg(" Address translation offset: %08X\n", data32->address_translation_offset); dbg(" Address Length: %08X\n", data32->address_length); if (0xFF != data32->resource_source.index) { dbg(" Resource Source Index: %X\n", data32->resource_source.index); /* dbg(" Resource Source: %s\n", data32->resource_source.string_ptr); */ } shpchprm_add_resource(aprh, data32->min_address_range, data32->address_length);}static acpi_status acpi_parse_crs( struct acpi_bridge *ab, struct acpi_resource *crsbuf ){ acpi_status status = AE_OK; struct acpi_resource *resource = crsbuf; u8 count = 0; u8 done = 0; while (!done) { dbg("acpi_shpchprm: PCI bus 0x%x Resource structure %x.\n", ab->bus, count++); switch (resource->id) { case ACPI_RSTYPE_IRQ: dbg("Irq -------- Resource\n"); break; case ACPI_RSTYPE_DMA: dbg("DMA -------- Resource\n"); break; case ACPI_RSTYPE_START_DPF: dbg("Start DPF -------- Resource\n"); break; case ACPI_RSTYPE_END_DPF: dbg("End DPF -------- Resource\n"); break; case ACPI_RSTYPE_IO: acpi_parse_io (ab, &resource->data); break; case ACPI_RSTYPE_FIXED_IO: acpi_parse_fixed_io (ab, &resource->data); break; case ACPI_RSTYPE_VENDOR: dbg("Vendor -------- Resource\n"); break; case ACPI_RSTYPE_END_TAG: dbg("End_tag -------- Resource\n"); done = 1; break; case ACPI_RSTYPE_MEM24: dbg("Mem24 -------- Resource\n"); break; case ACPI_RSTYPE_MEM32: dbg("Mem32 -------- Resource\n"); break; case ACPI_RSTYPE_FIXED_MEM32: dbg("Fixed Mem32 -------- Resource\n"); break; case ACPI_RSTYPE_ADDRESS16: acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS16); break; case ACPI_RSTYPE_ADDRESS32: acpi_parse_address16_32(ab, &resource->data, ACPI_RSTYPE_ADDRESS32); break; case ACPI_RSTYPE_ADDRESS64: info("Address64 -------- Resource unparsed\n"); break; case ACPI_RSTYPE_EXT_IRQ: dbg("Ext Irq -------- Resource\n"); break; default: dbg("Invalid -------- resource type 0x%x\n", resource->id); break; } resource = (struct acpi_resource *) ((char *)resource + resource->length); } return status;}static acpi_status acpi_get_crs( struct acpi_bridge *ab){ acpi_status status; struct acpi_resource *crsbuf; status = acpi_evaluate_crs(ab->handle, &crsbuf); if (ACPI_SUCCESS(status)) { status = acpi_parse_crs(ab, crsbuf); kfree(crsbuf); shpchp_resource_sort_and_combine(&ab->bus_head); shpchp_resource_sort_and_combine(&ab->io_head); shpchp_resource_sort_and_combine(&ab->mem_head); shpchp_resource_sort_and_combine(&ab->p_mem_head); shpchprm_add_resources (&ab->tbus_head, ab->bus_head); shpchprm_add_resources (&ab->tio_head, ab->io_head); shpchprm_add_resources (&ab->tmem_head, ab->mem_head); shpchprm_add_resources (&ab->tp_mem_head, ab->p_mem_head); } return status;}/* find acpi_bridge downword from ab. */static struct acpi_bridge *find_acpi_bridge_by_bus( struct acpi_bridge *ab, int seg, int bus /* pdev->subordinate->number */ ){ struct acpi_bridge *lab = NULL; if (!ab) return NULL; if ((ab->bus == bus) && (ab->seg == seg)) return ab; if (ab->child) lab = find_acpi_bridge_by_bus(ab->child, seg, bus); if (!lab) if (ab->next) lab = find_acpi_bridge_by_bus(ab->next, seg, bus); return lab;}/* * Build a device tree of ACPI PCI Bridges */static void shpchprm_acpi_register_a_bridge ( struct acpi_bridge **head, struct acpi_bridge *pab, /* parent bridge to which child bridge is added */ struct acpi_bridge *cab /* child bridge to add */ ){ struct acpi_bridge *lpab; struct acpi_bridge *lcab; lpab = find_acpi_bridge_by_bus(*head, pab->seg, pab->bus); if (!lpab) { if (!(pab->type & BRIDGE_TYPE_HOST)) warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab->seg, pab->bus); pab->next = *head; *head = pab; lpab = pab; } if ((cab->type & BRIDGE_TYPE_HOST) && (pab == cab)) return; lcab = find_acpi_bridge_by_bus(*head, cab->seg, cab->bus); if (lcab) { if ((pab->bus != lcab->parent->bus) || (lcab->bus != cab->bus)) err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab->seg, cab->bus); return; } else lcab = cab; lcab->parent = lpab; lcab->next = lpab->child; lpab->child = lcab;}static acpi_status shpchprm_acpi_build_php_slots_callback( acpi_handle handle, u32 Level, void *context, void **retval ){ ulong bus_num; ulong seg_num; ulong sun, adr; ulong padr = 0; acpi_handle phandle = NULL; struct acpi_bridge *pab = (struct acpi_bridge *)context; struct acpi_bridge *lab; acpi_status status; u8 *path_name = acpi_path_name(handle); /* get _SUN */ status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &sun); switch(status) { case AE_NOT_FOUND: return AE_OK; default: if (ACPI_FAILURE(status)) { err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status); return status; } } /* get _ADR. _ADR must exist if _SUN exists */ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); if (ACPI_FAILURE(status)) { err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); return status; } dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr); status = acpi_get_parent(handle, &phandle); if (ACPI_FAILURE(status)) { err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status); return (status); } bus_num = pab->bus; seg_num = pab->seg; if (pab->bus == bus_num) { lab = pab; } else { dbg("WARN: pab is not parent\n"); lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num); if (!lab) { dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL); if (!lab) { err("acpi_shpchprm: alloc for ab fail\n"); return AE_NO_MEMORY; } memset(lab, 0, sizeof(struct acpi_bridge)); lab->handle = phandle; lab->pbus = pab->bus; lab->pdevice = (int)(padr >> 16) & 0xffff; lab->pfunction = (int)(padr & 0xffff); lab->bus = (int)bus_num; lab->scanned = 0; lab->type = BRIDGE_TYPE_P2P; shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, lab); } else dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun); } acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun); return (status);}static int shpchprm_acpi_build_php_slots( struct acpi_bridge *ab, u32 depth ){ acpi_status status; u8 *path_name = acpi_path_name(ab->handle); /* Walk down this pci bridge to get _SUNs if any behind P2P */ status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, ab->handle, depth, shpchprm_acpi_build_php_slots_callback, ab, NULL ); if (ACPI_FAILURE(status)) { dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab->seg, ab->bus, status); return -1; } return 0;}static void build_a_bridge( struct acpi_bridge *pab, struct acpi_bridge *ab ){ u8 *path_name = acpi_path_name(ab->handle); shpchprm_acpi_register_a_bridge (&acpi_bridges_head, pab, ab); switch (ab->type) { case BRIDGE_TYPE_HOST: dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); break; case BRIDGE_TYPE_P2P: dbg("acpi_shpchprm: Registered PCI P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n", ab->pbus, ab->bus, ab->seg, ab->pbus, ab->pdevice, ab->pfunction, path_name); break; }; /* build any immediate PHP slots under this pci bridge */ shpchprm_acpi_build_php_slots(ab, 1);}static struct acpi_bridge * add_p2p_bridge( acpi_handle handle, struct acpi_bridge *pab, /* parent */ ulong adr ){ struct acpi_bridge *ab; struct pci_dev *pdev; ulong devnum, funcnum; u8 *path_name = acpi_path_name(handle); ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); if (!ab) { err("acpi_shpchprm: alloc for ab fail\n"); return NULL; } memset(ab, 0, sizeof(struct acpi_bridge)); devnum = (adr >> 16) & 0xffff; funcnum = adr & 0xffff; pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); if (!pdev || !pdev->subordinate) { err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name); kfree(ab); return NULL; } ab->handle = handle; ab->seg = pab->seg; ab->pbus = pab->bus; /* or pdev->bus->number */ ab->pdevice = devnum; /* or PCI_SLOT(pdev->devfn) */ ab->pfunction = funcnum; /* or PCI_FUNC(pdev->devfn) */ ab->bus = pdev->subordinate->number; ab->scanned = 0; ab->type = BRIDGE_TYPE_P2P; dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n", pab->bus, ab->bus, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pab->bus, (u32)devnum, (u32)funcnum, path_name); build_a_bridge(pab, ab); return ab;}static acpi_status scan_p2p_bridge( acpi_handle handle, u32 Level, void *context, void **retval ){ struct acpi_bridge *pab = (struct acpi_bridge *)context; struct acpi_bridge *ab; acpi_status status; ulong adr = 0; u8 *path_name = acpi_path_name(handle); ulong devnum, funcnum; struct pci_dev *pdev; /* get device, function */ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); return AE_OK; } devnum = (adr >> 16) & 0xffff; funcnum = adr & 0xffff; pdev = pci_find_slot(pab->bus, PCI_DEVFN(devnum, funcnum)); if (!pdev) return AE_OK; if (!pdev->subordinate) return AE_OK; ab = add_p2p_bridge(handle, pab, adr); if (ab) { status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, handle, (u32)1, scan_p2p_bridge, ab, NULL); if (ACPI_FAILURE(status)) dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); } return AE_OK;}static struct acpi_bridge * add_host_bridge( acpi_handle handle, ulong segnum, ulong busnum ){ ulong adr = 0; acpi_status status; struct acpi_bridge *ab; u8 *path_name = acpi_path_name(handle); /* get device, function: host br adr is always 0000 though. */ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); if (ACPI_FAILURE(status)) { err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status); return NULL; } dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, (u32)(adr >> 16) & 0xffff, (u32)adr & 0xffff, path_name); ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL); if (!ab) { err("acpi_shpchprm: alloc for ab fail\n"); return NULL; } memset(ab, 0, sizeof(struct acpi_bridge)); ab->handle = handle; ab->seg = (int)segnum; ab->bus = ab->pbus = (int)busnum; ab->pdevice = (int)(adr >> 16) & 0xffff; ab->pfunction = (int)(adr & 0xffff); ab->scanned = 0; ab->type = BRIDGE_TYPE_HOST; /* get root pci bridge's current resources */ status = acpi_get_crs(ab); if (ACPI_FAILURE(status)) { err("acpi_shpchprm:%s evaluate _CRS fail=0x%x\n", path_name, status); kfree(ab); return NULL; } build_a_bridge(ab, ab); return ab;}static acpi_status acpi_scan_from_root_pci_callback ( acpi_handle handle, u32 Level, void *context, void **retval ){ ulong segnum = 0; ulong busnum = 0; acpi_status status; struct acpi_bridge *ab; u8 *path_name = acpi_path_name(handle); /* get bus number of this pci root bridge */ status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &segnum); if (ACPI_FAILURE(status)) { if (status != AE_NOT_FOUND) { err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status); return status; } segnum = 0; } /* get bus number of this pci root bridge */ status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &busnum); if (ACPI_FAILURE(status)) { err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status); return (status); } ab = add_host_bridge(handle, segnum, busnum); if (ab) { status = acpi_walk_namespace ( ACPI_TYPE_DEVICE, handle, 1, scan_p2p_bridge, ab, NULL); if (ACPI_FAILURE(status)) dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status); } return AE_OK;}static int shpchprm_acpi_scan_pci (void){ acpi_status status; /* * TBD: traverse LDM device tree with the help of * unified ACPI augmented for php device population. */ status = acpi_get_devices ( PCI_ROOT_HID_STRING, acpi_scan_from_root_pci_callback, NULL, NULL ); if (ACPI_FAILURE(status)) { err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status); return -1; } return 0;}int shpchprm_init(enum php_ctlr_type ctlr_type){ int rc; if (ctlr_type != PCI) return -ENODEV; dbg("shpchprm ACPI init <enter>\n"); acpi_bridges_head = NULL; /* construct PCI bus:device tree of acpi_handles */ rc = shpchprm_acpi_scan_pci(); if (rc) return rc; dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success"); return rc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -