]>
Commit | Line | Data |
---|---|---|
cf4ece53 MO |
1 | /* |
2 | * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; version 2 of the License. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program; if not, write to the Free Software | |
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. | |
16 | */ | |
17 | ||
18 | #include <linux/module.h> | |
19 | #include <linux/kernel.h> | |
20 | #include <linux/types.h> | |
21 | #include <linux/fs.h> | |
22 | #include <linux/uaccess.h> | |
23 | #include <linux/string.h> | |
24 | #include <linux/pci.h> | |
25 | #include <linux/io.h> | |
26 | #include <linux/delay.h> | |
27 | #include <linux/mutex.h> | |
28 | #include <linux/if_ether.h> | |
29 | #include <linux/ctype.h> | |
30 | ||
31 | #define PHUB_STATUS 0x00 /* Status Register offset */ | |
32 | #define PHUB_CONTROL 0x04 /* Control Register offset */ | |
33 | #define PHUB_TIMEOUT 0x05 /* Time out value for Status Register */ | |
34 | #define PCH_PHUB_ROM_WRITE_ENABLE 0x01 /* Enabling for writing ROM */ | |
35 | #define PCH_PHUB_ROM_WRITE_DISABLE 0x00 /* Disabling for writing ROM */ | |
36 | #define PCH_PHUB_ROM_START_ADDR 0x14 /* ROM data area start address offset */ | |
37 | ||
38 | /* MAX number of INT_REDUCE_CONTROL registers */ | |
39 | #define MAX_NUM_INT_REDUCE_CONTROL_REG 128 | |
40 | #define PCI_DEVICE_ID_PCH1_PHUB 0x8801 | |
41 | #define PCH_MINOR_NOS 1 | |
42 | #define CLKCFG_CAN_50MHZ 0x12000000 | |
43 | #define CLKCFG_CANCLK_MASK 0xFF000000 | |
44 | ||
45 | /* SROM ACCESS Macro */ | |
46 | #define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) | |
47 | ||
48 | /* Registers address offset */ | |
49 | #define PCH_PHUB_ID_REG 0x0000 | |
50 | #define PCH_PHUB_QUEUE_PRI_VAL_REG 0x0004 | |
51 | #define PCH_PHUB_RC_QUEUE_MAXSIZE_REG 0x0008 | |
52 | #define PCH_PHUB_BRI_QUEUE_MAXSIZE_REG 0x000C | |
53 | #define PCH_PHUB_COMP_RESP_TIMEOUT_REG 0x0010 | |
54 | #define PCH_PHUB_BUS_SLAVE_CONTROL_REG 0x0014 | |
55 | #define PCH_PHUB_DEADLOCK_AVOID_TYPE_REG 0x0018 | |
56 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG0 0x0020 | |
57 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG1 0x0024 | |
58 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG2 0x0028 | |
59 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG3 0x002C | |
60 | #define PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE 0x0040 | |
61 | #define CLKCFG_REG_OFFSET 0x500 | |
62 | ||
63 | #define PCH_PHUB_OROM_SIZE 15360 | |
64 | ||
65 | /** | |
66 | * struct pch_phub_reg - PHUB register structure | |
67 | * @phub_id_reg: PHUB_ID register val | |
68 | * @q_pri_val_reg: QUEUE_PRI_VAL register val | |
69 | * @rc_q_maxsize_reg: RC_QUEUE_MAXSIZE register val | |
70 | * @bri_q_maxsize_reg: BRI_QUEUE_MAXSIZE register val | |
71 | * @comp_resp_timeout_reg: COMP_RESP_TIMEOUT register val | |
72 | * @bus_slave_control_reg: BUS_SLAVE_CONTROL_REG register val | |
73 | * @deadlock_avoid_type_reg: DEADLOCK_AVOID_TYPE register val | |
74 | * @intpin_reg_wpermit_reg0: INTPIN_REG_WPERMIT register 0 val | |
75 | * @intpin_reg_wpermit_reg1: INTPIN_REG_WPERMIT register 1 val | |
76 | * @intpin_reg_wpermit_reg2: INTPIN_REG_WPERMIT register 2 val | |
77 | * @intpin_reg_wpermit_reg3: INTPIN_REG_WPERMIT register 3 val | |
78 | * @int_reduce_control_reg: INT_REDUCE_CONTROL registers val | |
79 | * @clkcfg_reg: CLK CFG register val | |
80 | * @pch_phub_base_address: Register base address | |
81 | * @pch_phub_extrom_base_address: external rom base address | |
82 | */ | |
83 | struct pch_phub_reg { | |
84 | u32 phub_id_reg; | |
85 | u32 q_pri_val_reg; | |
86 | u32 rc_q_maxsize_reg; | |
87 | u32 bri_q_maxsize_reg; | |
88 | u32 comp_resp_timeout_reg; | |
89 | u32 bus_slave_control_reg; | |
90 | u32 deadlock_avoid_type_reg; | |
91 | u32 intpin_reg_wpermit_reg0; | |
92 | u32 intpin_reg_wpermit_reg1; | |
93 | u32 intpin_reg_wpermit_reg2; | |
94 | u32 intpin_reg_wpermit_reg3; | |
95 | u32 int_reduce_control_reg[MAX_NUM_INT_REDUCE_CONTROL_REG]; | |
96 | u32 clkcfg_reg; | |
97 | void __iomem *pch_phub_base_address; | |
98 | void __iomem *pch_phub_extrom_base_address; | |
99 | }; | |
100 | ||
101 | /* SROM SPEC for MAC address assignment offset */ | |
102 | static const int pch_phub_mac_offset[ETH_ALEN] = {0x3, 0x2, 0x1, 0x0, 0xb, 0xa}; | |
103 | ||
104 | static DEFINE_MUTEX(pch_phub_mutex); | |
105 | ||
106 | /** | |
107 | * pch_phub_read_modify_write_reg() - Reading modifying and writing register | |
108 | * @reg_addr_offset: Register offset address value. | |
109 | * @data: Writing value. | |
110 | * @mask: Mask value. | |
111 | */ | |
112 | static void pch_phub_read_modify_write_reg(struct pch_phub_reg *chip, | |
113 | unsigned int reg_addr_offset, | |
114 | unsigned int data, unsigned int mask) | |
115 | { | |
116 | void __iomem *reg_addr = chip->pch_phub_base_address + reg_addr_offset; | |
117 | iowrite32(((ioread32(reg_addr) & ~mask)) | data, reg_addr); | |
118 | } | |
119 | ||
120 | /* pch_phub_save_reg_conf - saves register configuration */ | |
121 | static void pch_phub_save_reg_conf(struct pci_dev *pdev) | |
122 | { | |
123 | unsigned int i; | |
124 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | |
125 | ||
126 | void __iomem *p = chip->pch_phub_base_address; | |
127 | ||
128 | chip->phub_id_reg = ioread32(p + PCH_PHUB_ID_REG); | |
129 | chip->q_pri_val_reg = ioread32(p + PCH_PHUB_QUEUE_PRI_VAL_REG); | |
130 | chip->rc_q_maxsize_reg = ioread32(p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); | |
131 | chip->bri_q_maxsize_reg = ioread32(p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); | |
132 | chip->comp_resp_timeout_reg = | |
133 | ioread32(p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); | |
134 | chip->bus_slave_control_reg = | |
135 | ioread32(p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); | |
136 | chip->deadlock_avoid_type_reg = | |
137 | ioread32(p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); | |
138 | chip->intpin_reg_wpermit_reg0 = | |
139 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); | |
140 | chip->intpin_reg_wpermit_reg1 = | |
141 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); | |
142 | chip->intpin_reg_wpermit_reg2 = | |
143 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); | |
144 | chip->intpin_reg_wpermit_reg3 = | |
145 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); | |
146 | dev_dbg(&pdev->dev, "%s : " | |
147 | "chip->phub_id_reg=%x, " | |
148 | "chip->q_pri_val_reg=%x, " | |
149 | "chip->rc_q_maxsize_reg=%x, " | |
150 | "chip->bri_q_maxsize_reg=%x, " | |
151 | "chip->comp_resp_timeout_reg=%x, " | |
152 | "chip->bus_slave_control_reg=%x, " | |
153 | "chip->deadlock_avoid_type_reg=%x, " | |
154 | "chip->intpin_reg_wpermit_reg0=%x, " | |
155 | "chip->intpin_reg_wpermit_reg1=%x, " | |
156 | "chip->intpin_reg_wpermit_reg2=%x, " | |
157 | "chip->intpin_reg_wpermit_reg3=%x\n", __func__, | |
158 | chip->phub_id_reg, | |
159 | chip->q_pri_val_reg, | |
160 | chip->rc_q_maxsize_reg, | |
161 | chip->bri_q_maxsize_reg, | |
162 | chip->comp_resp_timeout_reg, | |
163 | chip->bus_slave_control_reg, | |
164 | chip->deadlock_avoid_type_reg, | |
165 | chip->intpin_reg_wpermit_reg0, | |
166 | chip->intpin_reg_wpermit_reg1, | |
167 | chip->intpin_reg_wpermit_reg2, | |
168 | chip->intpin_reg_wpermit_reg3); | |
169 | for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { | |
170 | chip->int_reduce_control_reg[i] = | |
171 | ioread32(p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); | |
172 | dev_dbg(&pdev->dev, "%s : " | |
173 | "chip->int_reduce_control_reg[%d]=%x\n", | |
174 | __func__, i, chip->int_reduce_control_reg[i]); | |
175 | } | |
176 | chip->clkcfg_reg = ioread32(p + CLKCFG_REG_OFFSET); | |
177 | } | |
178 | ||
179 | /* pch_phub_restore_reg_conf - restore register configuration */ | |
180 | static void pch_phub_restore_reg_conf(struct pci_dev *pdev) | |
181 | { | |
182 | unsigned int i; | |
183 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | |
184 | void __iomem *p; | |
185 | p = chip->pch_phub_base_address; | |
186 | ||
187 | iowrite32(chip->phub_id_reg, p + PCH_PHUB_ID_REG); | |
188 | iowrite32(chip->q_pri_val_reg, p + PCH_PHUB_QUEUE_PRI_VAL_REG); | |
189 | iowrite32(chip->rc_q_maxsize_reg, p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); | |
190 | iowrite32(chip->bri_q_maxsize_reg, p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); | |
191 | iowrite32(chip->comp_resp_timeout_reg, | |
192 | p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); | |
193 | iowrite32(chip->bus_slave_control_reg, | |
194 | p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); | |
195 | iowrite32(chip->deadlock_avoid_type_reg, | |
196 | p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); | |
197 | iowrite32(chip->intpin_reg_wpermit_reg0, | |
198 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); | |
199 | iowrite32(chip->intpin_reg_wpermit_reg1, | |
200 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); | |
201 | iowrite32(chip->intpin_reg_wpermit_reg2, | |
202 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); | |
203 | iowrite32(chip->intpin_reg_wpermit_reg3, | |
204 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); | |
205 | dev_dbg(&pdev->dev, "%s : " | |
206 | "chip->phub_id_reg=%x, " | |
207 | "chip->q_pri_val_reg=%x, " | |
208 | "chip->rc_q_maxsize_reg=%x, " | |
209 | "chip->bri_q_maxsize_reg=%x, " | |
210 | "chip->comp_resp_timeout_reg=%x, " | |
211 | "chip->bus_slave_control_reg=%x, " | |
212 | "chip->deadlock_avoid_type_reg=%x, " | |
213 | "chip->intpin_reg_wpermit_reg0=%x, " | |
214 | "chip->intpin_reg_wpermit_reg1=%x, " | |
215 | "chip->intpin_reg_wpermit_reg2=%x, " | |
216 | "chip->intpin_reg_wpermit_reg3=%x\n", __func__, | |
217 | chip->phub_id_reg, | |
218 | chip->q_pri_val_reg, | |
219 | chip->rc_q_maxsize_reg, | |
220 | chip->bri_q_maxsize_reg, | |
221 | chip->comp_resp_timeout_reg, | |
222 | chip->bus_slave_control_reg, | |
223 | chip->deadlock_avoid_type_reg, | |
224 | chip->intpin_reg_wpermit_reg0, | |
225 | chip->intpin_reg_wpermit_reg1, | |
226 | chip->intpin_reg_wpermit_reg2, | |
227 | chip->intpin_reg_wpermit_reg3); | |
228 | for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { | |
229 | iowrite32(chip->int_reduce_control_reg[i], | |
230 | p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); | |
231 | dev_dbg(&pdev->dev, "%s : " | |
232 | "chip->int_reduce_control_reg[%d]=%x\n", | |
233 | __func__, i, chip->int_reduce_control_reg[i]); | |
234 | } | |
235 | ||
236 | iowrite32(chip->clkcfg_reg, p + CLKCFG_REG_OFFSET); | |
237 | } | |
238 | ||
239 | /** | |
240 | * pch_phub_read_serial_rom() - Reading Serial ROM | |
241 | * @offset_address: Serial ROM offset address to read. | |
242 | * @data: Read buffer for specified Serial ROM value. | |
243 | */ | |
244 | static void pch_phub_read_serial_rom(struct pch_phub_reg *chip, | |
245 | unsigned int offset_address, u8 *data) | |
246 | { | |
247 | void __iomem *mem_addr = chip->pch_phub_extrom_base_address + | |
248 | offset_address; | |
249 | ||
250 | *data = ioread8(mem_addr); | |
251 | } | |
252 | ||
253 | /** | |
254 | * pch_phub_write_serial_rom() - Writing Serial ROM | |
255 | * @offset_address: Serial ROM offset address. | |
256 | * @data: Serial ROM value to write. | |
257 | */ | |
258 | static int pch_phub_write_serial_rom(struct pch_phub_reg *chip, | |
259 | unsigned int offset_address, u8 data) | |
260 | { | |
261 | void __iomem *mem_addr = chip->pch_phub_extrom_base_address + | |
262 | (offset_address & PCH_WORD_ADDR_MASK); | |
263 | int i; | |
264 | unsigned int word_data; | |
265 | unsigned int pos; | |
266 | unsigned int mask; | |
267 | pos = (offset_address % 4) * 8; | |
268 | mask = ~(0xFF << pos); | |
269 | ||
270 | iowrite32(PCH_PHUB_ROM_WRITE_ENABLE, | |
271 | chip->pch_phub_extrom_base_address + PHUB_CONTROL); | |
272 | ||
273 | word_data = ioread32(mem_addr); | |
274 | iowrite32((word_data & mask) | (u32)data << pos, mem_addr); | |
275 | ||
276 | i = 0; | |
277 | while (ioread8(chip->pch_phub_extrom_base_address + | |
278 | PHUB_STATUS) != 0x00) { | |
279 | msleep(1); | |
280 | if (i == PHUB_TIMEOUT) | |
281 | return -ETIMEDOUT; | |
282 | i++; | |
283 | } | |
284 | ||
285 | iowrite32(PCH_PHUB_ROM_WRITE_DISABLE, | |
286 | chip->pch_phub_extrom_base_address + PHUB_CONTROL); | |
287 | ||
288 | return 0; | |
289 | } | |
290 | ||
291 | /** | |
292 | * pch_phub_read_serial_rom_val() - Read Serial ROM value | |
293 | * @offset_address: Serial ROM address offset value. | |
294 | * @data: Serial ROM value to read. | |
295 | */ | |
296 | static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip, | |
297 | unsigned int offset_address, u8 *data) | |
298 | { | |
299 | unsigned int mem_addr; | |
300 | ||
301 | mem_addr = PCH_PHUB_ROM_START_ADDR + | |
302 | pch_phub_mac_offset[offset_address]; | |
303 | ||
304 | pch_phub_read_serial_rom(chip, mem_addr, data); | |
305 | } | |
306 | ||
307 | /** | |
308 | * pch_phub_write_serial_rom_val() - writing Serial ROM value | |
309 | * @offset_address: Serial ROM address offset value. | |
310 | * @data: Serial ROM value. | |
311 | */ | |
312 | static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip, | |
313 | unsigned int offset_address, u8 data) | |
314 | { | |
315 | int retval; | |
316 | unsigned int mem_addr; | |
317 | ||
318 | mem_addr = PCH_PHUB_ROM_START_ADDR + | |
319 | pch_phub_mac_offset[offset_address]; | |
320 | ||
321 | retval = pch_phub_write_serial_rom(chip, mem_addr, data); | |
322 | ||
323 | return retval; | |
324 | } | |
325 | ||
326 | /* pch_phub_gbe_serial_rom_conf - makes Serial ROM header format configuration | |
327 | * for Gigabit Ethernet MAC address | |
328 | */ | |
329 | static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip) | |
330 | { | |
331 | int retval; | |
332 | ||
333 | retval = pch_phub_write_serial_rom(chip, 0x0b, 0xbc); | |
334 | retval |= pch_phub_write_serial_rom(chip, 0x0a, 0x10); | |
335 | retval |= pch_phub_write_serial_rom(chip, 0x09, 0x01); | |
336 | retval |= pch_phub_write_serial_rom(chip, 0x08, 0x02); | |
337 | ||
338 | retval |= pch_phub_write_serial_rom(chip, 0x0f, 0x00); | |
339 | retval |= pch_phub_write_serial_rom(chip, 0x0e, 0x00); | |
340 | retval |= pch_phub_write_serial_rom(chip, 0x0d, 0x00); | |
341 | retval |= pch_phub_write_serial_rom(chip, 0x0c, 0x80); | |
342 | ||
343 | retval |= pch_phub_write_serial_rom(chip, 0x13, 0xbc); | |
344 | retval |= pch_phub_write_serial_rom(chip, 0x12, 0x10); | |
345 | retval |= pch_phub_write_serial_rom(chip, 0x11, 0x01); | |
346 | retval |= pch_phub_write_serial_rom(chip, 0x10, 0x18); | |
347 | ||
348 | retval |= pch_phub_write_serial_rom(chip, 0x1b, 0xbc); | |
349 | retval |= pch_phub_write_serial_rom(chip, 0x1a, 0x10); | |
350 | retval |= pch_phub_write_serial_rom(chip, 0x19, 0x01); | |
351 | retval |= pch_phub_write_serial_rom(chip, 0x18, 0x19); | |
352 | ||
353 | retval |= pch_phub_write_serial_rom(chip, 0x23, 0xbc); | |
354 | retval |= pch_phub_write_serial_rom(chip, 0x22, 0x10); | |
355 | retval |= pch_phub_write_serial_rom(chip, 0x21, 0x01); | |
356 | retval |= pch_phub_write_serial_rom(chip, 0x20, 0x3a); | |
357 | ||
358 | retval |= pch_phub_write_serial_rom(chip, 0x27, 0x01); | |
359 | retval |= pch_phub_write_serial_rom(chip, 0x26, 0x00); | |
360 | retval |= pch_phub_write_serial_rom(chip, 0x25, 0x00); | |
361 | retval |= pch_phub_write_serial_rom(chip, 0x24, 0x00); | |
362 | ||
363 | return retval; | |
364 | } | |
365 | ||
366 | /** | |
367 | * pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address | |
368 | * @offset_address: Gigabit Ethernet MAC address offset value. | |
369 | * @data: Buffer of the Gigabit Ethernet MAC address value. | |
370 | */ | |
371 | static void pch_phub_read_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) | |
372 | { | |
373 | int i; | |
374 | for (i = 0; i < ETH_ALEN; i++) | |
375 | pch_phub_read_serial_rom_val(chip, i, &data[i]); | |
376 | } | |
377 | ||
378 | /** | |
379 | * pch_phub_write_gbe_mac_addr() - Write MAC address | |
380 | * @offset_address: Gigabit Ethernet MAC address offset value. | |
381 | * @data: Gigabit Ethernet MAC address value. | |
382 | */ | |
383 | static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) | |
384 | { | |
385 | int retval; | |
386 | int i; | |
387 | ||
388 | retval = pch_phub_gbe_serial_rom_conf(chip); | |
389 | if (retval) | |
390 | return retval; | |
391 | ||
392 | for (i = 0; i < ETH_ALEN; i++) { | |
393 | retval = pch_phub_write_serial_rom_val(chip, i, data[i]); | |
394 | if (retval) | |
395 | return retval; | |
396 | } | |
397 | ||
398 | return retval; | |
399 | } | |
400 | ||
401 | static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, | |
402 | struct bin_attribute *attr, char *buf, | |
403 | loff_t off, size_t count) | |
404 | { | |
405 | unsigned int rom_signature; | |
406 | unsigned char rom_length; | |
407 | unsigned int tmp; | |
408 | unsigned int addr_offset; | |
409 | unsigned int orom_size; | |
410 | int ret; | |
411 | int err; | |
412 | ||
413 | struct pch_phub_reg *chip = | |
414 | dev_get_drvdata(container_of(kobj, struct device, kobj)); | |
415 | ||
416 | ret = mutex_lock_interruptible(&pch_phub_mutex); | |
417 | if (ret) { | |
418 | err = -ERESTARTSYS; | |
419 | goto return_err_nomutex; | |
420 | } | |
421 | ||
422 | /* Get Rom signature */ | |
423 | pch_phub_read_serial_rom(chip, 0x80, (unsigned char *)&rom_signature); | |
424 | rom_signature &= 0xff; | |
425 | pch_phub_read_serial_rom(chip, 0x81, (unsigned char *)&tmp); | |
426 | rom_signature |= (tmp & 0xff) << 8; | |
427 | if (rom_signature == 0xAA55) { | |
428 | pch_phub_read_serial_rom(chip, 0x82, &rom_length); | |
429 | orom_size = rom_length * 512; | |
430 | if (orom_size < off) { | |
431 | addr_offset = 0; | |
432 | goto return_ok; | |
433 | } | |
434 | if (orom_size < count) { | |
435 | addr_offset = 0; | |
436 | goto return_ok; | |
437 | } | |
438 | ||
439 | for (addr_offset = 0; addr_offset < count; addr_offset++) { | |
440 | pch_phub_read_serial_rom(chip, 0x80 + addr_offset + off, | |
441 | &buf[addr_offset]); | |
442 | } | |
443 | } else { | |
444 | err = -ENODATA; | |
445 | goto return_err; | |
446 | } | |
447 | return_ok: | |
448 | mutex_unlock(&pch_phub_mutex); | |
449 | return addr_offset; | |
450 | ||
451 | return_err: | |
452 | mutex_unlock(&pch_phub_mutex); | |
453 | return_err_nomutex: | |
454 | return err; | |
455 | } | |
456 | ||
457 | static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, | |
458 | struct bin_attribute *attr, | |
459 | char *buf, loff_t off, size_t count) | |
460 | { | |
461 | int err; | |
462 | unsigned int addr_offset; | |
463 | int ret; | |
464 | struct pch_phub_reg *chip = | |
465 | dev_get_drvdata(container_of(kobj, struct device, kobj)); | |
466 | ||
467 | ret = mutex_lock_interruptible(&pch_phub_mutex); | |
468 | if (ret) | |
469 | return -ERESTARTSYS; | |
470 | ||
471 | if (off > PCH_PHUB_OROM_SIZE) { | |
472 | addr_offset = 0; | |
473 | goto return_ok; | |
474 | } | |
475 | if (count > PCH_PHUB_OROM_SIZE) { | |
476 | addr_offset = 0; | |
477 | goto return_ok; | |
478 | } | |
479 | ||
480 | for (addr_offset = 0; addr_offset < count; addr_offset++) { | |
481 | if (PCH_PHUB_OROM_SIZE < off + addr_offset) | |
482 | goto return_ok; | |
483 | ||
484 | ret = pch_phub_write_serial_rom(chip, 0x80 + addr_offset + off, | |
485 | buf[addr_offset]); | |
486 | if (ret) { | |
487 | err = ret; | |
488 | goto return_err; | |
489 | } | |
490 | } | |
491 | ||
492 | return_ok: | |
493 | mutex_unlock(&pch_phub_mutex); | |
494 | return addr_offset; | |
495 | ||
496 | return_err: | |
497 | mutex_unlock(&pch_phub_mutex); | |
498 | return err; | |
499 | } | |
500 | ||
501 | static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr, | |
502 | char *buf) | |
503 | { | |
504 | u8 mac[8]; | |
505 | struct pch_phub_reg *chip = dev_get_drvdata(dev); | |
506 | ||
507 | pch_phub_read_gbe_mac_addr(chip, mac); | |
508 | ||
509 | return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", | |
510 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | |
511 | } | |
512 | ||
513 | static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, | |
514 | const char *buf, size_t count) | |
515 | { | |
516 | u8 mac[6]; | |
517 | struct pch_phub_reg *chip = dev_get_drvdata(dev); | |
518 | ||
519 | if (count != 18) | |
520 | return -EINVAL; | |
521 | ||
522 | sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", | |
523 | (u32 *)&mac[0], (u32 *)&mac[1], (u32 *)&mac[2], (u32 *)&mac[3], | |
524 | (u32 *)&mac[4], (u32 *)&mac[5]); | |
525 | ||
526 | pch_phub_write_gbe_mac_addr(chip, mac); | |
527 | ||
528 | return count; | |
529 | } | |
530 | ||
531 | static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); | |
532 | ||
533 | static struct bin_attribute pch_bin_attr = { | |
534 | .attr = { | |
535 | .name = "pch_firmware", | |
536 | .mode = S_IRUGO | S_IWUSR, | |
537 | }, | |
538 | .size = PCH_PHUB_OROM_SIZE + 1, | |
539 | .read = pch_phub_bin_read, | |
540 | .write = pch_phub_bin_write, | |
541 | }; | |
542 | ||
543 | static int __devinit pch_phub_probe(struct pci_dev *pdev, | |
544 | const struct pci_device_id *id) | |
545 | { | |
546 | int retval; | |
547 | ||
548 | int ret; | |
da0d7f98 | 549 | ssize_t rom_size; |
cf4ece53 MO |
550 | struct pch_phub_reg *chip; |
551 | ||
552 | chip = kzalloc(sizeof(struct pch_phub_reg), GFP_KERNEL); | |
553 | if (chip == NULL) | |
554 | return -ENOMEM; | |
555 | ||
556 | ret = pci_enable_device(pdev); | |
557 | if (ret) { | |
558 | dev_err(&pdev->dev, | |
559 | "%s : pci_enable_device FAILED(ret=%d)", __func__, ret); | |
560 | goto err_pci_enable_dev; | |
561 | } | |
562 | dev_dbg(&pdev->dev, "%s : pci_enable_device returns %d\n", __func__, | |
563 | ret); | |
564 | ||
565 | ret = pci_request_regions(pdev, KBUILD_MODNAME); | |
566 | if (ret) { | |
567 | dev_err(&pdev->dev, | |
568 | "%s : pci_request_regions FAILED(ret=%d)", __func__, ret); | |
569 | goto err_req_regions; | |
570 | } | |
571 | dev_dbg(&pdev->dev, "%s : " | |
572 | "pci_request_regions returns %d\n", __func__, ret); | |
573 | ||
574 | chip->pch_phub_base_address = pci_iomap(pdev, 1, 0); | |
575 | ||
576 | ||
577 | if (chip->pch_phub_base_address == 0) { | |
578 | dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); | |
579 | ret = -ENOMEM; | |
580 | goto err_pci_iomap; | |
581 | } | |
582 | dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value " | |
da0d7f98 GKH |
583 | "in pch_phub_base_address variable is %p\n", __func__, |
584 | chip->pch_phub_base_address); | |
cf4ece53 MO |
585 | chip->pch_phub_extrom_base_address = pci_map_rom(pdev, &rom_size); |
586 | ||
587 | if (chip->pch_phub_extrom_base_address == 0) { | |
588 | dev_err(&pdev->dev, "%s : pci_map_rom FAILED", __func__); | |
589 | ret = -ENOMEM; | |
590 | goto err_pci_map; | |
591 | } | |
592 | dev_dbg(&pdev->dev, "%s : " | |
593 | "pci_map_rom SUCCESS and value in " | |
da0d7f98 GKH |
594 | "pch_phub_extrom_base_address variable is %p\n", __func__, |
595 | chip->pch_phub_extrom_base_address); | |
cf4ece53 MO |
596 | |
597 | pci_set_drvdata(pdev, chip); | |
598 | ||
599 | retval = sysfs_create_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); | |
600 | if (retval) | |
601 | goto err_sysfs_create; | |
602 | ||
603 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); | |
604 | if (retval) | |
605 | goto exit_bin_attr; | |
606 | ||
607 | pch_phub_read_modify_write_reg(chip, (unsigned int)CLKCFG_REG_OFFSET, | |
608 | CLKCFG_CAN_50MHZ, CLKCFG_CANCLK_MASK); | |
609 | ||
610 | /* set the prefech value */ | |
611 | iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); | |
612 | /* set the interrupt delay value */ | |
613 | iowrite32(0x25, chip->pch_phub_base_address + 0x44); | |
614 | ||
615 | return 0; | |
616 | exit_bin_attr: | |
617 | sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); | |
618 | ||
619 | err_sysfs_create: | |
620 | pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); | |
621 | err_pci_map: | |
622 | pci_iounmap(pdev, chip->pch_phub_base_address); | |
623 | err_pci_iomap: | |
624 | pci_release_regions(pdev); | |
625 | err_req_regions: | |
626 | pci_disable_device(pdev); | |
627 | err_pci_enable_dev: | |
628 | kfree(chip); | |
629 | dev_err(&pdev->dev, "%s returns %d\n", __func__, ret); | |
630 | return ret; | |
631 | } | |
632 | ||
633 | static void __devexit pch_phub_remove(struct pci_dev *pdev) | |
634 | { | |
635 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | |
636 | ||
637 | sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); | |
638 | sysfs_remove_bin_file(&pdev->dev.kobj, &pch_bin_attr); | |
639 | pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); | |
640 | pci_iounmap(pdev, chip->pch_phub_base_address); | |
641 | pci_release_regions(pdev); | |
642 | pci_disable_device(pdev); | |
643 | kfree(chip); | |
644 | } | |
645 | ||
646 | #ifdef CONFIG_PM | |
647 | ||
648 | static int pch_phub_suspend(struct pci_dev *pdev, pm_message_t state) | |
649 | { | |
650 | int ret; | |
651 | ||
652 | pch_phub_save_reg_conf(pdev); | |
653 | ret = pci_save_state(pdev); | |
654 | if (ret) { | |
655 | dev_err(&pdev->dev, | |
656 | " %s -pci_save_state returns %d\n", __func__, ret); | |
657 | return ret; | |
658 | } | |
659 | pci_enable_wake(pdev, PCI_D3hot, 0); | |
660 | pci_disable_device(pdev); | |
661 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | |
662 | ||
663 | return 0; | |
664 | } | |
665 | ||
666 | static int pch_phub_resume(struct pci_dev *pdev) | |
667 | { | |
668 | int ret; | |
669 | ||
670 | pci_set_power_state(pdev, PCI_D0); | |
671 | pci_restore_state(pdev); | |
672 | ret = pci_enable_device(pdev); | |
673 | if (ret) { | |
674 | dev_err(&pdev->dev, | |
675 | "%s-pci_enable_device failed(ret=%d) ", __func__, ret); | |
676 | return ret; | |
677 | } | |
678 | ||
679 | pci_enable_wake(pdev, PCI_D3hot, 0); | |
680 | pch_phub_restore_reg_conf(pdev); | |
681 | ||
682 | return 0; | |
683 | } | |
684 | #else | |
685 | #define pch_phub_suspend NULL | |
686 | #define pch_phub_resume NULL | |
687 | #endif /* CONFIG_PM */ | |
688 | ||
689 | static struct pci_device_id pch_phub_pcidev_id[] = { | |
690 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH1_PHUB)}, | |
691 | {0,} | |
692 | }; | |
693 | ||
694 | static struct pci_driver pch_phub_driver = { | |
695 | .name = "pch_phub", | |
696 | .id_table = pch_phub_pcidev_id, | |
697 | .probe = pch_phub_probe, | |
698 | .remove = __devexit_p(pch_phub_remove), | |
699 | .suspend = pch_phub_suspend, | |
700 | .resume = pch_phub_resume | |
701 | }; | |
702 | ||
703 | static int __init pch_phub_pci_init(void) | |
704 | { | |
705 | return pci_register_driver(&pch_phub_driver); | |
706 | } | |
707 | ||
708 | static void __exit pch_phub_pci_exit(void) | |
709 | { | |
710 | pci_unregister_driver(&pch_phub_driver); | |
711 | } | |
712 | ||
713 | module_init(pch_phub_pci_init); | |
714 | module_exit(pch_phub_pci_exit); | |
715 | ||
716 | MODULE_DESCRIPTION("PCH Packet Hub PCI Driver"); | |
717 | MODULE_LICENSE("GPL"); |