PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/sys/dev/imcsmb/imcsmb.c

https://bitbucket.org/freebsd/freebsd-base
C | 556 lines | 233 code | 63 blank | 260 comment | 38 complexity | c4e5d14b12821538eaaf1bec819cd9b3 MD5 | raw file
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  3. *
  4. * Authors: Joe Kloss; Ravi Pokala (rpokala@freebsd.org)
  5. *
  6. * Copyright (c) 2017-2018 Panasas
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. *
  29. * $FreeBSD$
  30. */
  31. /* A detailed description of this device is present in imcsmb_pci.c */
  32. #include <sys/param.h>
  33. #include <sys/systm.h>
  34. #include <sys/kernel.h>
  35. #include <sys/module.h>
  36. #include <sys/endian.h>
  37. #include <sys/errno.h>
  38. #include <sys/lock.h>
  39. #include <sys/mutex.h>
  40. #include <sys/syslog.h>
  41. #include <sys/bus.h>
  42. #include <machine/bus.h>
  43. #include <machine/atomic.h>
  44. #include <dev/pci/pcivar.h>
  45. #include <dev/pci/pcireg.h>
  46. #include <dev/smbus/smbconf.h>
  47. #include "imcsmb_reg.h"
  48. #include "imcsmb_var.h"
  49. /* Device methods */
  50. static int imcsmb_attach(device_t dev);
  51. static int imcsmb_detach(device_t dev);
  52. static int imcsmb_probe(device_t dev);
  53. /* SMBus methods */
  54. static int imcsmb_callback(device_t dev, int index, void *data);
  55. static int imcsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
  56. static int imcsmb_readw(device_t dev, u_char slave, char cmd, short *word);
  57. static int imcsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
  58. static int imcsmb_writew(device_t dev, u_char slave, char cmd, short word);
  59. /* All the read/write methods wrap around this. */
  60. static int imcsmb_transfer(device_t dev, u_char slave, char cmd, void *data,
  61. int word_op, int write_op);
  62. /**
  63. * device_attach() method. Set up the softc, including getting the set of the
  64. * parent imcsmb_pci's registers that we will use. Create the smbus(4) device,
  65. * which any SMBus slave device drivers will connect to.
  66. *
  67. * @author rpokala
  68. *
  69. * @param[in,out] dev
  70. * Device being attached.
  71. */
  72. static int
  73. imcsmb_attach(device_t dev)
  74. {
  75. struct imcsmb_softc *sc;
  76. int rc;
  77. /* Initialize private state */
  78. sc = device_get_softc(dev);
  79. sc->dev = dev;
  80. sc->imcsmb_pci = device_get_parent(dev);
  81. sc->regs = device_get_ivars(dev);
  82. /* Create the smbus child */
  83. sc->smbus = device_add_child(dev, "smbus", -1);
  84. if (sc->smbus == NULL) {
  85. /* Nothing has been allocated, so there's no cleanup. */
  86. device_printf(dev, "Child smbus not added\n");
  87. rc = ENXIO;
  88. goto out;
  89. }
  90. /* Attach the smbus child. */
  91. if ((rc = bus_generic_attach(dev)) != 0) {
  92. device_printf(dev, "Failed to attach smbus: %d\n", rc);
  93. }
  94. out:
  95. return (rc);
  96. }
  97. /**
  98. * device_detach() method. attach() didn't do any allocations, so all that's
  99. * needed here is to free up any downstream drivers and children.
  100. *
  101. * @author Joe Kloss
  102. *
  103. * @param[in] dev
  104. * Device being detached.
  105. */
  106. static int
  107. imcsmb_detach(device_t dev)
  108. {
  109. int rc;
  110. /* Detach any attached drivers */
  111. rc = bus_generic_detach(dev);
  112. if (rc == 0) {
  113. /* Remove all children */
  114. rc = device_delete_children(dev);
  115. }
  116. return (rc);
  117. }
  118. /**
  119. * device_probe() method. All the actual probing was done by the imcsmb_pci
  120. * parent, so just report success.
  121. *
  122. * @author Joe Kloss
  123. *
  124. * @param[in,out] dev
  125. * Device being probed.
  126. */
  127. static int
  128. imcsmb_probe(device_t dev)
  129. {
  130. device_set_desc(dev, "iMC SMBus controller");
  131. return (BUS_PROBE_DEFAULT);
  132. }
  133. /**
  134. * smbus_callback() method. Call the parent imcsmb_pci's request or release
  135. * function to quiesce / restart firmware tasks which might use the SMBus.
  136. *
  137. * @author rpokala
  138. *
  139. * @param[in] dev
  140. * Device being requested or released.
  141. *
  142. * @param[in] index
  143. * Either SMB_REQUEST_BUS or SMB_RELEASE_BUS.
  144. *
  145. * @param[in] data
  146. * Tell's the rest of the SMBus subsystem to allow or disallow waiting;
  147. * this driver only works with SMB_DONTWAIT.
  148. */
  149. static int
  150. imcsmb_callback(device_t dev, int index, void *data)
  151. {
  152. struct imcsmb_softc *sc;
  153. int *how;
  154. int rc;
  155. sc = device_get_softc(dev);
  156. how = (int *) data;
  157. switch (index) {
  158. case SMB_REQUEST_BUS: {
  159. if (*how != SMB_DONTWAIT) {
  160. rc = EINVAL;
  161. goto out;
  162. }
  163. rc = imcsmb_pci_request_bus(sc->imcsmb_pci);
  164. break;
  165. }
  166. case SMB_RELEASE_BUS:
  167. imcsmb_pci_release_bus(sc->imcsmb_pci);
  168. rc = 0;
  169. break;
  170. default:
  171. rc = EINVAL;
  172. break;
  173. }
  174. out:
  175. return (rc);
  176. }
  177. /**
  178. * smbus_readb() method. Thin wrapper around imcsmb_transfer().
  179. *
  180. * @author Joe Kloss
  181. *
  182. * @param[in] dev
  183. *
  184. * @param[in] slave
  185. * The SMBus address of the target device.
  186. *
  187. * @param[in] cmd
  188. * The SMBus command for the target device; this is the offset for SPDs,
  189. * or the register number for TSODs.
  190. *
  191. * @param[out] byte
  192. * The byte which was read.
  193. */
  194. static int
  195. imcsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  196. {
  197. return (imcsmb_transfer(dev, slave, cmd, byte, FALSE, FALSE));
  198. }
  199. /**
  200. * smbus_readw() method. Thin wrapper around imcsmb_transfer().
  201. *
  202. * @author Joe Kloss
  203. *
  204. * @param[in] dev
  205. *
  206. * @param[in] slave
  207. * The SMBus address of the target device.
  208. *
  209. * @param[in] cmd
  210. * The SMBus command for the target device; this is the offset for SPDs,
  211. * or the register number for TSODs.
  212. *
  213. * @param[out] word
  214. * The word which was read.
  215. */
  216. static int
  217. imcsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  218. {
  219. return (imcsmb_transfer(dev, slave, cmd, word, TRUE, FALSE));
  220. }
  221. /**
  222. * smbus_writeb() method. Thin wrapper around imcsmb_transfer().
  223. *
  224. * @author Joe Kloss
  225. *
  226. * @param[in] dev
  227. *
  228. * @param[in] slave
  229. * The SMBus address of the target device.
  230. *
  231. * @param[in] cmd
  232. * The SMBus command for the target device; this is the offset for SPDs,
  233. * or the register number for TSODs.
  234. *
  235. * @param[in] byte
  236. * The byte to write.
  237. */
  238. static int
  239. imcsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  240. {
  241. return (imcsmb_transfer(dev, slave, cmd, &byte, FALSE, TRUE));
  242. }
  243. /**
  244. * smbus_writew() method. Thin wrapper around imcsmb_transfer().
  245. *
  246. * @author Joe Kloss
  247. *
  248. * @param[in] dev
  249. *
  250. * @param[in] slave
  251. * The SMBus address of the target device.
  252. *
  253. * @param[in] cmd
  254. * The SMBus command for the target device; this is the offset for SPDs,
  255. * or the register number for TSODs.
  256. *
  257. * @param[in] word
  258. * The word to write.
  259. */
  260. static int
  261. imcsmb_writew(device_t dev, u_char slave, char cmd, short word)
  262. {
  263. return (imcsmb_transfer(dev, slave, cmd, &word, TRUE, TRUE));
  264. }
  265. /**
  266. * Manipulate the PCI control registers to read data from or write data to the
  267. * SMBus controller.
  268. *
  269. * @author Joe Kloss, rpokala
  270. *
  271. * @param[in] dev
  272. *
  273. * @param[in] slave
  274. * The SMBus address of the target device.
  275. *
  276. * @param[in] cmd
  277. * The SMBus command for the target device; this is the offset for SPDs,
  278. * or the register number for TSODs.
  279. *
  280. * @param[in,out] data
  281. * Pointer to either the value to be written, or where to place the value
  282. * which was read.
  283. *
  284. * @param[in] word_op
  285. * Bool: is this a word operation?
  286. *
  287. * @param[in] write_op
  288. * Bool: is this a write operation?
  289. */
  290. static int
  291. imcsmb_transfer(device_t dev, u_char slave, char cmd, void *data, int word_op,
  292. int write_op)
  293. {
  294. struct imcsmb_softc *sc;
  295. int i;
  296. int rc;
  297. uint32_t cmd_val;
  298. uint32_t cntl_val;
  299. uint32_t orig_cntl_val;
  300. uint32_t stat_val;
  301. uint16_t *word;
  302. uint16_t lword;
  303. uint8_t *byte;
  304. uint8_t lbyte;
  305. sc = device_get_softc(dev);
  306. byte = data;
  307. word = data;
  308. lbyte = *byte;
  309. lword = *word;
  310. /* We modify the value of the control register; save the original, so
  311. * we can restore it later
  312. */
  313. orig_cntl_val = pci_read_config(sc->imcsmb_pci,
  314. sc->regs->smb_cntl, 4);
  315. cntl_val = orig_cntl_val;
  316. /*
  317. * Set up the SMBCNTL register
  318. */
  319. /* [31:28] Clear the existing value of the DTI bits, then set them to
  320. * the four high bits of the slave address.
  321. */
  322. cntl_val &= ~IMCSMB_CNTL_DTI_MASK;
  323. cntl_val |= ((uint32_t) slave & 0xf0) << 24;
  324. /* [27:27] Set the CLK_OVERRIDE bit, to enable normal operation */
  325. cntl_val |= IMCSMB_CNTL_CLK_OVERRIDE;
  326. /* [26:26] Clear the WRITE_DISABLE bit; the datasheet says this isn't
  327. * necessary, but empirically, it is.
  328. */
  329. cntl_val &= ~IMCSMB_CNTL_WRITE_DISABLE_BIT;
  330. /* [9:9] Clear the POLL_EN bit, to stop the hardware TSOD polling. */
  331. cntl_val &= ~IMCSMB_CNTL_POLL_EN;
  332. /*
  333. * Set up the SMBCMD register
  334. */
  335. /* [31:31] Set the TRIGGER bit; when this gets written, the controller
  336. * will issue the command.
  337. */
  338. cmd_val = IMCSMB_CMD_TRIGGER_BIT;
  339. /* [29:29] For word operations, set the WORD_ACCESS bit. */
  340. if (word_op) {
  341. cmd_val |= IMCSMB_CMD_WORD_ACCESS;
  342. }
  343. /* [27:27] For write operations, set the WRITE bit. */
  344. if (write_op) {
  345. cmd_val |= IMCSMB_CMD_WRITE_BIT;
  346. }
  347. /* [26:24] The three non-DTI, non-R/W bits of the slave address. */
  348. cmd_val |= (uint32_t) ((slave & 0xe) << 23);
  349. /* [23:16] The command (offset in the case of an EEPROM, or register in
  350. * the case of TSOD or NVDIMM controller).
  351. */
  352. cmd_val |= (uint32_t) ((uint8_t) cmd << 16);
  353. /* [15:0] The data to be written for a write operation. */
  354. if (write_op) {
  355. if (word_op) {
  356. /* The datasheet says the controller uses different
  357. * endianness for word operations on I2C vs SMBus!
  358. * I2C: [15:8] = MSB; [7:0] = LSB
  359. * SMB: [15:8] = LSB; [7:0] = MSB
  360. * As a practical matter, this controller is very
  361. * specifically for use with DIMMs, the SPD (and
  362. * NVDIMM controllers) are only accessed as bytes,
  363. * the temperature sensor is only accessed as words, and
  364. * the temperature sensors are I2C. Thus, byte-swap the
  365. * word.
  366. */
  367. lword = htobe16(lword);
  368. } else {
  369. /* For byte operations, the data goes in the LSB, and
  370. * the MSB is a don't care.
  371. */
  372. lword = (uint16_t) (lbyte & 0xff);
  373. }
  374. cmd_val |= lword;
  375. }
  376. /* Write the updated value to the control register first, to disable
  377. * the hardware TSOD polling.
  378. */
  379. pci_write_config(sc->imcsmb_pci, sc->regs->smb_cntl, cntl_val, 4);
  380. /* Poll on the BUSY bit in the status register until clear, or timeout.
  381. * We just cleared the auto-poll bit, so we need to make sure the device
  382. * is idle before issuing a command. We can safely timeout after 35 ms,
  383. * as this is the maximum time the SMBus spec allows for a transaction.
  384. */
  385. for (i = 4; i != 0; i--) {
  386. stat_val = pci_read_config(sc->imcsmb_pci, sc->regs->smb_stat,
  387. 4);
  388. if ((stat_val & IMCSMB_STATUS_BUSY_BIT) == 0) {
  389. break;
  390. }
  391. pause("imcsmb", 10 * hz / 1000);
  392. }
  393. if (i == 0) {
  394. device_printf(sc->dev,
  395. "transfer: timeout waiting for device to settle\n");
  396. }
  397. /* Now that polling has stopped, we can write the command register. This
  398. * starts the SMBus command.
  399. */
  400. pci_write_config(sc->imcsmb_pci, sc->regs->smb_cmd, cmd_val, 4);
  401. /* Wait for WRITE_DATA_DONE/READ_DATA_VALID to be set, or timeout and
  402. * fail. We wait up to 35ms.
  403. */
  404. for (i = 35000; i != 0; i -= 10)
  405. {
  406. DELAY(10);
  407. stat_val = pci_read_config(sc->imcsmb_pci, sc->regs->smb_stat,
  408. 4);
  409. /* For a write, the bits holding the data contain the data being
  410. * written. You'd think that would cause the READ_DATA_VALID bit
  411. * to be cleared, because the data bits no longer contain valid
  412. * data from the most recent read operation. While that would be
  413. * logical, that's not the case here: READ_DATA_VALID is only
  414. * cleared when starting a read operation, and WRITE_DATA_DONE
  415. * is only cleared when starting a write operation.
  416. */
  417. if (write_op) {
  418. if ((stat_val & IMCSMB_STATUS_WRITE_DATA_DONE) != 0) {
  419. break;
  420. }
  421. } else {
  422. if ((stat_val & IMCSMB_STATUS_READ_DATA_VALID) != 0) {
  423. break;
  424. }
  425. }
  426. }
  427. if (i == 0) {
  428. rc = SMB_ETIMEOUT;
  429. device_printf(dev, "transfer timeout\n");
  430. goto out;
  431. }
  432. /* It is generally the case that this bit indicates non-ACK, but it
  433. * could also indicate other bus errors. There's no way to tell the
  434. * difference.
  435. */
  436. if ((stat_val & IMCSMB_STATUS_BUS_ERROR_BIT) != 0) {
  437. /* While it is not documented, empirically, SPD page-change
  438. * commands (writes with DTI = 0x60) always complete with the
  439. * error bit set. So, ignore it in those cases.
  440. */
  441. if ((slave & 0xf0) != 0x60) {
  442. rc = SMB_ENOACK;
  443. goto out;
  444. }
  445. }
  446. /* For a read operation, copy the data out */
  447. if (write_op == 0) {
  448. if (word_op) {
  449. /* The data is returned in bits [15:0]; as discussed
  450. * above, byte-swap.
  451. */
  452. lword = (uint16_t) (stat_val & 0xffff);
  453. lword = htobe16(lword);
  454. *word = lword;
  455. } else {
  456. /* The data is returned in bits [7:0] */
  457. lbyte = (uint8_t) (stat_val & 0xff);
  458. *byte = lbyte;
  459. }
  460. }
  461. /* A lack of an error is, de facto, success. */
  462. rc = SMB_ENOERR;
  463. out:
  464. /* Restore the original value of the control register. */
  465. pci_write_config(sc->imcsmb_pci, sc->regs->smb_cntl, orig_cntl_val, 4);
  466. return (rc);
  467. }
  468. /* Our device class */
  469. static devclass_t imcsmb_devclass;
  470. /* Device methods */
  471. static device_method_t imcsmb_methods[] = {
  472. /* Device interface */
  473. DEVMETHOD(device_attach, imcsmb_attach),
  474. DEVMETHOD(device_detach, imcsmb_detach),
  475. DEVMETHOD(device_probe, imcsmb_probe),
  476. /* smbus methods */
  477. DEVMETHOD(smbus_callback, imcsmb_callback),
  478. DEVMETHOD(smbus_readb, imcsmb_readb),
  479. DEVMETHOD(smbus_readw, imcsmb_readw),
  480. DEVMETHOD(smbus_writeb, imcsmb_writeb),
  481. DEVMETHOD(smbus_writew, imcsmb_writew),
  482. DEVMETHOD_END
  483. };
  484. static driver_t imcsmb_driver = {
  485. .name = "imcsmb",
  486. .methods = imcsmb_methods,
  487. .size = sizeof(struct imcsmb_softc),
  488. };
  489. DRIVER_MODULE(imcsmb, imcsmb_pci, imcsmb_driver, imcsmb_devclass, 0, 0);
  490. MODULE_DEPEND(imcsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  491. MODULE_VERSION(imcsmb, 1);
  492. DRIVER_MODULE(smbus, imcsmb, smbus_driver, smbus_devclass, 0, 0);
  493. /* vi: set ts=8 sw=4 sts=8 noet: */