diff options
author | Gabor Juhos <juhosg@openwrt.org> | 2012-05-12 10:49:26 +0000 |
---|---|---|
committer | Gabor Juhos <juhosg@openwrt.org> | 2012-05-12 10:49:26 +0000 |
commit | fd651daa4baa64c78555a1afe128bdd762e3765f (patch) | |
tree | de455b703c3420f678178c9776d30c21146bc1bf /target/linux/sibyte/patches-3.3 | |
parent | 4f6acae5f796b90364ebccdee3121520545b4404 (diff) | |
download | upstream-fd651daa4baa64c78555a1afe128bdd762e3765f.tar.gz upstream-fd651daa4baa64c78555a1afe128bdd762e3765f.tar.bz2 upstream-fd651daa4baa64c78555a1afe128bdd762e3765f.zip |
sibyte: add 3.3 support
SVN-Revision: 31680
Diffstat (limited to 'target/linux/sibyte/patches-3.3')
5 files changed, 922 insertions, 0 deletions
diff --git a/target/linux/sibyte/patches-3.3/101-rhone_physmap.patch b/target/linux/sibyte/patches-3.3/101-rhone_physmap.patch new file mode 100644 index 0000000000..fb917379ec --- /dev/null +++ b/target/linux/sibyte/patches-3.3/101-rhone_physmap.patch @@ -0,0 +1,82 @@ +--- a/arch/mips/sibyte/swarm/platform.c ++++ b/arch/mips/sibyte/swarm/platform.c +@@ -5,6 +5,7 @@ + #include <linux/platform_device.h> + #include <linux/ata_platform.h> + ++#include <asm/addrspace.h> + #include <asm/sibyte/board.h> + #include <asm/sibyte/sb1250_genbus.h> + #include <asm/sibyte/sb1250_regs.h> +@@ -137,3 +138,71 @@ static int __init sb1250_device_init(voi + return ret; + } + device_initcall(sb1250_device_init); ++ ++#ifdef CONFIG_SIBYTE_RHONE ++ ++#include <linux/mtd/partitions.h> ++#include <linux/mtd/physmap.h> ++ ++/* The board has 16MB flash but CFE sets up only 2MB */ ++#define PHYS_TO_K1(a) CKSEG1ADDR(a) ++#define BOOTROM_SIZE 0x100 ++ ++static void fixup_cs0_size(void) ++{ ++ SBWRITECSR(((A_IO_EXT_CS_BASE(0)) + R_IO_EXT_MULT_SIZE), BOOTROM_SIZE); ++} ++ ++static struct mtd_partition flash_parts[] = { ++ { ++ .name = "cfe", ++ .offset = 0x00000000, ++ .size = 0x00200000, ++ .mask_flags = MTD_WRITEABLE, ++ }, ++ { ++ .name = "os", ++ .offset = 0x00200000, ++ .size = 0x00d00000, ++ }, ++ { ++ .name = "environment", ++ .offset = 0x00f00000, ++ .size = 0x00100000, ++ .mask_flags = MTD_WRITEABLE, ++ }, ++}; ++ ++static struct physmap_flash_data flash_data = { ++ .width = 1, ++ .nr_parts = ARRAY_SIZE(flash_parts), ++ .parts = flash_parts, ++}; ++ ++static struct resource flash_resource = { ++ .start = 0x1fc00000, ++ .end = 0x20bfffff, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct platform_device flash_device = { ++ .name = "physmap-flash", ++ .id = 0, ++ .resource = &flash_resource, ++ .num_resources = 1, ++ .dev = { ++ .platform_data = &flash_data, ++ }, ++}; ++ ++static int __init flash_setup(void) ++{ ++ fixup_cs0_size(); ++ platform_device_register(&flash_device); ++ ++ return 0; ++}; ++ ++device_initcall(flash_setup); ++ ++#endif /* CONFIG_SIBYTE_RHONE */ diff --git a/target/linux/sibyte/patches-3.3/103-m41t80_smbus.patch b/target/linux/sibyte/patches-3.3/103-m41t80_smbus.patch new file mode 100644 index 0000000000..667d07c726 --- /dev/null +++ b/target/linux/sibyte/patches-3.3/103-m41t80_smbus.patch @@ -0,0 +1,367 @@ +--- a/drivers/rtc/rtc-m41t80.c ++++ b/drivers/rtc/rtc-m41t80.c +@@ -6,6 +6,7 @@ + * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com> + * + * 2006 (c) mycable GmbH ++ * Copyright (c) 2008 Maciej W. Rozycki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -38,6 +39,8 @@ + #define M41T80_REG_DAY 5 + #define M41T80_REG_MON 6 + #define M41T80_REG_YEAR 7 ++#define M41T80_REG_CONTROL 8 ++#define M41T80_REG_WATCHDOG 9 + #define M41T80_REG_ALARM_MON 0xa + #define M41T80_REG_ALARM_DAY 0xb + #define M41T80_REG_ALARM_HOUR 0xc +@@ -66,7 +69,7 @@ + #define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */ + #define M41T80_FEATURE_SQ_ALT (1 << 4) /* RSx bits are in reg 4 */ + +-#define DRV_VERSION "0.05" ++#define DRV_VERSION "0.06" + + static DEFINE_MUTEX(m41t80_rtc_mutex); + static const struct i2c_device_id m41t80_id[] = { +@@ -89,31 +92,88 @@ struct m41t80_data { + struct rtc_device *rtc; + }; + +-static int m41t80_get_datetime(struct i2c_client *client, +- struct rtc_time *tm) ++ ++static int m41t80_write_block_data(struct i2c_client *client, ++ u8 reg, u8 num, u8 *buf) + { +- u8 buf[M41T80_DATETIME_REG_SIZE], dt_addr[1] = { M41T80_REG_SEC }; +- struct i2c_msg msgs[] = { +- { +- .addr = client->addr, +- .flags = 0, +- .len = 1, +- .buf = dt_addr, +- }, +- { +- .addr = client->addr, +- .flags = I2C_M_RD, +- .len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC, +- .buf = buf + M41T80_REG_SEC, +- }, +- }; ++ int i, rc; + +- if (i2c_transfer(client->adapter, msgs, 2) < 0) { +- dev_err(&client->dev, "read error\n"); +- return -EIO; ++ if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { ++ i = i2c_smbus_write_i2c_block_data(client, reg, num, buf); ++ } else { ++ for (i = 0; i < num; i++) { ++ rc = i2c_smbus_write_byte_data(client, reg + i, ++ buf[i]); ++ if (rc < 0) { ++ i = rc; ++ goto out; ++ } ++ } + } ++out: ++ return i; ++} ++ ++static int m41t80_read_block_data(struct i2c_client *client, ++ u8 reg, u8 num, u8 *buf) ++{ ++ int i, rc; ++ ++ if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { ++ i = i2c_smbus_read_i2c_block_data(client, reg, num, buf); ++ } else { ++ for (i = 0; i < num; i++) { ++ rc = i2c_smbus_read_byte_data(client, reg + i); ++ if (rc < 0) { ++ i = rc; ++ goto out; ++ } ++ buf[i] = rc; ++ } ++ } ++out: ++ return i; ++} ++ ++static int m41t80_get_datetime(struct i2c_client *client, struct rtc_time *tm) ++{ ++ u8 buf[M41T80_DATETIME_REG_SIZE]; ++ int loops = 2; ++ int sec0, sec1; ++ ++ /* ++ * Time registers are latched by this chip if an I2C block ++ * transfer is used, but with SMBus-style byte accesses ++ * this is not the case, so check seconds for a wraparound. ++ */ ++ do { ++ if (m41t80_read_block_data(client, M41T80_REG_SEC, ++ M41T80_DATETIME_REG_SIZE - ++ M41T80_REG_SEC, ++ buf + M41T80_REG_SEC) < 0) { ++ dev_err(&client->dev, "read error\n"); ++ return -EIO; ++ } ++ if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { ++ sec1 = buf[M41T80_REG_SEC]; ++ break; ++ } ++ ++ sec0 = buf[M41T80_REG_SEC]; ++ sec1 = i2c_smbus_read_byte_data(client, M41T80_REG_SEC); ++ if (sec1 < 0) { ++ dev_err(&client->dev, "read error\n"); ++ return -EIO; ++ } ++ ++ sec0 = bcd2bin(sec0 & 0x7f); ++ sec1 = bcd2bin(sec1 & 0x7f); ++ } while (sec1 < sec0 && --loops); + +- tm->tm_sec = bcd2bin(buf[M41T80_REG_SEC] & 0x7f); ++ tm->tm_sec = sec1; + tm->tm_min = bcd2bin(buf[M41T80_REG_MIN] & 0x7f); + tm->tm_hour = bcd2bin(buf[M41T80_REG_HOUR] & 0x3f); + tm->tm_mday = bcd2bin(buf[M41T80_REG_DAY] & 0x3f); +@@ -128,39 +188,16 @@ static int m41t80_get_datetime(struct i2 + /* Sets the given date and time to the real time clock. */ + static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) + { +- u8 wbuf[1 + M41T80_DATETIME_REG_SIZE]; +- u8 *buf = &wbuf[1]; +- u8 dt_addr[1] = { M41T80_REG_SEC }; +- struct i2c_msg msgs_in[] = { +- { +- .addr = client->addr, +- .flags = 0, +- .len = 1, +- .buf = dt_addr, +- }, +- { +- .addr = client->addr, +- .flags = I2C_M_RD, +- .len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC, +- .buf = buf + M41T80_REG_SEC, +- }, +- }; +- struct i2c_msg msgs[] = { +- { +- .addr = client->addr, +- .flags = 0, +- .len = 1 + M41T80_DATETIME_REG_SIZE, +- .buf = wbuf, +- }, +- }; ++ u8 buf[M41T80_DATETIME_REG_SIZE]; + + /* Read current reg values into buf[1..7] */ +- if (i2c_transfer(client->adapter, msgs_in, 2) < 0) { ++ if (m41t80_read_block_data(client, M41T80_REG_SEC, ++ M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC, ++ buf + M41T80_REG_SEC) < 0) { + dev_err(&client->dev, "read error\n"); + return -EIO; + } + +- wbuf[0] = 0; /* offset into rtc's regs */ + /* Merge time-data and register flags into buf[0..7] */ + buf[M41T80_REG_SSEC] = 0; + buf[M41T80_REG_SEC] = +@@ -178,7 +215,8 @@ static int m41t80_set_datetime(struct i2 + /* assume 20YY not 19YY */ + buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year % 100); + +- if (i2c_transfer(client->adapter, msgs, 1) != 1) { ++ if (m41t80_write_block_data(client, M41T80_REG_SSEC, ++ M41T80_DATETIME_REG_SIZE, buf) < 0) { + dev_err(&client->dev, "write error\n"); + return -EIO; + } +@@ -238,34 +276,11 @@ err: + static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) + { + struct i2c_client *client = to_i2c_client(dev); +- u8 wbuf[1 + M41T80_ALARM_REG_SIZE]; +- u8 *buf = &wbuf[1]; ++ u8 buf[M41T80_ALARM_REG_SIZE]; + u8 *reg = buf - M41T80_REG_ALARM_MON; +- u8 dt_addr[1] = { M41T80_REG_ALARM_MON }; +- struct i2c_msg msgs_in[] = { +- { +- .addr = client->addr, +- .flags = 0, +- .len = 1, +- .buf = dt_addr, +- }, +- { +- .addr = client->addr, +- .flags = I2C_M_RD, +- .len = M41T80_ALARM_REG_SIZE, +- .buf = buf, +- }, +- }; +- struct i2c_msg msgs[] = { +- { +- .addr = client->addr, +- .flags = 0, +- .len = 1 + M41T80_ALARM_REG_SIZE, +- .buf = wbuf, +- }, +- }; + +- if (i2c_transfer(client->adapter, msgs_in, 2) < 0) { ++ if (m41t80_read_block_data(client, M41T80_REG_ALARM_MON, ++ M41T80_ALARM_REG_SIZE, buf) < 0) { + dev_err(&client->dev, "read error\n"); + return -EIO; + } +@@ -275,7 +290,6 @@ static int m41t80_rtc_set_alarm(struct d + reg[M41T80_REG_ALARM_MIN] = 0; + reg[M41T80_REG_ALARM_SEC] = 0; + +- wbuf[0] = M41T80_REG_ALARM_MON; /* offset into rtc's regs */ + reg[M41T80_REG_ALARM_SEC] |= t->time.tm_sec >= 0 ? + bin2bcd(t->time.tm_sec) : 0x80; + reg[M41T80_REG_ALARM_MIN] |= t->time.tm_min >= 0 ? +@@ -289,7 +303,8 @@ static int m41t80_rtc_set_alarm(struct d + else + reg[M41T80_REG_ALARM_DAY] |= 0x40; + +- if (i2c_transfer(client->adapter, msgs, 1) != 1) { ++ if (m41t80_write_block_data(client, M41T80_REG_ALARM_MON, ++ M41T80_ALARM_REG_SIZE, buf) < 0) { + dev_err(&client->dev, "write error\n"); + return -EIO; + } +@@ -309,24 +324,10 @@ static int m41t80_rtc_read_alarm(struct + { + struct i2c_client *client = to_i2c_client(dev); + u8 buf[M41T80_ALARM_REG_SIZE + 1]; /* all alarm regs and flags */ +- u8 dt_addr[1] = { M41T80_REG_ALARM_MON }; + u8 *reg = buf - M41T80_REG_ALARM_MON; +- struct i2c_msg msgs[] = { +- { +- .addr = client->addr, +- .flags = 0, +- .len = 1, +- .buf = dt_addr, +- }, +- { +- .addr = client->addr, +- .flags = I2C_M_RD, +- .len = M41T80_ALARM_REG_SIZE + 1, +- .buf = buf, +- }, +- }; + +- if (i2c_transfer(client->adapter, msgs, 2) < 0) { ++ if (m41t80_read_block_data(client, M41T80_REG_ALARM_MON, ++ M41T80_ALARM_REG_SIZE + 1, buf) < 0) { + dev_err(&client->dev, "read error\n"); + return -EIO; + } +@@ -508,26 +509,16 @@ static int boot_flag; + */ + static void wdt_ping(void) + { +- unsigned char i2c_data[2]; +- struct i2c_msg msgs1[1] = { +- { +- .addr = save_client->addr, +- .flags = 0, +- .len = 2, +- .buf = i2c_data, +- }, +- }; +- struct m41t80_data *clientdata = i2c_get_clientdata(save_client); ++ u8 wdt = 0x80; /* WDS = 1 (0x80) */ + +- i2c_data[0] = 0x09; /* watchdog register */ ++ struct m41t80_data *clientdata = i2c_get_clientdata(save_client); + + if (wdt_margin > 31) +- i2c_data[1] = (wdt_margin & 0xFC) | 0x83; /* resolution = 4s */ ++ /* mulitplier = WD_TIMO / 4, resolution = 4s (0x3) */ ++ wdt |= (wdt_margin & 0xfc) | 0x3; + else +- /* +- * WDS = 1 (0x80), mulitplier = WD_TIMO, resolution = 1s (0x02) +- */ +- i2c_data[1] = wdt_margin<<2 | 0x82; ++ /* mulitplier = WD_TIMO, resolution = 1s (0x2) */ ++ wdt |= wdt_margin << 2 | 0x2; + + /* + * M41T65 has three bits for watchdog resolution. Don't set bit 7, as +@@ -536,7 +527,7 @@ static void wdt_ping(void) + if (clientdata->features & M41T80_FEATURE_WD) + i2c_data[1] &= ~M41T80_WATCHDOG_RB2; + +- i2c_transfer(save_client->adapter, msgs1, 1); ++ i2c_smbus_write_byte_data(save_client, M41T80_REG_WATCHDOG, wdt); + } + + /** +@@ -546,36 +537,8 @@ static void wdt_ping(void) + */ + static void wdt_disable(void) + { +- unsigned char i2c_data[2], i2c_buf[0x10]; +- struct i2c_msg msgs0[2] = { +- { +- .addr = save_client->addr, +- .flags = 0, +- .len = 1, +- .buf = i2c_data, +- }, +- { +- .addr = save_client->addr, +- .flags = I2C_M_RD, +- .len = 1, +- .buf = i2c_buf, +- }, +- }; +- struct i2c_msg msgs1[1] = { +- { +- .addr = save_client->addr, +- .flags = 0, +- .len = 2, +- .buf = i2c_data, +- }, +- }; +- +- i2c_data[0] = 0x09; +- i2c_transfer(save_client->adapter, msgs0, 2); +- +- i2c_data[0] = 0x09; +- i2c_data[1] = 0x00; +- i2c_transfer(save_client->adapter, msgs1, 1); ++ i2c_smbus_read_byte_data(save_client, M41T80_REG_WATCHDOG); ++ i2c_smbus_write_byte_data(save_client, M41T80_REG_WATCHDOG, 0); + } + + /** +@@ -777,8 +740,8 @@ static int m41t80_probe(struct i2c_clien + struct rtc_time tm; + struct m41t80_data *clientdata = NULL; + +- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C +- | I2C_FUNC_SMBUS_BYTE_DATA)) { ++ if (!i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_BYTE_DATA)) { + rc = -ENODEV; + goto exit; + } diff --git a/target/linux/sibyte/patches-3.3/104-sibyte_rtc_cleanup.patch b/target/linux/sibyte/patches-3.3/104-sibyte_rtc_cleanup.patch new file mode 100644 index 0000000000..0483142b10 --- /dev/null +++ b/target/linux/sibyte/patches-3.3/104-sibyte_rtc_cleanup.patch @@ -0,0 +1,80 @@ +--- a/arch/mips/sibyte/swarm/setup.c ++++ b/arch/mips/sibyte/swarm/setup.c +@@ -56,14 +56,6 @@ extern void sb1250_setup(void); + #error invalid SiByte board configuration + #endif + +-extern int xicor_probe(void); +-extern int xicor_set_time(unsigned long); +-extern unsigned long xicor_get_time(void); +- +-extern int m41t81_probe(void); +-extern int m41t81_set_time(unsigned long); +-extern unsigned long m41t81_get_time(void); +- + const char *get_system_type(void) + { + return "SiByte " SIBYTE_BOARD_NAME; +@@ -79,49 +71,18 @@ int swarm_be_handler(struct pt_regs *reg + return (is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL); + } + +-enum swarm_rtc_type { +- RTC_NONE, +- RTC_XICOR, +- RTC_M41T81, +-}; +- +-enum swarm_rtc_type swarm_rtc_type; +- + void read_persistent_clock(struct timespec *ts) + { + unsigned long sec; + +- switch (swarm_rtc_type) { +- case RTC_XICOR: +- sec = xicor_get_time(); +- break; +- +- case RTC_M41T81: +- sec = m41t81_get_time(); +- break; +- +- case RTC_NONE: +- default: +- sec = mktime(2000, 1, 1, 0, 0, 0); +- break; +- } ++ sec = mktime(2000, 1, 1, 0, 0, 0); + ts->tv_sec = sec; + ts->tv_nsec = 0; + } + + int rtc_mips_set_time(unsigned long sec) + { +- switch (swarm_rtc_type) { +- case RTC_XICOR: +- return xicor_set_time(sec); +- +- case RTC_M41T81: +- return m41t81_set_time(sec); +- +- case RTC_NONE: +- default: + return -1; +- } + } + + void __init plat_mem_setup(void) +@@ -138,11 +99,6 @@ void __init plat_mem_setup(void) + + board_be_handler = swarm_be_handler; + +- if (xicor_probe()) +- swarm_rtc_type = RTC_XICOR; +- if (m41t81_probe()) +- swarm_rtc_type = RTC_M41T81; +- + #ifdef CONFIG_VT + screen_info = (struct screen_info) { + .orig_video_page = 52, diff --git a/target/linux/sibyte/patches-3.3/105-sibyte_hwmon.patch b/target/linux/sibyte/patches-3.3/105-sibyte_hwmon.patch new file mode 100644 index 0000000000..93dd4230d5 --- /dev/null +++ b/target/linux/sibyte/patches-3.3/105-sibyte_hwmon.patch @@ -0,0 +1,23 @@ +--- a/arch/mips/sibyte/swarm/swarm-i2c.c ++++ b/arch/mips/sibyte/swarm/swarm-i2c.c +@@ -13,6 +13,11 @@ + #include <linux/init.h> + #include <linux/kernel.h> + ++static struct i2c_board_info swarm_i2c_info0[] __initdata = { ++ { ++ I2C_BOARD_INFO("lm90", 0x2a), ++ }, ++}; + + static struct i2c_board_info swarm_i2c_info1[] __initdata = { + { +@@ -24,6 +29,8 @@ static int __init swarm_i2c_init(void) + { + int err; + ++ err = i2c_register_board_info(0, swarm_i2c_info0, ++ ARRAY_SIZE(swarm_i2c_info0)); + err = i2c_register_board_info(1, swarm_i2c_info1, + ARRAY_SIZE(swarm_i2c_info1)); + if (err < 0) diff --git a/target/linux/sibyte/patches-3.3/106-no_module_reloc.patch b/target/linux/sibyte/patches-3.3/106-no_module_reloc.patch new file mode 100644 index 0000000000..8082c3d027 --- /dev/null +++ b/target/linux/sibyte/patches-3.3/106-no_module_reloc.patch @@ -0,0 +1,370 @@ +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -90,8 +90,8 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib +-KBUILD_AFLAGS_MODULE += -mno-long-calls +-KBUILD_CFLAGS_MODULE += -mno-long-calls ++KBUILD_AFLAGS_MODULE += -mlong-calls ++KBUILD_CFLAGS_MODULE += -mlong-calls + + cflags-y += -ffreestanding + +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -9,11 +9,6 @@ struct mod_arch_specific { + struct list_head dbe_list; + const struct exception_table_entry *dbe_start; + const struct exception_table_entry *dbe_end; +- +- void *phys_plt_tbl; +- void *virt_plt_tbl; +- unsigned int phys_plt_offset; +- unsigned int virt_plt_offset; + }; + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -44,117 +44,6 @@ static struct mips_hi16 *mips_hi16_list; + static LIST_HEAD(dbe_list); + static DEFINE_SPINLOCK(dbe_lock); + +-/* +- * Get the potential max trampolines size required of the init and +- * non-init sections. Only used if we cannot find enough contiguous +- * physically mapped memory to put the module into. +- */ +-static unsigned int +-get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, +- const char *secstrings, unsigned int symindex, bool is_init) +-{ +- unsigned long ret = 0; +- unsigned int i, j; +- Elf_Sym *syms; +- +- /* Everything marked ALLOC (this includes the exported symbols) */ +- for (i = 1; i < hdr->e_shnum; ++i) { +- unsigned int info = sechdrs[i].sh_info; +- +- if (sechdrs[i].sh_type != SHT_REL +- && sechdrs[i].sh_type != SHT_RELA) +- continue; +- +- /* Not a valid relocation section? */ +- if (info >= hdr->e_shnum) +- continue; +- +- /* Don't bother with non-allocated sections */ +- if (!(sechdrs[info].sh_flags & SHF_ALLOC)) +- continue; +- +- /* If it's called *.init*, and we're not init, we're +- not interested */ +- if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) +- != is_init) +- continue; +- +- syms = (Elf_Sym *) sechdrs[symindex].sh_addr; +- if (sechdrs[i].sh_type == SHT_REL) { +- Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; +- unsigned int size = sechdrs[i].sh_size / sizeof(*rel); +- +- for (j = 0; j < size; ++j) { +- Elf_Sym *sym; +- +- if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) +- continue; +- +- sym = syms + ELF_MIPS_R_SYM(rel[j]); +- if (!is_init && sym->st_shndx != SHN_UNDEF) +- continue; +- +- ret += 4 * sizeof(int); +- } +- } else { +- Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; +- unsigned int size = sechdrs[i].sh_size / sizeof(*rela); +- +- for (j = 0; j < size; ++j) { +- Elf_Sym *sym; +- +- if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) +- continue; +- +- sym = syms + ELF_MIPS_R_SYM(rela[j]); +- if (!is_init && sym->st_shndx != SHN_UNDEF) +- continue; +- +- ret += 4 * sizeof(int); +- } +- } +- } +- +- return ret; +-} +- +-#ifndef MODULE_START +-static void *alloc_phys(unsigned long size) +-{ +- unsigned order; +- struct page *page; +- struct page *p; +- +- size = PAGE_ALIGN(size); +- order = get_order(size); +- +- page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | +- __GFP_THISNODE, order); +- if (!page) +- return NULL; +- +- split_page(page, order); +- +- for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) +- __free_page(p); +- +- return page_address(page); +-} +-#endif +- +-static void free_phys(void *ptr, unsigned long size) +-{ +- struct page *page; +- struct page *end; +- +- page = virt_to_page(ptr); +- end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT); +- +- for (; page < end; ++page) +- __free_page(page); +-} +- +- + void *module_alloc(unsigned long size) + { + #ifdef MODULE_START +@@ -162,99 +51,21 @@ void *module_alloc(unsigned long size) + GFP_KERNEL, PAGE_KERNEL, -1, + __builtin_return_address(0)); + #else +- void *ptr; +- + if (size == 0) + return NULL; +- +- ptr = alloc_phys(size); +- +- /* If we failed to allocate physically contiguous memory, +- * fall back to regular vmalloc. The module loader code will +- * create jump tables to handle long jumps */ +- if (!ptr) +- return vmalloc(size); +- +- return ptr; +-#endif +-} +- +-static inline bool is_phys_addr(void *ptr) +-{ +-#ifdef CONFIG_64BIT +- return (KSEGX((unsigned long)ptr) == CKSEG0); +-#else +- return (KSEGX(ptr) == KSEG0); ++ return vmalloc(size); + #endif + } + + /* Free memory returned from module_alloc */ + void module_free(struct module *mod, void *module_region) + { +- if (is_phys_addr(module_region)) { +- if (mod->module_init == module_region) +- free_phys(module_region, mod->init_size); +- else if (mod->module_core == module_region) +- free_phys(module_region, mod->core_size); +- else +- BUG(); +- } else { +- vfree(module_region); +- } +-} +- +-static void *__module_alloc(int size, bool phys) +-{ +- void *ptr; +- +- if (phys) +- ptr = kmalloc(size, GFP_KERNEL); +- else +- ptr = vmalloc(size); +- return ptr; +-} +- +-static void __module_free(void *ptr) +-{ +- if (is_phys_addr(ptr)) +- kfree(ptr); +- else +- vfree(ptr); ++ vfree(module_region); + } + + int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, + char *secstrings, struct module *mod) + { +- unsigned int symindex = 0; +- unsigned int core_size, init_size; +- int i; +- +- for (i = 1; i < hdr->e_shnum; i++) +- if (sechdrs[i].sh_type == SHT_SYMTAB) +- symindex = i; +- +- core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); +- init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); +- +- mod->arch.phys_plt_offset = 0; +- mod->arch.virt_plt_offset = 0; +- mod->arch.phys_plt_tbl = NULL; +- mod->arch.virt_plt_tbl = NULL; +- +- if ((core_size + init_size) == 0) +- return 0; +- +- mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); +- if (!mod->arch.phys_plt_tbl) +- return -ENOMEM; +- +- mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); +- if (!mod->arch.virt_plt_tbl) { +- __module_free(mod->arch.phys_plt_tbl); +- mod->arch.phys_plt_tbl = NULL; +- return -ENOMEM; +- } +- + return 0; + } + +@@ -277,36 +88,28 @@ static int apply_r_mips_32_rela(struct m + return 0; + } + +-static Elf_Addr add_plt_entry_to(unsigned *plt_offset, +- void *start, Elf_Addr v) ++static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) + { +- unsigned *tramp = start + *plt_offset; +- *plt_offset += 4 * sizeof(int); +- +- /* adjust carry for addiu */ +- if (v & 0x00008000) +- v += 0x10000; +- +- tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ +- tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ +- tramp[2] = 0x03200008; /* jr t9 */ +- tramp[3] = 0x00000000; /* nop */ ++ if (v % 4) { ++ pr_err("module %s: dangerous R_MIPS_26 REL relocation\n", ++ me->name); ++ return -ENOEXEC; ++ } + +- return (Elf_Addr) tramp; +-} ++ if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { ++ printk(KERN_ERR ++ "module %s: relocation overflow\n", ++ me->name); ++ return -ENOEXEC; ++ } + +-static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) +-{ +- if (is_phys_addr(location)) +- return add_plt_entry_to(&me->arch.phys_plt_offset, +- me->arch.phys_plt_tbl, v); +- else +- return add_plt_entry_to(&me->arch.virt_plt_offset, +- me->arch.virt_plt_tbl, v); ++ *location = (*location & ~0x03ffffff) | ++ ((*location + (v >> 2)) & 0x03ffffff); + ++ return 0; + } + +-static int set_r_mips_26(struct module *me, u32 *location, u32 ofs, Elf_Addr v) ++static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v) + { + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n", +@@ -315,31 +118,17 @@ static int set_r_mips_26(struct module * + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { +- v = add_plt_entry(me, location, v + (ofs << 2)); +- if (!v) { +- printk(KERN_ERR ++ printk(KERN_ERR + "module %s: relocation overflow\n", + me->name); +- return -ENOEXEC; +- } +- ofs = 0; ++ return -ENOEXEC; + } + +- *location = (*location & ~0x03ffffff) | ((ofs + (v >> 2)) & 0x03ffffff); ++ *location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff); + + return 0; + } + +-static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v) +-{ +- return set_r_mips_26(me, location, *location & 0x03ffffff, v); +-} +- +-static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v) +-{ +- return set_r_mips_26(me, location, 0, v); +-} +- + static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v) + { + struct mips_hi16 *n; +@@ -607,32 +396,11 @@ int module_finalize(const Elf_Ehdr *hdr, + list_add(&me->arch.dbe_list, &dbe_list); + spin_unlock_irq(&dbe_lock); + } +- +- /* Get rid of the fixup trampoline if we're running the module +- * from physically mapped address space */ +- if (me->arch.phys_plt_offset == 0) { +- __module_free(me->arch.phys_plt_tbl); +- me->arch.phys_plt_tbl = NULL; +- } +- if (me->arch.virt_plt_offset == 0) { +- __module_free(me->arch.virt_plt_tbl); +- me->arch.virt_plt_tbl = NULL; +- } +- + return 0; + } + + void module_arch_cleanup(struct module *mod) + { +- if (mod->arch.phys_plt_tbl) { +- __module_free(mod->arch.phys_plt_tbl); +- mod->arch.phys_plt_tbl = NULL; +- } +- if (mod->arch.virt_plt_tbl) { +- __module_free(mod->arch.virt_plt_tbl); +- mod->arch.virt_plt_tbl = NULL; +- } +- + spin_lock_irq(&dbe_lock); + list_del(&mod->arch.dbe_list); + spin_unlock_irq(&dbe_lock); |