Subject: force proper address translation in Dell RBU Replacing virt_to_phys() by virt_to_bus(), and adding code to ensure contiguity as required by the firmware. As usual, written and tested on 2.6.27.37 and made apply to the 2.6.18 tree without further testing. Signed-off-by: Jan Beulich Tested-by: Douglas Warzecha --- sle11-2009-10-16.orig/drivers/firmware/dell_rbu.c 2009-02-02 09:22:26.000000000 +0100 +++ sle11-2009-10-16/drivers/firmware/dell_rbu.c 2009-10-26 16:34:16.000000000 +0100 @@ -169,9 +169,28 @@ static int create_packet(void *data, siz spin_lock(&rbu_data.lock); goto out_alloc_packet_array; } +#ifdef CONFIG_XEN + if (ordernum && xen_create_contiguous_region( + (unsigned long)packet_data_temp_buf, ordernum, 0)) { + free_pages((unsigned long)packet_data_temp_buf, + ordernum); + printk(KERN_WARNING + "dell_rbu:%s: failed to adjust new " + "packet\n", __func__); + retval = -ENOMEM; + spin_lock(&rbu_data.lock); + goto out_alloc_packet_array; + } +#endif - if ((unsigned long)virt_to_phys(packet_data_temp_buf) + if ((unsigned long)virt_to_bus(packet_data_temp_buf) < allocation_floor) { +#ifdef CONFIG_XEN + if (ordernum) + xen_destroy_contiguous_region( + (unsigned long)packet_data_temp_buf, + ordernum); +#endif pr_debug("packet 0x%lx below floor at 0x%lx.\n", (unsigned long)virt_to_phys( packet_data_temp_buf), @@ -185,7 +204,7 @@ static int create_packet(void *data, siz newpacket->data = packet_data_temp_buf; pr_debug("create_packet: newpacket at physical addr %lx\n", - (unsigned long)virt_to_phys(newpacket->data)); + (unsigned long)virt_to_bus(newpacket->data)); /* packets may not have fixed size */ newpacket->length = length; @@ -204,7 +223,7 @@ out_alloc_packet_array: /* always free packet array */ for (;idx>0;idx--) { pr_debug("freeing unused packet below floor 0x%lx.\n", - (unsigned long)virt_to_phys( + (unsigned long)virt_to_bus( invalid_addr_packet_array[idx-1])); free_pages((unsigned long)invalid_addr_packet_array[idx-1], ordernum); @@ -348,6 +367,13 @@ static void packet_empty_list(void) * to make sure there are no stale RBU packets left in memory */ memset(newpacket->data, 0, rbu_data.packetsize); +#ifdef CONFIG_XEN + if (newpacket->ordernum) + xen_destroy_contiguous_region( + (unsigned long)newpacket->data, + newpacket->ordernum); +#endif + free_pages((unsigned long) newpacket->data, newpacket->ordernum); kfree(newpacket); @@ -402,7 +428,9 @@ static int img_update_realloc(unsigned l { unsigned char *image_update_buffer = NULL; unsigned long rc; +#ifndef CONFIG_XEN unsigned long img_buf_phys_addr; +#endif int ordernum; int dma_alloc = 0; @@ -433,15 +461,19 @@ static int img_update_realloc(unsigned l spin_unlock(&rbu_data.lock); +#ifndef CONFIG_XEN ordernum = get_order(size); image_update_buffer = (unsigned char *) __get_free_pages(GFP_KERNEL, ordernum); img_buf_phys_addr = - (unsigned long) virt_to_phys(image_update_buffer); + (unsigned long) virt_to_bus(image_update_buffer); if (img_buf_phys_addr > BIOS_SCAN_LIMIT) { free_pages((unsigned long) image_update_buffer, ordernum); +#else + { +#endif ordernum = -1; image_update_buffer = dma_alloc_coherent(NULL, size, &dell_rbu_dmaaddr, GFP_KERNEL); @@ -706,6 +738,12 @@ static struct bin_attribute rbu_packet_s static int __init dcdrbu_init(void) { int rc = 0; + +#ifdef CONFIG_XEN + if (!is_initial_xendomain()) + return -ENODEV; +#endif + spin_lock_init(&rbu_data.lock); init_packet_head();